From a011bde42441e0ec0ca6fd10d39d5927dd49d886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joni=20R=C3=A4s=C3=A4nen?= Date: Tue, 23 Nov 2021 14:50:18 +0200 Subject: [PATCH] Update latency benchmarks to use command line parameters --- benchmark.pl | 35 +++++++------ util/util.cc | 23 +++++++++ util/util.hh | 6 ++- uvgrtp/latency_receiver.cc | 29 ++++++++--- uvgrtp/latency_sender.cc | 101 +++++++++++++++++++++---------------- uvgrtp/receiver.cc | 22 +++----- uvgrtp/sender.cc | 37 ++++---------- 7 files changed, 140 insertions(+), 113 deletions(-) diff --git a/benchmark.pl b/benchmark.pl index 325c3fc..83a859a 100755 --- a/benchmark.pl +++ b/benchmark.pl @@ -200,29 +200,29 @@ sub recv_generic { print "End netcat receiver\n"; } -sub lat_send { +sub send_latency { print "Latency send benchmark\n"; - my ($lib, $file, $addr, $port) = @_; + my ($lib, $file, $saddr, $raddr, $port, $fps, $iter, $format, $srtp) = @_; my ($socket, $remote, $data); - $socket = mk_ssock($addr, $port); + $socket = mk_ssock($saddr, $port); $remote = $socket->accept(); - for ((1 .. 100)) { + for ((1 .. $iter)) { $remote->recv($data, 16); - system ("./$lib/latency_sender >> $lib/results/latencies 2>&1"); + system ("./$lib/latency_sender $file $saddr $port $raddr $port $fps $format $srtp>> $lib/results/latencies 2>&1"); } print "Latency send benchmark finished\n"; } -sub lat_recv { +sub recv_latency { print "Latency receive benchmark\n"; - my ($lib, $addr, $port) = @_; - my $socket = mk_rsock($addr, $port); + my ($lib, $saddr, $raddr, $port, $iter, $format, $srtp) = @_; + my $socket = mk_rsock($saddr, $port); - for ((1 .. 100)) { + for ((1 .. $iter)) { $socket->send("start"); - system ("./$lib/latency_receiver 2>&1 >/dev/null"); + system ("./$lib/latency_receiver $raddr $port $saddr $port $format $srtp 2>&1 >/dev/null"); sleep 2; } print "Latency receive benchmark finished\n"; @@ -236,7 +236,7 @@ sub print_help { . "\t--file \n" . "\t--saddr \n" . "\t--raddr \n" - . "\t--port \n" + . "\t--port \n" . "\t--threads <# of threads>\n" . "\t--start \n" . "\t--end \n\n"; @@ -244,8 +244,10 @@ sub print_help { print "usage (latency):\n ./benchmark.pl \n" . "\t--latency\n" . "\t--role \n" - . "\t--addr \n" - . "\t--port \n" + . "\t--saddr \n" + . "\t--raddr \n" + . "\t--port \n" + . "\t--fps \n" . "\t--lib \n\n" and exit; } @@ -262,7 +264,7 @@ GetOptions( "end|e=f" => \(my $end = 0), "step=i" => \(my $step = 0), "use-nc|use-netcat" => \(my $nc = 0), - "framerates|fps=s" => \(my $fps = ""), + "framerate|framerates|fps=s" => \(my $fps = ""), "latency|lat" => \(my $lat = 0), "srtp" => \(my $srtp = 0), "exec=s" => \(my $exec = "default"), @@ -282,6 +284,7 @@ die "Please specify role with --role" if !$role; die "library not supported\n" if !grep (/$lib/, ("uvgrtp", "ffmpeg", "live555")); die "format not supported\n" if !grep (/$format/, ("hevc", "vvc", "h265", "h266")); +$fps = 30.0 if $lat and !$fps; my @fps_vals = (); @@ -315,7 +318,7 @@ if ($role eq "send" or $role eq "sender") { if ($lat) { system "make $lib" . "_latency_sender"; - lat_send($lib, $file, $raddr, $port); + send_latency($lib, $file, $saddr, $raddr, $port, $fps, $iter, $format, $srtp); } else { if ($exec eq "default") { system "make $lib" . "_sender"; @@ -328,7 +331,7 @@ if ($role eq "send" or $role eq "sender") { if ($lat) { system "make $lib" . "_latency_receiver"; - lat_recv($lib, $saddr, $port); + recv_latency($lib, $saddr, $raddr, $port, $iter, $format, $srtp); } elsif (!$nc) { if ($exec eq "default") { system "make $lib" . "_receiver"; diff --git a/util/util.cc b/util/util.cc index e5729c0..f2bdf5d 100644 --- a/util/util.cc +++ b/util/util.cc @@ -129,4 +129,27 @@ void write_send_results_to_file(const std::string& filename, result_file << bytes << " bytes, " << bytes / 1000 << " kB, " << bytes / 1000000 << " MB took " << diff << " ms " << diff / 1000 << " s" << std::endl; result_file.close(); +} + +bool get_srtp_state(std::string srtp) +{ + if (srtp == "1" || srtp == "yes" || srtp == "y" || srtp == "srtp") + { + return true; + } + + return false; +} + +bool get_vvc_state(std::string format) +{ + if (format == "vvc" || format == "h266") + { + return true; + } + else if (format != "hevc" && format != "h265") + { + std::cerr << "Unsupported sender format: " << format << std::endl; + } + return false; } \ No newline at end of file diff --git a/util/util.hh b/util/util.hh index cce7a10..521b56b 100644 --- a/util/util.hh +++ b/util/util.hh @@ -12,4 +12,8 @@ void* get_mem(std::string filename, size_t& len); int get_next_frame_start(uint8_t* data, uint32_t offset, uint32_t data_len, uint8_t& start_len); void write_send_results_to_file(const std::string& filename, - const size_t bytes, const uint64_t diff); \ No newline at end of file + const size_t bytes, const uint64_t diff); + +bool get_srtp_state(std::string srtp); + +bool get_vvc_state(std::string format); \ No newline at end of file diff --git a/uvgrtp/latency_receiver.cc b/uvgrtp/latency_receiver.cc index 67c02a4..9155116 100644 --- a/uvgrtp/latency_receiver.cc +++ b/uvgrtp/latency_receiver.cc @@ -1,4 +1,5 @@ #include "uvgrtp_util.h" +#include "../util/util.hh" #include #include @@ -17,22 +18,23 @@ void hook_receiver(void *arg, uvg_rtp::frame::rtp_frame *frame) nframes++; } -int receiver(void) +int receiver(std::string local_address, int local_port, std::string remote_address, int remote_port, + bool vvc_enabled, bool srtp_enabled) { - std::string addr("127.0.0.1"); - uvgrtp::context rtp_ctx; uvgrtp::session* session = nullptr; uvgrtp::media_stream* receive = nullptr; - uint16_t send_port = SENDER_PORT; - uint16_t receive_port = RECEIVER_PORT; - intialize_uvgrtp(rtp_ctx, &session, &receive, addr_, addr_, receive_port, send_port, false); + intialize_uvgrtp(rtp_ctx, &session, &receive, remote_address, local_address, + local_port, remote_port, vvc_enabled, srtp_enabled); receive->install_receive_hook(receive, hook_receiver); + // the reaceiving end is not measured in latency tests while (nframes < EXPECTED_FRAMES) + { std::this_thread::sleep_for(std::chrono::milliseconds(3)); + } cleanup_uvgrtp(rtp_ctx, session, receive); @@ -41,7 +43,18 @@ int receiver(void) int main(int argc, char **argv) { - (void)argc, (void)argv; + if (argc != 7) { + fprintf(stderr, "usage: ./%s \ + \n", __FILE__); + return EXIT_FAILURE; + } - return receiver(); + std::string local_address = argv[1]; + int local_port = atoi(argv[2]); + std::string remote_address = argv[3]; + int remote_port = atoi(argv[4]); + bool vvc_enabled = get_vvc_state(argv[5]); + bool srtp_enabled = get_srtp_state(argv[6]); + + return receiver(local_address, local_port, remote_address, remote_port, vvc_enabled, srtp_enabled); } diff --git a/uvgrtp/latency_sender.cc b/uvgrtp/latency_sender.cc index 8887f29..b55aa10 100644 --- a/uvgrtp/latency_sender.cc +++ b/uvgrtp/latency_sender.cc @@ -1,4 +1,5 @@ #include "uvgrtp_util.h" +#include "../util/util.hh" #include #include @@ -9,9 +10,7 @@ constexpr float LATENCY_TEST_FPS = 30.0f; -extern void* get_mem(std::string filename, size_t& len); - -std::chrono::high_resolution_clock::time_point start2; +std::chrono::high_resolution_clock::time_point frame_send_time; size_t frames = 0; size_t ninters = 0; @@ -28,7 +27,7 @@ static void hook_sender(void *arg, uvg_rtp::frame::rtp_frame *frame) if (frame) { uint64_t diff = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start2 + std::chrono::high_resolution_clock::now() - frame_send_time ).count(); switch ((frame->payload[0] >> 1) & 0x3f) { @@ -47,64 +46,63 @@ static void hook_sender(void *arg, uvg_rtp::frame::rtp_frame *frame) } } -static int sender(void) +static int sender(std::string input_file, std::string local_address, int local_port, + std::string remote_address, int remote_port, float fps, bool vvc_enabled, bool srtp_enabled) { - std::string addr("127.0.0.1"); - uvgrtp::context rtp_ctx; uvgrtp::session* session = nullptr; uvgrtp::media_stream* send = nullptr; - uint16_t send_port = SENDER_PORT + thread_num * 2; - uint16_t receive_port = RECEIVER_PORT + thread_num * 2; - intialize_uvgrtp(rtp_ctx, session, send, addr_, addr_, send_port, receive_port, false); + uint16_t thread_local_port = local_port + thread_num * 2; + uint16_t thread_remote_port = remote_port + thread_num * 2; + + intialize_uvgrtp(rtp_ctx, &session, &send, remote_address, local_address, + thread_local_port, thread_remote_port, vvc_enabled, srtp_enabled); send->install_receive_hook(nullptr, hook_sender); size_t len = 0; - void* mem = get_mem("test_file.hevc", len); + void* mem = get_mem(input_file, len); - if (mem == nullptr) + std::vector chunk_sizes; + get_chunk_locations(get_chunk_filename(input_file), chunk_sizes); + + if (mem == nullptr || chunk_sizes.empty()) { return EXIT_FAILURE; } - uint64_t csize = 0; - uint64_t diff = 0; - uint64_t current = 0; + uint64_t current_frame = 0; uint64_t chunk_size = 0; - uint64_t period = (uint64_t)((1000 / LATENCY_TEST_FPS) * 1000); + uint64_t period = (uint64_t)((1000 / fps) * 1000); + size_t offset = 0; rtp_error_t ret = RTP_OK; std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); - for (int rounds = 0; rounds < 1; ++rounds) { - for (size_t offset = 0, k = 0; offset < len; ++k) { - memcpy(&chunk_size, (uint8_t *)mem + offset, sizeof(uint64_t)); - - offset += sizeof(uint64_t); - - // record send time - start2 = std::chrono::high_resolution_clock::now(); - if ((ret = send->push_frame((uint8_t *)mem + offset, chunk_size, 0)) != RTP_OK) { - fprintf(stderr, "push_frame() failed!\n"); - cleanup_uvgrtp(rtp_ctx, session, send); - return EXIT_FAILURE; - } - - // wait until is the time to send next latency test frame - auto runtime = (uint64_t)std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start - ).count(); - - if (runtime < current * period) - std::this_thread::sleep_for(std::chrono::microseconds(current * period - runtime)); - - current += 1; - offset += chunk_size; + for (auto& chunk_size : chunk_sizes) + { + // record send time + frame_send_time = std::chrono::high_resolution_clock::now(); + if ((ret = send->push_frame((uint8_t*)mem + offset, chunk_size, 0)) != RTP_OK) { + fprintf(stderr, "push_frame() failed!\n"); + cleanup_uvgrtp(rtp_ctx, session, send); + return EXIT_FAILURE; } + + current_frame += 1; + offset += chunk_size; + + // wait until is the time to send next latency test frame + auto runtime = (uint64_t)std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - start).count(); + + if (runtime < current_frame * period) + std::this_thread::sleep_for(std::chrono::microseconds(current_frame * period - runtime)); } - std::this_thread::sleep_for(std::chrono::milliseconds(50)); // just so we don't exit too soon + + // just so we don't exit before last frame has arrived. Does not affect results + std::this_thread::sleep_for(std::chrono::milliseconds(100)); cleanup_uvgrtp(rtp_ctx, session, send); @@ -120,7 +118,22 @@ static int sender(void) int main(int argc, char **argv) { - (void)argc, (void)argv; + if (argc != 9) { + fprintf(stderr, "usage: ./%s \ + \n", __FILE__); + return EXIT_FAILURE; + } - return sender(); -} + std::string input_file = argv[1]; + + std::string local_address = argv[2]; + int local_port = atoi(argv[3]); + std::string remote_address = argv[4]; + int remote_port = atoi(argv[5]); + + float fps = atof(argv[6]); + bool vvc_enabled = get_vvc_state(argv[7]); + bool srtp_enabled = get_srtp_state(argv[8]); + + return sender(input_file, local_address, local_port, remote_address, remote_port, fps, vvc_enabled, srtp_enabled); +} \ No newline at end of file diff --git a/uvgrtp/receiver.cc b/uvgrtp/receiver.cc index 0f25047..0fdc72c 100644 --- a/uvgrtp/receiver.cc +++ b/uvgrtp/receiver.cc @@ -1,4 +1,5 @@ #include "uvgrtp_util.hh" +#include "../util/util.hh" #include #include @@ -33,28 +34,17 @@ int main(int argc, char** argv) } std::string local_address = argv[1]; - int local_port = atoi(argv[2]); + int local_port = atoi(argv[2]); std::string remote_address = argv[3]; - int remote_port = atoi(argv[4]); + int remote_port = atoi(argv[4]); std::cout << "Starting uvgRTP receiver tests. " << local_address << ":" << local_port << "<-" << remote_address << ":" << remote_port << std::endl; int nthreads = atoi(argv[5]); - std::string format = argv[6]; - bool vvc = false; - if (format == "vvc" || format == "h266") - { - vvc = true; - } - else if (format != "hevc" && format != "h265") - { - std::cerr << "Unsupported uvgRTP receiver format: " << format << std::endl; - return EXIT_FAILURE; - } - - bool srtp = false; // TODO + bool vvc_enabled = get_vvc_state(argv[6]); + bool srtp_enabled = get_srtp_state(argv[7]); thread_info = (struct thread_info*)calloc(nthreads, sizeof(*thread_info)); @@ -62,7 +52,7 @@ int main(int argc, char** argv) for (int i = 0; i < nthreads; ++i) { threads.push_back(new std::thread(receiver_thread, i, nthreads, local_address, local_port, - remote_address, remote_port, vvc, srtp)); + remote_address, remote_port, vvc_enabled, srtp_enabled)); } // wait all the thread executions to end and delete them diff --git a/uvgrtp/sender.cc b/uvgrtp/sender.cc index 892c13f..679993f 100644 --- a/uvgrtp/sender.cc +++ b/uvgrtp/sender.cc @@ -23,37 +23,18 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - std::string input_file = argv[1]; - std::string result_file = argv[2]; + std::string input_file = argv[1]; + std::string result_file = argv[2]; - std::string local_address = argv[3]; - int local_port = atoi(argv[4]); + std::string local_address = argv[3]; + int local_port = atoi(argv[4]); std::string remote_address = argv[5]; int remote_port = atoi(argv[6]); - int nthreads = atoi(argv[7]); - int fps = atoi(argv[8]); - std::string format = argv[9]; - std::string srtp = argv[10]; - - bool vvc = false; - - if (format == "vvc" || format == "h266") - { - vvc = true; - } - else if (format != "hevc" && format != "h265") - { - std::cerr << "Unsupported uvgRTP sender format: " << format << std::endl; - return EXIT_FAILURE; - } - - bool srtp_enabled = false; - - if (srtp == "1" || srtp == "yes" || srtp == "y" || srtp == "srtp") - { - srtp_enabled = true; - } + int nthreads = atoi(argv[7]); + int fps = atoi(argv[8]); + bool vvc_enabled = get_vvc_state(argv[9]); + bool srtp_enabled = get_srtp_state(argv[10]); std::cout << "Starting uvgRTP sender tests. " << local_address << ":" << local_port << "->" << remote_address << ":" << remote_port << std::endl; @@ -75,7 +56,7 @@ int main(int argc, char **argv) for (int i = 0; i < nthreads; ++i) { threads.push_back(new std::thread(sender_thread, mem, local_address, local_port, remote_address, - remote_port, i, fps, vvc, srtp_enabled, result_file, chunk_sizes)); + remote_port, i, fps, vvc_enabled, srtp_enabled, result_file, chunk_sizes)); } for (unsigned int i = 0; i < threads.size(); ++i) {