OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include "webrtc/video/video_quality_test.h" | 10 #include "webrtc/video/video_quality_test.h" |
11 | 11 |
12 #include <stdio.h> | 12 #include <stdio.h> |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <deque> | 14 #include <deque> |
15 #include <map> | 15 #include <map> |
16 #include <sstream> | 16 #include <sstream> |
17 #include <string> | 17 #include <string> |
18 #include <vector> | 18 #include <vector> |
19 | 19 |
20 #include "webrtc/base/checks.h" | 20 #include "webrtc/base/checks.h" |
21 #include "webrtc/base/cpu_time.h" | |
21 #include "webrtc/base/event.h" | 22 #include "webrtc/base/event.h" |
22 #include "webrtc/base/format_macros.h" | 23 #include "webrtc/base/format_macros.h" |
23 #include "webrtc/base/optional.h" | 24 #include "webrtc/base/optional.h" |
24 #include "webrtc/base/platform_file.h" | 25 #include "webrtc/base/platform_file.h" |
25 #include "webrtc/base/timeutils.h" | 26 #include "webrtc/base/timeutils.h" |
26 #include "webrtc/call/call.h" | 27 #include "webrtc/call/call.h" |
27 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 28 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
28 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" | 29 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" |
29 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" | 30 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" |
30 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" | 31 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 pre_encode_proxy_(this), | 156 pre_encode_proxy_(this), |
156 encode_timing_proxy_(this), | 157 encode_timing_proxy_(this), |
157 frames_to_process_(duration_frames), | 158 frames_to_process_(duration_frames), |
158 frames_recorded_(0), | 159 frames_recorded_(0), |
159 frames_processed_(0), | 160 frames_processed_(0), |
160 dropped_frames_(0), | 161 dropped_frames_(0), |
161 dropped_frames_before_first_encode_(0), | 162 dropped_frames_before_first_encode_(0), |
162 dropped_frames_before_rendering_(0), | 163 dropped_frames_before_rendering_(0), |
163 last_render_time_(0), | 164 last_render_time_(0), |
164 rtp_timestamp_delta_(0), | 165 rtp_timestamp_delta_(0), |
166 cpu_time_(0), | |
167 wallclock_time_(0), | |
165 avg_psnr_threshold_(avg_psnr_threshold), | 168 avg_psnr_threshold_(avg_psnr_threshold), |
166 avg_ssim_threshold_(avg_ssim_threshold), | 169 avg_ssim_threshold_(avg_ssim_threshold), |
167 is_quick_test_enabled_(is_quick_test_enabled), | 170 is_quick_test_enabled_(is_quick_test_enabled), |
168 stats_polling_thread_(&PollStatsThread, this, "StatsPoller"), | 171 stats_polling_thread_(&PollStatsThread, this, "StatsPoller"), |
169 comparison_available_event_(false, false), | 172 comparison_available_event_(false, false), |
170 done_(true, false) { | 173 done_(true, false) { |
171 // Create thread pool for CPU-expensive PSNR/SSIM calculations. | 174 // Create thread pool for CPU-expensive PSNR/SSIM calculations. |
172 | 175 |
173 // Try to use about as many threads as cores, but leave kMinCoresLeft alone, | 176 // Try to use about as many threads as cores, but leave kMinCoresLeft alone, |
174 // so that we don't accidentally starve "real" worker threads (codec etc). | 177 // so that we don't accidentally starve "real" worker threads (codec etc). |
(...skipping 11 matching lines...) Expand all Loading... | |
186 num_cores -= kMinCoresLeft; | 189 num_cores -= kMinCoresLeft; |
187 num_cores = std::min(num_cores, kMaxComparisonThreads); | 190 num_cores = std::min(num_cores, kMaxComparisonThreads); |
188 } | 191 } |
189 | 192 |
190 for (uint32_t i = 0; i < num_cores; ++i) { | 193 for (uint32_t i = 0; i < num_cores; ++i) { |
191 rtc::PlatformThread* thread = | 194 rtc::PlatformThread* thread = |
192 new rtc::PlatformThread(&FrameComparisonThread, this, "Analyzer"); | 195 new rtc::PlatformThread(&FrameComparisonThread, this, "Analyzer"); |
193 thread->Start(); | 196 thread->Start(); |
194 comparison_thread_pool_.push_back(thread); | 197 comparison_thread_pool_.push_back(thread); |
195 } | 198 } |
199 | |
200 // Start time measurements | |
sprang_webrtc
2017/02/21 15:43:20
nit: End comments with period.
ilnik
2017/02/22 08:43:28
Done.
| |
201 cpu_time_ -= rtc::GetProcessCpuTimeNanos(); | |
sprang_webrtc
2017/02/21 15:43:20
I was a bit confused of the usage here at first. C
sprang_webrtc
2017/02/21 15:43:20
I'm not sure we should start measuring time from t
ilnik
2017/02/22 08:43:28
Done.
ilnik
2017/02/22 08:43:28
I created special functions for manipulating cpu_t
| |
202 wallclock_time_ -= rtc::SystemTimeNanos(); | |
196 } | 203 } |
197 | 204 |
198 ~VideoAnalyzer() { | 205 ~VideoAnalyzer() { |
199 for (rtc::PlatformThread* thread : comparison_thread_pool_) { | 206 for (rtc::PlatformThread* thread : comparison_thread_pool_) { |
200 thread->Stop(); | 207 thread->Stop(); |
201 delete thread; | 208 delete thread; |
202 } | 209 } |
203 } | 210 } |
204 | 211 |
205 virtual void SetReceiver(PacketReceiver* receiver) { receiver_ = receiver; } | 212 virtual void SetReceiver(PacketReceiver* receiver) { receiver_ = receiver; } |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 rtc::CritScope lock(&comparison_lock_); | 330 rtc::CritScope lock(&comparison_lock_); |
324 if (frames_recorded_ < frames_to_process_) | 331 if (frames_recorded_ < frames_to_process_) |
325 encoded_frame_size_.AddSample(frame.length_); | 332 encoded_frame_size_.AddSample(frame.length_); |
326 } | 333 } |
327 | 334 |
328 void OnFrame(const VideoFrame& video_frame) override { | 335 void OnFrame(const VideoFrame& video_frame) override { |
329 int64_t render_time_ms = | 336 int64_t render_time_ms = |
330 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds(); | 337 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds(); |
331 | 338 |
332 rtc::CritScope lock(&crit_); | 339 rtc::CritScope lock(&crit_); |
340 | |
341 cpu_time_ += rtc::GetThreadCpuTimeNanos(); | |
sprang_webrtc
2017/02/21 15:43:20
Is this scope significant?
I think it would be mor
ilnik
2017/02/22 08:43:28
Done it the other way.
| |
342 | |
333 int64_t send_timestamp = | 343 int64_t send_timestamp = |
334 wrap_handler_.Unwrap(video_frame.timestamp() - rtp_timestamp_delta_); | 344 wrap_handler_.Unwrap(video_frame.timestamp() - rtp_timestamp_delta_); |
335 | 345 |
336 while (wrap_handler_.Unwrap(frames_.front().timestamp()) < send_timestamp) { | 346 while (wrap_handler_.Unwrap(frames_.front().timestamp()) < send_timestamp) { |
337 if (!last_rendered_frame_) { | 347 if (!last_rendered_frame_) { |
338 // No previous frame rendered, this one was dropped after sending but | 348 // No previous frame rendered, this one was dropped after sending but |
339 // before rendering. | 349 // before rendering. |
340 ++dropped_frames_before_rendering_; | 350 ++dropped_frames_before_rendering_; |
341 } else { | 351 } else { |
342 AddFrameComparison(frames_.front(), *last_rendered_frame_, true, | 352 AddFrameComparison(frames_.front(), *last_rendered_frame_, true, |
(...skipping 10 matching lines...) Expand all Loading... | |
353 if (send_timestamp == reference_timestamp - 1) { | 363 if (send_timestamp == reference_timestamp - 1) { |
354 // TODO(ivica): Make this work for > 2 streams. | 364 // TODO(ivica): Make this work for > 2 streams. |
355 // Look at RTPSender::BuildRTPHeader. | 365 // Look at RTPSender::BuildRTPHeader. |
356 ++send_timestamp; | 366 ++send_timestamp; |
357 } | 367 } |
358 ASSERT_EQ(reference_timestamp, send_timestamp); | 368 ASSERT_EQ(reference_timestamp, send_timestamp); |
359 | 369 |
360 AddFrameComparison(reference_frame, video_frame, false, render_time_ms); | 370 AddFrameComparison(reference_frame, video_frame, false, render_time_ms); |
361 | 371 |
362 last_rendered_frame_ = rtc::Optional<VideoFrame>(video_frame); | 372 last_rendered_frame_ = rtc::Optional<VideoFrame>(video_frame); |
373 | |
374 cpu_time_ -= rtc::GetThreadCpuTimeNanos(); | |
sprang_webrtc
2017/02/21 15:43:20
...and here did something like
cpu_time_start_offs
ilnik
2017/02/22 08:43:28
Acknowledged.
| |
363 } | 375 } |
364 | 376 |
365 void Wait() { | 377 void Wait() { |
366 // Frame comparisons can be very expensive. Wait for test to be done, but | 378 // Frame comparisons can be very expensive. Wait for test to be done, but |
367 // at time-out check if frames_processed is going up. If so, give it more | 379 // at time-out check if frames_processed is going up. If so, give it more |
368 // time, otherwise fail. Hopefully this will reduce test flakiness. | 380 // time, otherwise fail. Hopefully this will reduce test flakiness. |
369 | 381 |
370 stats_polling_thread_.Start(); | 382 stats_polling_thread_.Start(); |
371 | 383 |
372 int last_frames_processed = -1; | 384 int last_frames_processed = -1; |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
602 // Wait until new comparison task is available, or test is done. | 614 // Wait until new comparison task is available, or test is done. |
603 // If done, wake up remaining threads waiting. | 615 // If done, wake up remaining threads waiting. |
604 comparison_available_event_.Wait(1000); | 616 comparison_available_event_.Wait(1000); |
605 if (AllFramesRecorded()) { | 617 if (AllFramesRecorded()) { |
606 comparison_available_event_.Set(); | 618 comparison_available_event_.Set(); |
607 return false; | 619 return false; |
608 } | 620 } |
609 return true; // Try again. | 621 return true; // Try again. |
610 } | 622 } |
611 | 623 |
624 { | |
625 rtc::CritScope crit(&comparison_lock_); | |
626 cpu_time_ += rtc::GetThreadCpuTimeNanos(); | |
sprang_webrtc
2017/02/21 15:43:20
Could do same thing with a local temp timestamp he
ilnik
2017/02/22 08:43:28
Acknowledged.
| |
627 } | |
628 | |
612 PerformFrameComparison(comparison); | 629 PerformFrameComparison(comparison); |
613 | 630 |
631 { | |
632 rtc::CritScope crit(&comparison_lock_); | |
633 cpu_time_ -= rtc::GetThreadCpuTimeNanos(); | |
634 } | |
635 | |
614 if (FrameProcessed()) { | 636 if (FrameProcessed()) { |
615 PrintResults(); | 637 PrintResults(); |
616 if (graph_data_output_file_) | 638 if (graph_data_output_file_) |
617 PrintSamplesToFile(); | 639 PrintSamplesToFile(); |
618 done_.Set(); | 640 done_.Set(); |
619 comparison_available_event_.Set(); | 641 comparison_available_event_.Set(); |
620 return false; | 642 return false; |
621 } | 643 } |
622 | 644 |
623 return true; | 645 return true; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
657 // last frame to be processed. | 679 // last frame to be processed. |
658 bool FrameProcessed() { | 680 bool FrameProcessed() { |
659 rtc::CritScope crit(&comparison_lock_); | 681 rtc::CritScope crit(&comparison_lock_); |
660 ++frames_processed_; | 682 ++frames_processed_; |
661 assert(frames_processed_ <= frames_to_process_); | 683 assert(frames_processed_ <= frames_to_process_); |
662 return frames_processed_ == frames_to_process_; | 684 return frames_processed_ == frames_to_process_; |
663 } | 685 } |
664 | 686 |
665 void PrintResults() { | 687 void PrintResults() { |
666 rtc::CritScope crit(&comparison_lock_); | 688 rtc::CritScope crit(&comparison_lock_); |
689 cpu_time_ += rtc::GetProcessCpuTimeNanos(); | |
690 wallclock_time_ += rtc::SystemTimeNanos(); | |
691 | |
667 PrintResult("psnr", psnr_, " dB"); | 692 PrintResult("psnr", psnr_, " dB"); |
668 PrintResult("ssim", ssim_, " score"); | 693 PrintResult("ssim", ssim_, " score"); |
669 PrintResult("sender_time", sender_time_, " ms"); | 694 PrintResult("sender_time", sender_time_, " ms"); |
670 PrintResult("receiver_time", receiver_time_, " ms"); | 695 PrintResult("receiver_time", receiver_time_, " ms"); |
671 PrintResult("total_delay_incl_network", end_to_end_, " ms"); | 696 PrintResult("total_delay_incl_network", end_to_end_, " ms"); |
672 PrintResult("time_between_rendered_frames", rendered_delta_, " ms"); | 697 PrintResult("time_between_rendered_frames", rendered_delta_, " ms"); |
673 PrintResult("encoded_frame_size", encoded_frame_size_, " bytes"); | 698 PrintResult("encoded_frame_size", encoded_frame_size_, " bytes"); |
674 PrintResult("encode_frame_rate", encode_frame_rate_, " fps"); | 699 PrintResult("encode_frame_rate", encode_frame_rate_, " fps"); |
675 PrintResult("encode_time", encode_time_ms_, " ms"); | 700 PrintResult("encode_time", encode_time_ms_, " ms"); |
676 PrintResult("encode_usage_percent", encode_usage_percent_, " percent"); | 701 PrintResult("encode_usage_percent", encode_usage_percent_, " percent"); |
677 PrintResult("media_bitrate", media_bitrate_bps_, " bps"); | 702 PrintResult("media_bitrate", media_bitrate_bps_, " bps"); |
678 | 703 |
679 if (receive_stream_ != nullptr) { | 704 if (receive_stream_ != nullptr) { |
680 PrintResult("decode_time", decode_time_ms_, " ms"); | 705 PrintResult("decode_time", decode_time_ms_, " ms"); |
681 PrintResult("decode_time_max", decode_time_max_ms_, " ms"); | 706 PrintResult("decode_time_max", decode_time_max_ms_, " ms"); |
682 } | 707 } |
683 | 708 |
684 printf("RESULT dropped_frames: %s = %d frames\n", test_label_.c_str(), | 709 printf("RESULT dropped_frames: %s = %d frames\n", test_label_.c_str(), |
685 dropped_frames_); | 710 dropped_frames_); |
686 printf("RESULT dropped_frames_before_first_encode: %s = %d frames\n", | 711 printf("RESULT dropped_frames_before_first_encode: %s = %d frames\n", |
687 test_label_.c_str(), dropped_frames_before_first_encode_); | 712 test_label_.c_str(), dropped_frames_before_first_encode_); |
688 printf("RESULT dropped_frames_before_rendering: %s = %d frames\n", | 713 printf("RESULT dropped_frames_before_rendering: %s = %d frames\n", |
689 test_label_.c_str(), dropped_frames_before_rendering_); | 714 test_label_.c_str(), dropped_frames_before_rendering_); |
715 printf("RESULT cpu_usage: %s = %lf %%\n", test_label_.c_str(), | |
716 static_cast<double>(cpu_time_) / wallclock_time_ * 100.0); | |
690 // Disable quality check for quick test, as quality checks may fail | 717 // Disable quality check for quick test, as quality checks may fail |
691 // because too few samples were collected. | 718 // because too few samples were collected. |
692 if (!is_quick_test_enabled_) { | 719 if (!is_quick_test_enabled_) { |
693 EXPECT_GT(psnr_.Mean(), avg_psnr_threshold_); | 720 EXPECT_GT(psnr_.Mean(), avg_psnr_threshold_); |
694 EXPECT_GT(ssim_.Mean(), avg_ssim_threshold_); | 721 EXPECT_GT(ssim_.Mean(), avg_ssim_threshold_); |
695 } | 722 } |
696 } | 723 } |
697 | 724 |
698 void PerformFrameComparison(const FrameComparison& comparison) { | 725 void PerformFrameComparison(const FrameComparison& comparison) { |
699 // Perform expensive psnr and ssim calculations while not holding lock. | 726 // Perform expensive psnr and ssim calculations while not holding lock. |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
878 test::Statistics media_bitrate_bps_ GUARDED_BY(comparison_lock_); | 905 test::Statistics media_bitrate_bps_ GUARDED_BY(comparison_lock_); |
879 | 906 |
880 const int frames_to_process_; | 907 const int frames_to_process_; |
881 int frames_recorded_; | 908 int frames_recorded_; |
882 int frames_processed_; | 909 int frames_processed_; |
883 int dropped_frames_; | 910 int dropped_frames_; |
884 int dropped_frames_before_first_encode_; | 911 int dropped_frames_before_first_encode_; |
885 int dropped_frames_before_rendering_; | 912 int dropped_frames_before_rendering_; |
886 int64_t last_render_time_; | 913 int64_t last_render_time_; |
887 uint32_t rtp_timestamp_delta_; | 914 uint32_t rtp_timestamp_delta_; |
915 int64_t cpu_time_; | |
916 int64_t wallclock_time_; | |
888 | 917 |
889 rtc::CriticalSection crit_; | 918 rtc::CriticalSection crit_; |
890 std::deque<VideoFrame> frames_ GUARDED_BY(crit_); | 919 std::deque<VideoFrame> frames_ GUARDED_BY(crit_); |
891 rtc::Optional<VideoFrame> last_rendered_frame_ GUARDED_BY(crit_); | 920 rtc::Optional<VideoFrame> last_rendered_frame_ GUARDED_BY(crit_); |
892 rtc::TimestampWrapAroundHandler wrap_handler_ GUARDED_BY(crit_); | 921 rtc::TimestampWrapAroundHandler wrap_handler_ GUARDED_BY(crit_); |
893 std::map<int64_t, int64_t> send_times_ GUARDED_BY(crit_); | 922 std::map<int64_t, int64_t> send_times_ GUARDED_BY(crit_); |
894 std::map<int64_t, int64_t> recv_times_ GUARDED_BY(crit_); | 923 std::map<int64_t, int64_t> recv_times_ GUARDED_BY(crit_); |
895 std::map<int64_t, size_t> encoded_frame_sizes_ GUARDED_BY(crit_); | 924 std::map<int64_t, size_t> encoded_frame_sizes_ GUARDED_BY(crit_); |
896 rtc::Optional<uint32_t> first_encoded_timestamp_ GUARDED_BY(crit_); | 925 rtc::Optional<uint32_t> first_encoded_timestamp_ GUARDED_BY(crit_); |
897 rtc::Optional<uint32_t> first_sent_timestamp_ GUARDED_BY(crit_); | 926 rtc::Optional<uint32_t> first_sent_timestamp_ GUARDED_BY(crit_); |
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1604 std::ostringstream str; | 1633 std::ostringstream str; |
1605 str << receive_logs_++; | 1634 str << receive_logs_++; |
1606 std::string path = | 1635 std::string path = |
1607 params_.video.encoded_frame_base_path + "." + str.str() + ".recv.ivf"; | 1636 params_.video.encoded_frame_base_path + "." + str.str() + ".recv.ivf"; |
1608 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path), | 1637 stream->EnableEncodedFrameRecording(rtc::CreatePlatformFile(path), |
1609 10000000); | 1638 10000000); |
1610 } | 1639 } |
1611 } | 1640 } |
1612 | 1641 |
1613 } // namespace webrtc | 1642 } // namespace webrtc |
OLD | NEW |