OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 const int kMinimumFramesForAnalysis = 5; | 100 const int kMinimumFramesForAnalysis = 5; |
101 | 101 |
102 class LatencyTest | 102 class LatencyTest |
103 : public BrowserPerfTest, | 103 : public BrowserPerfTest, |
104 public ::testing::WithParamInterface<int> { | 104 public ::testing::WithParamInterface<int> { |
105 public: | 105 public: |
106 LatencyTest() : | 106 LatencyTest() : |
107 query_instant_(Query::EventPhase() == | 107 query_instant_(Query::EventPhase() == |
108 Query::Phase(TRACE_EVENT_PHASE_INSTANT)), | 108 Query::Phase(TRACE_EVENT_PHASE_INSTANT)), |
109 // These queries are initialized in RunTest. | 109 // These queries are initialized in RunTest. |
110 query_swaps_(Query::Bool(false)), | 110 query_begin_swaps_(Query::Bool(false)), |
| 111 query_end_swaps_(Query::Bool(false)), |
111 query_inputs_(Query::Bool(false)), | 112 query_inputs_(Query::Bool(false)), |
112 query_blits_(Query::Bool(false)), | 113 query_blits_(Query::Bool(false)), |
113 query_clears_(Query::Bool(false)), | 114 query_clears_(Query::Bool(false)), |
114 mouse_x_(0), | 115 mouse_x_(0), |
115 tab_width_(0), | 116 tab_width_(0), |
116 mode_(kWebGL), | 117 mode_(kWebGL), |
117 delay_time_us_(0), | 118 delay_time_us_(0), |
118 num_frames_(0), | 119 num_frames_(0), |
119 verbose_(false), | 120 verbose_(false), |
120 test_flags_(0) {} | 121 test_flags_(0) {} |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 void SendInput(); | 159 void SendInput(); |
159 | 160 |
160 void PrintEvents(const TraceEventVector& events); | 161 void PrintEvents(const TraceEventVector& events); |
161 | 162 |
162 // Path to html file. | 163 // Path to html file. |
163 FilePath test_path_; | 164 FilePath test_path_; |
164 | 165 |
165 // Query INSTANT events. | 166 // Query INSTANT events. |
166 Query query_instant_; | 167 Query query_instant_; |
167 | 168 |
168 // Query "swaps" which is SwapBuffers for GL and UpdateRect for software. | 169 // Query begin of "swaps" which is SwapBuffers for GL and UpdateRect for |
169 Query query_swaps_; | 170 // software. |
| 171 Query query_begin_swaps_; |
| 172 |
| 173 // Query end of "swaps" which is SwapBuffers for GL and UpdateRect for |
| 174 // software. |
| 175 Query query_end_swaps_; |
170 | 176 |
171 // Query mouse input entry events in browser process (ForwardMouseEvent). | 177 // Query mouse input entry events in browser process (ForwardMouseEvent). |
172 Query query_inputs_; | 178 Query query_inputs_; |
173 | 179 |
174 // Query GL blits for the WebGL canvas -- represents the compositor consuming | 180 // Query GL blits for the WebGL canvas -- represents the compositor consuming |
175 // the WebGL contents for display. | 181 // the WebGL contents for display. |
176 Query query_blits_; | 182 Query query_blits_; |
177 | 183 |
178 // Query glClear calls with mouse coordinate as clear color. | 184 // Query glClear calls with mouse coordinate as clear color. |
179 Query query_clears_; | 185 Query query_clears_; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 return behaviors; | 238 return behaviors; |
233 } | 239 } |
234 | 240 |
235 void LatencyTest::RunTest(LatencyTestMode mode, | 241 void LatencyTest::RunTest(LatencyTestMode mode, |
236 const std::vector<int>& behaviors) { | 242 const std::vector<int>& behaviors) { |
237 mode_ = mode; | 243 mode_ = mode; |
238 verbose_ = (logging::GetVlogLevel("latency_tests") > 0); | 244 verbose_ = (logging::GetVlogLevel("latency_tests") > 0); |
239 | 245 |
240 // Construct queries for searching trace events via TraceAnalyzer. | 246 // Construct queries for searching trace events via TraceAnalyzer. |
241 if (mode_ == kWebGL) { | 247 if (mode_ == kWebGL) { |
242 query_swaps_ = query_instant_ && | 248 query_begin_swaps_ = query_instant_ && |
243 Query::EventName() == Query::String("SwapBuffers") && | 249 Query::EventName() == Query::String("SwapBuffers") && |
244 Query::EventArg("width") != Query::Int(kWebGLCanvasWidth); | 250 Query::EventArg("width") != Query::Int(kWebGLCanvasWidth); |
| 251 query_end_swaps_ = query_instant_ && |
| 252 Query::EventName() == Query::String("CompositorSwapBuffersComplete"); |
245 } else if (mode_ == kSoftware) { | 253 } else if (mode_ == kSoftware) { |
246 // Software updates need to have x=0 and y=0 to contain the input color. | 254 // Software updates need to have x=0 and y=0 to contain the input color. |
247 query_swaps_ = query_instant_ && | 255 query_begin_swaps_ = query_instant_ && |
248 Query::EventName() == Query::String("UpdateRect") && | 256 Query::EventName() == Query::String("UpdateRect") && |
249 Query::EventArg("x+y") == Query::Int(0); | 257 Query::EventArg("x+y") == Query::Int(0); |
| 258 query_end_swaps_ = query_instant_ && |
| 259 Query::EventName() == Query::String("UpdateRectComplete") && |
| 260 Query::EventArg("x+y") == Query::Int(0); |
250 } | 261 } |
251 query_inputs_ = query_instant_ && | 262 query_inputs_ = query_instant_ && |
252 Query::EventName() == Query::String("MouseEventBegin"); | 263 Query::EventName() == Query::String("MouseEventBegin"); |
253 query_blits_ = query_instant_ && | 264 query_blits_ = query_instant_ && |
254 Query::EventName() == Query::String("DoBlit") && | 265 Query::EventName() == Query::String("DoBlit") && |
255 Query::EventArg("width") == Query::Int(kWebGLCanvasWidth); | 266 Query::EventArg("width") == Query::Int(kWebGLCanvasWidth); |
256 query_clears_ = query_instant_ && | 267 query_clears_ = query_instant_ && |
257 Query::EventName() == Query::String("DoClear") && | 268 Query::EventName() == Query::String("DoClear") && |
258 Query::EventArg("green") == Query::Int(kClearColorGreen); | 269 Query::EventArg("green") == Query::Int(kClearColorGreen); |
259 Query query_width_swaps = query_swaps_; | 270 Query query_width_swaps = query_begin_swaps_; |
260 if (mode_ == kSoftware) { | 271 if (mode_ == kSoftware) { |
261 query_width_swaps = query_instant_ && | 272 query_width_swaps = query_instant_ && |
262 Query::EventName() == Query::String("UpdateRectWidth") && | 273 Query::EventName() == Query::String("UpdateRectWidth") && |
263 Query::EventArg("width") > Query::Int(kWebGLCanvasWidth); | 274 Query::EventArg("width") > Query::Int(kWebGLCanvasWidth); |
264 } | 275 } |
265 | 276 |
266 // Set path to test html. | 277 // Set path to test html. |
267 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_path_)); | 278 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_path_)); |
268 test_path_ = test_path_.Append(FILE_PATH_LITERAL("perf")); | 279 test_path_ = test_path_.Append(FILE_PATH_LITERAL("perf")); |
269 test_path_ = test_path_.Append(FILE_PATH_LITERAL("latency_suite.html")); | 280 test_path_ = test_path_.Append(FILE_PATH_LITERAL("latency_suite.html")); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 analyzer_->MergeAssociatedEventArgs(); | 394 analyzer_->MergeAssociatedEventArgs(); |
384 } | 395 } |
385 | 396 |
386 double LatencyTest::CalculateLatency() { | 397 double LatencyTest::CalculateLatency() { |
387 TraceEventVector events; | 398 TraceEventVector events; |
388 if (mode_ == kWebGL) { | 399 if (mode_ == kWebGL) { |
389 // Search for three types of events in WebGL mode: | 400 // Search for three types of events in WebGL mode: |
390 // - onscreen swaps. | 401 // - onscreen swaps. |
391 // - DoClear calls that contain the mouse x coordinate. | 402 // - DoClear calls that contain the mouse x coordinate. |
392 // - mouse events. | 403 // - mouse events. |
393 analyzer_->FindEvents(query_swaps_ || query_inputs_ || | 404 analyzer_->FindEvents(query_begin_swaps_ || query_end_swaps_ || |
394 query_blits_ || query_clears_, &events); | 405 query_inputs_ || query_blits_ || query_clears_, |
| 406 &events); |
395 } else if (mode_ == kSoftware) { | 407 } else if (mode_ == kSoftware) { |
396 analyzer_->FindEvents(query_swaps_ || query_inputs_, &events); | 408 analyzer_->FindEvents(query_begin_swaps_ || query_end_swaps_ || |
| 409 query_inputs_, &events); |
397 } else { | 410 } else { |
398 NOTREACHED() << "invalid mode"; | 411 NOTREACHED() << "invalid mode"; |
399 } | 412 } |
400 | 413 |
401 if (verbose_) | 414 if (verbose_) |
402 PrintEvents(events); | 415 PrintEvents(events); |
403 | 416 |
404 int swap_count = 0; | 417 int swap_count = 0; |
405 size_t previous_blit_pos = 0; | 418 size_t previous_blit_pos = 0; |
406 swap_count = 0; | 419 swap_count = 0; |
407 std::vector<int> latencies; | 420 std::vector<int> latencies; |
408 printf("Measured latency (in number of frames) for each frame:\n"); | 421 printf("Measured latency (in number of frames) for each frame:\n"); |
409 for (size_t i = 0; i < events.size(); ++i) { | 422 for (size_t i = 0; i < events.size(); ++i) { |
410 if (query_swaps_.Evaluate(*events[i])) { | 423 if (query_end_swaps_.Evaluate(*events[i])) { |
| 424 size_t end_swap_pos = i; |
| 425 |
411 // Compositor context swap buffers. | 426 // Compositor context swap buffers. |
412 ++swap_count; | 427 ++swap_count; |
413 // Don't analyze first few swaps, because they are filling the rendering | 428 // Don't analyze first few swaps, because they are filling the rendering |
414 // pipeline and may be unstable. | 429 // pipeline and may be unstable. |
415 if (swap_count > kIgnoreBeginFrames) { | 430 if (swap_count > kIgnoreBeginFrames) { |
| 431 // First, find the beginning of this swap. |
| 432 size_t begin_swap_pos = 0; |
| 433 EXPECT_TRUE(FindLastOf(events, query_begin_swaps_, end_swap_pos, |
| 434 &begin_swap_pos)); |
| 435 |
416 int mouse_x = 0; | 436 int mouse_x = 0; |
417 if (mode_ == kWebGL) { | 437 if (mode_ == kWebGL) { |
418 // Trace backwards through the events to find the input event that | 438 // Trace backwards through the events to find the input event that |
419 // matches the glClear that was presented by this SwapBuffers. | 439 // matches the glClear that was presented by this SwapBuffers. |
420 | 440 |
421 // Step 1: Find the last blit (which will be the WebGL blit). | 441 // Step 1: Find the last blit (which will be the WebGL blit). |
422 size_t blit_pos = 0; | 442 size_t blit_pos = 0; |
423 EXPECT_TRUE(FindLastOf(events, query_blits_, i, &blit_pos)); | 443 EXPECT_TRUE(FindLastOf(events, query_blits_, begin_swap_pos, |
| 444 &blit_pos)); |
424 // Skip this SwapBuffers if the blit has already been consumed by a | 445 // Skip this SwapBuffers if the blit has already been consumed by a |
425 // previous SwapBuffers. This means the current frame did not receive | 446 // previous SwapBuffers. This means the current frame did not receive |
426 // an update from WebGL. | 447 // an update from WebGL. |
427 EXPECT_GT(blit_pos, previous_blit_pos); | 448 EXPECT_GT(blit_pos, previous_blit_pos); |
428 if (blit_pos == previous_blit_pos) { | 449 if (blit_pos == previous_blit_pos) { |
429 if (verbose_) | 450 if (verbose_) |
430 printf(" %03d: ERROR\n", swap_count); | 451 printf(" %03d: ERROR\n", swap_count); |
431 else | 452 else |
432 printf(" ERROR"); | 453 printf(" ERROR"); |
433 continue; | 454 continue; |
434 } | 455 } |
435 previous_blit_pos = blit_pos; | 456 previous_blit_pos = blit_pos; |
436 | 457 |
437 // Step 2: find the last clear from the WebGL blit. This will be the | 458 // Step 2: find the last clear from the WebGL blit. This will be the |
438 // value of the latest mouse input that has affected this swap. | 459 // value of the latest mouse input that has affected this swap. |
439 size_t clear_pos = 0; | 460 size_t clear_pos = 0; |
440 EXPECT_TRUE(FindLastOf(events, query_clears_, blit_pos, &clear_pos)); | 461 EXPECT_TRUE(FindLastOf(events, query_clears_, blit_pos, &clear_pos)); |
441 mouse_x = events[clear_pos]->GetKnownArgAsInt("red"); | 462 mouse_x = events[clear_pos]->GetKnownArgAsInt("red"); |
442 } else if (mode_ == kSoftware) { | 463 } else if (mode_ == kSoftware) { |
443 // The software path gets the mouse_x directly from the DIB colors. | 464 // The software path gets the mouse_x directly from the DIB colors. |
444 mouse_x = events[i]->GetKnownArgAsInt("color"); | 465 mouse_x = events[begin_swap_pos]->GetKnownArgAsInt("color"); |
445 } | 466 } |
446 | 467 |
447 // Find the corresponding mouse input. | 468 // Find the corresponding mouse input. |
448 size_t input_pos = 0; | 469 size_t input_pos = 0; |
449 Query query_mouse_event = query_inputs_ && | 470 Query query_mouse_event = query_inputs_ && |
450 Query::EventArg("x") == Query::Int(mouse_x); | 471 Query::EventArg("x") == Query::Int(mouse_x); |
451 EXPECT_TRUE(FindLastOf(events, query_mouse_event, i, &input_pos)); | 472 EXPECT_TRUE(FindLastOf(events, query_mouse_event, begin_swap_pos, |
| 473 &input_pos)); |
452 | 474 |
453 // Step 4: Find the nearest onscreen SwapBuffers to this input event. | 475 // Step 4: Find the nearest onscreen SwapBuffers to this input event. |
454 size_t closest_swap = 0; | 476 size_t closest_swap_to_input = 0; |
455 size_t second_closest_swap = 0; | 477 size_t second_closest_swap = 0; |
456 EXPECT_TRUE(FindClosest(events, query_swaps_, input_pos, | 478 EXPECT_TRUE(FindClosest(events, query_end_swaps_, input_pos, |
457 &closest_swap, &second_closest_swap)); | 479 &closest_swap_to_input, &second_closest_swap)); |
458 int latency = CountMatches(events, query_swaps_, closest_swap, i); | 480 |
| 481 // Calculate latency by counting the number of swaps between the input |
| 482 // event and the corresponding on-screen end-of-swap. |
| 483 int latency = CountMatches(events, query_end_swaps_, |
| 484 closest_swap_to_input, end_swap_pos); |
459 latencies.push_back(latency); | 485 latencies.push_back(latency); |
460 if (verbose_) | 486 if (verbose_) |
461 printf(" %03d: %d\n", swap_count, latency); | 487 printf(" %03d: %d\n", swap_count, latency); |
462 else | 488 else |
463 printf(" %d", latency); | 489 printf(" %d", latency); |
464 } | 490 } |
465 } | 491 } |
466 } | 492 } |
467 printf("\n"); | 493 printf("\n"); |
468 | 494 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 test_url += "&canvasWidth=" + base::IntToString(kWebGLCanvasWidth); | 556 test_url += "&canvasWidth=" + base::IntToString(kWebGLCanvasWidth); |
531 test_url += "&clearColorGreen=" + base::IntToString(kClearColorGreen); | 557 test_url += "&clearColorGreen=" + base::IntToString(kClearColorGreen); |
532 test_url += "&delayTimeMS=" + base::IntToString(delay_time_us_ / 1000); | 558 test_url += "&delayTimeMS=" + base::IntToString(delay_time_us_ / 1000); |
533 test_url += "&y=" + base::IntToString(kMouseY); | 559 test_url += "&y=" + base::IntToString(kMouseY); |
534 return test_url + GetUrlModeString(flags); | 560 return test_url + GetUrlModeString(flags); |
535 } | 561 } |
536 | 562 |
537 void LatencyTest::GetMeanFrameTimeMicros(int* frame_time) const { | 563 void LatencyTest::GetMeanFrameTimeMicros(int* frame_time) const { |
538 TraceEventVector events; | 564 TraceEventVector events; |
539 // Search for compositor swaps (or UpdateRects in the software path). | 565 // Search for compositor swaps (or UpdateRects in the software path). |
540 analyzer_->FindEvents(query_swaps_, &events); | 566 analyzer_->FindEvents(query_end_swaps_, &events); |
541 RateStats stats; | 567 RateStats stats; |
542 ASSERT_TRUE(GetRateStats(events, &stats, NULL)); | 568 ASSERT_TRUE(GetRateStats(events, &stats, NULL)); |
543 | 569 |
544 // Check that the number of swaps is close to kNumFrames. | 570 // Check that the number of swaps is close to kNumFrames. |
545 EXPECT_LT(num_frames_ - num_frames_ / 4, static_cast<int>(events.size())); | 571 EXPECT_LT(num_frames_ - num_frames_ / 4, static_cast<int>(events.size())); |
546 *frame_time = static_cast<int>(stats.mean_us); | 572 *frame_time = static_cast<int>(stats.mean_us); |
547 } | 573 } |
548 | 574 |
549 void LatencyTest::SendInput() { | 575 void LatencyTest::SendInput() { |
550 content::RenderViewHost* rvh = browser()->GetSelectedTabContentsWrapper()-> | 576 content::RenderViewHost* rvh = browser()->GetSelectedTabContentsWrapper()-> |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 INSTANTIATE_TEST_CASE_P(, LatencyTest, ::testing::Values( | 640 INSTANTIATE_TEST_CASE_P(, LatencyTest, ::testing::Values( |
615 0, | 641 0, |
616 kInputHeavy, | 642 kInputHeavy, |
617 kInputHeavy | kInputDirty | kRafHeavy, | 643 kInputHeavy | kInputDirty | kRafHeavy, |
618 kInputHeavy | kInputDirty | kRafHeavy | kPaintHeavy, | 644 kInputHeavy | kInputDirty | kRafHeavy | kPaintHeavy, |
619 kInputDirty | kPaintHeavy, | 645 kInputDirty | kPaintHeavy, |
620 kInputDirty | kRafHeavy | kPaintHeavy | 646 kInputDirty | kRafHeavy | kPaintHeavy |
621 )); | 647 )); |
622 | 648 |
623 } // namespace | 649 } // namespace |
OLD | NEW |