- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / perf / rendering / throughput_tests.cc
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
3 // found in the LICENSE file.
4
5 #include "base/command_line.h"
6 #include "base/file_util.h"
7 #include "base/files/file_path.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/test/trace_event_analyzer.h"
15 #include "base/values.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/browser/ui/window_snapshot/window_snapshot.h"
20 #include "chrome/common/chrome_paths.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/net/url_fixer_upper.h"
23 #include "chrome/test/base/test_switches.h"
24 #include "chrome/test/base/tracing.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "chrome/test/perf/browser_perf_test.h"
27 #include "chrome/test/perf/perf_test.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_view.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/test/browser_test_utils.h"
32 #include "content/public/test/test_utils.h"
33 #include "gpu/config/gpu_test_config.h"
34 #include "net/base/net_util.h"
35 #include "net/dns/mock_host_resolver.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "testing/perf/perf_test.h"
38 #include "third_party/skia/include/core/SkBitmap.h"
39 #include "third_party/skia/include/core/SkColor.h"
40 #include "ui/gfx/codec/png_codec.h"
41 #include "ui/gl/gl_switches.h"
42 #include "url/gurl.h"
43
44 #if defined(OS_WIN)
45 #include "base/win/windows_version.h"
46 #endif
47
48 namespace {
49
50 enum RunTestFlags {
51   kNone = 0,
52   kInternal = 1 << 0,         // Test uses internal test data.
53   kAllowExternalDNS = 1 << 1, // Test needs external DNS lookup.
54   kIsGpuCanvasTest = 1 << 2,  // Test uses GPU accelerated canvas features.
55   kIsFlaky = 1 << 3
56 };
57
58 enum ThroughputTestFlags {
59   kSW = 0,
60   kGPU = 1 << 0,
61   kCompositorThread = 1 << 1
62 };
63
64 const int kSpinUpTimeMs = 4 * 1000;
65 const int kRunTimeMs = 10 * 1000;
66 const int kIgnoreSomeFrames = 3;
67
68 class ThroughputTest : public BrowserPerfTest {
69  public:
70   explicit ThroughputTest(int flags) :
71       use_gpu_(flags & kGPU),
72       use_compositor_thread_(flags & kCompositorThread),
73       spinup_time_ms_(kSpinUpTimeMs),
74       run_time_ms_(kRunTimeMs) {}
75
76   // This indicates running on GPU bots, not necessarily using the GPU.
77   bool IsGpuAvailable() const {
78     return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
79   }
80
81   // Parse flags from JSON to control the test behavior.
82   bool ParseFlagsFromJSON(const base::FilePath& json_dir,
83                           const std::string& json,
84                           int index) {
85     scoped_ptr<base::Value> root;
86     root.reset(base::JSONReader::Read(json));
87
88     ListValue* root_list = NULL;
89     if (!root.get() || !root->GetAsList(&root_list)) {
90       LOG(ERROR) << "JSON missing root list element";
91       return false;
92     }
93
94     DictionaryValue* item = NULL;
95     if (!root_list->GetDictionary(index, &item)) {
96       LOG(ERROR) << "index " << index << " not found in JSON";
97       return false;
98     }
99
100     std::string str;
101     if (item->GetStringASCII("url", &str)) {
102       gurl_ = GURL(str);
103     } else if (item->GetStringASCII("file", &str)) {
104       base::FilePath empty;
105       gurl_ = URLFixerUpper::FixupRelativeFile(empty, empty.AppendASCII(str));
106     } else {
107       LOG(ERROR) << "missing url or file";
108       return false;
109     }
110
111     if (!gurl_.is_valid()) {
112       LOG(ERROR) << "invalid url: " << gurl_.possibly_invalid_spec();
113       return false;
114     }
115
116     base::FilePath::StringType cache_dir;
117     if (item->GetString("local_path", &cache_dir))
118       local_cache_path_ = json_dir.Append(cache_dir);
119
120     int num;
121     if (item->GetInteger("spinup_time", &num))
122       spinup_time_ms_ = num * 1000;
123     if (item->GetInteger("run_time", &num))
124       run_time_ms_ = num * 1000;
125
126     DictionaryValue* pixel = NULL;
127     if (item->GetDictionary("wait_pixel", &pixel)) {
128       int x, y, r, g, b;
129       ListValue* color;
130       if (pixel->GetInteger("x", &x) &&
131           pixel->GetInteger("y", &y) &&
132           pixel->GetString("op", &str) &&
133           pixel->GetList("color", &color) &&
134           color->GetInteger(0, &r) &&
135           color->GetInteger(1, &g) &&
136           color->GetInteger(2, &b)) {
137         wait_for_pixel_.reset(new WaitPixel(x, y, r, g, b, str));
138       } else {
139         LOG(ERROR) << "invalid wait_pixel args";
140         return false;
141       }
142     }
143     return true;
144   }
145
146   // Parse extra-chrome-flags for extra command line flags.
147   void ParseFlagsFromCommandLine() {
148     if (!CommandLine::ForCurrentProcess()->HasSwitch(
149         switches::kExtraChromeFlags))
150       return;
151     CommandLine::StringType flags =
152         CommandLine::ForCurrentProcess()->GetSwitchValueNative(
153             switches::kExtraChromeFlags);
154     if (MatchPattern(flags, FILE_PATH_LITERAL("*.json:*"))) {
155       CommandLine::StringType::size_type colon_pos = flags.find_last_of(':');
156       CommandLine::StringType::size_type num_pos = colon_pos + 1;
157       int index;
158       ASSERT_TRUE(base::StringToInt(
159           flags.substr(num_pos, flags.size() - num_pos), &index));
160       base::FilePath filepath(flags.substr(0, colon_pos));
161       std::string json;
162       ASSERT_TRUE(base::ReadFileToString(filepath, &json));
163       ASSERT_TRUE(ParseFlagsFromJSON(filepath.DirName(), json, index));
164     } else {
165       gurl_ = GURL(flags);
166     }
167   }
168
169   void AllowExternalDNS() {
170     net::RuleBasedHostResolverProc* resolver =
171         new net::RuleBasedHostResolverProc(host_resolver());
172     resolver->AllowDirectLookup("*");
173     host_resolver_override_.reset(
174         new net::ScopedDefaultHostResolverProc(resolver));
175   }
176
177   void ResetAllowExternalDNS() {
178     host_resolver_override_.reset();
179   }
180
181   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
182     BrowserPerfTest::SetUpCommandLine(command_line);
183     ParseFlagsFromCommandLine();
184     if (!local_cache_path_.value().empty()) {
185       // If --record-mode is already specified, don't set playback-mode.
186       if (!command_line->HasSwitch(switches::kRecordMode))
187         command_line->AppendSwitch(switches::kPlaybackMode);
188       command_line->AppendSwitchNative(switches::kDiskCacheDir,
189                                        local_cache_path_.value());
190       LOG(INFO) << local_cache_path_.value();
191     }
192     // We are measuring throughput, so we don't want any FPS throttling.
193     command_line->AppendSwitch(switches::kDisableGpuVsync);
194     command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
195     // Enable or disable GPU acceleration.
196     if (!use_gpu_) {
197       command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
198       command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
199       command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
200     }
201     if (use_compositor_thread_) {
202       ASSERT_TRUE(use_gpu_);
203       command_line->AppendSwitch(switches::kEnableThreadedCompositing);
204     } else {
205       command_line->AppendSwitch(switches::kDisableThreadedCompositing);
206     }
207   }
208
209   void Wait(int ms) {
210     base::RunLoop run_loop;
211     base::MessageLoop::current()->PostDelayedTask(
212         FROM_HERE,
213         run_loop.QuitClosure(),
214         base::TimeDelta::FromMilliseconds(ms));
215     content::RunThisRunLoop(&run_loop);
216   }
217
218   // Take snapshot of the current tab, encode it as PNG, and save to a SkBitmap.
219   bool TabSnapShotToImage(SkBitmap* bitmap) {
220     CHECK(bitmap);
221     std::vector<unsigned char> png;
222
223     gfx::Rect root_bounds = browser()->window()->GetBounds();
224     gfx::Rect tab_contents_bounds;
225     browser()->tab_strip_model()->GetActiveWebContents()->GetView()->
226         GetContainerBounds(&tab_contents_bounds);
227
228     gfx::Rect snapshot_bounds(tab_contents_bounds.x() - root_bounds.x(),
229                               tab_contents_bounds.y() - root_bounds.y(),
230                               tab_contents_bounds.width(),
231                               tab_contents_bounds.height());
232
233     gfx::NativeWindow native_window = browser()->window()->GetNativeWindow();
234     if (!chrome::GrabWindowSnapshotForUser(native_window, &png,
235                                            snapshot_bounds)) {
236       LOG(ERROR) << "browser::GrabWindowSnapShot() failed";
237       return false;
238     }
239
240     if (!gfx::PNGCodec::Decode(reinterpret_cast<unsigned char*>(&*png.begin()),
241                                png.size(), bitmap)) {
242       LOG(ERROR) << "Decode PNG to a SkBitmap failed";
243       return false;
244     }
245     return true;
246   }
247
248   // Check a pixel color every second until it passes test.
249   void WaitForPixelColor() {
250     if (wait_for_pixel_.get()) {
251       bool success = false;
252       do {
253         SkBitmap bitmap;
254         ASSERT_TRUE(TabSnapShotToImage(&bitmap));
255         success = wait_for_pixel_->IsDone(bitmap);
256         if (!success)
257           Wait(1000);
258       } while (!success);
259     }
260   }
261
262   // flags is one or more of RunTestFlags OR'd together.
263   void RunTest(const std::string& test_name, int flags) {
264     // Set path to test html.
265     base::FilePath test_path;
266     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_path));
267     test_path = test_path.Append(FILE_PATH_LITERAL("perf"));
268     if (flags & kInternal)
269       test_path = test_path.Append(FILE_PATH_LITERAL("private"));
270     test_path = test_path.Append(FILE_PATH_LITERAL("rendering"));
271     test_path = test_path.Append(FILE_PATH_LITERAL("throughput"));
272     test_path = test_path.AppendASCII(test_name);
273     test_path = test_path.Append(FILE_PATH_LITERAL("index.html"));
274     ASSERT_TRUE(base::PathExists(test_path))
275         << "Missing test file: " << test_path.value();
276
277     gurl_ = net::FilePathToFileURL(test_path);
278     RunTestWithURL(test_name, flags);
279   }
280
281   // flags is one or more of RunTestFlags OR'd together.
282   void RunCanvasBenchTest(const std::string& test_name, int flags) {
283     // Set path to test html.
284     base::FilePath test_path;
285     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_path));
286     test_path = test_path.Append(FILE_PATH_LITERAL("perf"));
287     test_path = test_path.Append(FILE_PATH_LITERAL("canvas_bench"));
288     test_path = test_path.AppendASCII(test_name + ".html");
289     ASSERT_TRUE(base::PathExists(test_path))
290         << "Missing test file: " << test_path.value();
291
292     gurl_ = net::FilePathToFileURL(test_path);
293     RunTestWithURL(test_name, flags);
294   }
295
296   // flags is one or more of RunTestFlags OR'd together.
297   void RunTestWithURL(int flags) {
298     RunTestWithURL(gurl_.possibly_invalid_spec(), flags);
299   }
300
301   // flags is one or more of RunTestFlags OR'd together.
302   void RunTestWithURL(const std::string& test_name, int flags) {
303     using trace_analyzer::Query;
304     using trace_analyzer::TraceAnalyzer;
305     using trace_analyzer::TraceEventVector;
306
307 #if defined(OS_WIN)
308     if (use_gpu_ && (flags & kIsGpuCanvasTest) &&
309         base::win::OSInfo::GetInstance()->version() == base::win::VERSION_XP) {
310       // crbug.com/128208
311       LOG(WARNING) << "Test skipped: GPU canvas tests do not run on XP.";
312       return;
313     }
314 #endif
315
316     if (use_gpu_ && !IsGpuAvailable()) {
317       LOG(WARNING) << "Test skipped: requires gpu. Pass --enable-gpu on the "
318                       "command line if use of GPU is desired.";
319       return;
320     }
321
322     if (flags & kAllowExternalDNS)
323       AllowExternalDNS();
324
325     std::string json_events;
326     TraceEventVector events_sw, events_gpu;
327     scoped_ptr<TraceAnalyzer> analyzer;
328
329     LOG(INFO) << gurl_.possibly_invalid_spec();
330     ui_test_utils::NavigateToURLWithDisposition(
331         browser(), gurl_, CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
332     content::WaitForLoadStop(
333         browser()->tab_strip_model()->GetActiveWebContents());
334
335     // Let the test spin up.
336     LOG(INFO) << "Spinning up test...";
337     ASSERT_TRUE(tracing::BeginTracing("test_gpu"));
338     Wait(spinup_time_ms_);
339     ASSERT_TRUE(tracing::EndTracing(&json_events));
340
341     // Wait for a pixel color to change (if requested).
342     WaitForPixelColor();
343
344     // Check if GPU is rendering:
345     analyzer.reset(TraceAnalyzer::Create(json_events));
346     bool ran_on_gpu = (analyzer->FindEvents(
347         Query::EventNameIs("SwapBuffers"), &events_gpu) > 0u);
348     LOG(INFO) << "Mode: " << (ran_on_gpu ? "GPU" : "Software");
349     EXPECT_EQ(use_gpu_, ran_on_gpu);
350
351     // Let the test run for a while.
352     LOG(INFO) << "Running test...";
353     ASSERT_TRUE(tracing::BeginTracing("test_fps"));
354     Wait(run_time_ms_);
355     ASSERT_TRUE(tracing::EndTracing(&json_events));
356
357     // Search for frame ticks. We look for both SW and GPU frame ticks so that
358     // the test can verify that only one or the other are found.
359     analyzer.reset(TraceAnalyzer::Create(json_events));
360     Query query_sw = Query::EventNameIs("TestFrameTickSW");
361     Query query_gpu = Query::EventNameIs("TestFrameTickGPU");
362     analyzer->FindEvents(query_sw, &events_sw);
363     analyzer->FindEvents(query_gpu, &events_gpu);
364     TraceEventVector* frames = NULL;
365     if (use_gpu_) {
366       frames = &events_gpu;
367       EXPECT_EQ(0u, events_sw.size());
368     } else {
369       frames = &events_sw;
370       EXPECT_EQ(0u, events_gpu.size());
371     }
372     if (!(flags & kIsFlaky)) {
373       ASSERT_GT(frames->size(), 20u);
374     }
375     // Cull a few leading and trailing events as they might be unreliable.
376     TraceEventVector rate_events(frames->begin() + kIgnoreSomeFrames,
377                                  frames->end() - kIgnoreSomeFrames);
378     trace_analyzer::RateStats stats;
379     ASSERT_TRUE(GetRateStats(rate_events, &stats, NULL));
380     LOG(INFO) << "FPS = " << 1000000.0 / stats.mean_us;
381
382     // Print perf results.
383     double mean_ms = stats.mean_us / 1000.0;
384     double std_dev_ms = stats.standard_deviation_us / 1000.0;
385     std::string trace_name = use_compositor_thread_? "gpu_thread" :
386                              ran_on_gpu ? "gpu" : "software";
387     std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
388                                                     std_dev_ms);
389     perf_test::PrintResultMeanAndError(test_name,
390                                        std::string(),
391                                        trace_name,
392                                        mean_and_error,
393                                        "frame_time",
394                                        true);
395
396     if (flags & kAllowExternalDNS)
397       ResetAllowExternalDNS();
398
399     // Close the tab so that we can quit without timing out during the
400     // wait-for-idle stage in browser_test framework.
401     browser()->tab_strip_model()->GetActiveWebContents()->Close();
402   }
403
404  private:
405   // WaitPixel checks a color against the color at the given pixel coordinates
406   // of an SkBitmap.
407   class WaitPixel {
408    enum Operator {
409      EQUAL,
410      NOT_EQUAL
411    };
412    public:
413     WaitPixel(int x, int y, int r, int g, int b, const std::string& op) :
414         x_(x), y_(y), r_(r), g_(g), b_(b) {
415       if (op == "!=")
416         op_ = EQUAL;
417       else if (op == "==")
418         op_ = NOT_EQUAL;
419       else
420         CHECK(false) << "op value \"" << op << "\" is not supported";
421     }
422     bool IsDone(const SkBitmap& bitmap) {
423       SkColor color = bitmap.getColor(x_, y_);
424       int r = SkColorGetR(color);
425       int g = SkColorGetG(color);
426       int b = SkColorGetB(color);
427       LOG(INFO) << "color("  << x_ << "," << y_ << "): " <<
428                    r << "," << g << "," << b;
429       switch (op_) {
430         case EQUAL:
431           return r != r_ || g != g_ || b != b_;
432         case NOT_EQUAL:
433           return r == r_ && g == g_ && b == b_;
434         default:
435           return false;
436       }
437     }
438    private:
439     int x_;
440     int y_;
441     int r_;
442     int g_;
443     int b_;
444     Operator op_;
445   };
446
447   bool use_gpu_;
448   bool use_compositor_thread_;
449   int spinup_time_ms_;
450   int run_time_ms_;
451   base::FilePath local_cache_path_;
452   GURL gurl_;
453   scoped_ptr<net::ScopedDefaultHostResolverProc> host_resolver_override_;
454   scoped_ptr<WaitPixel> wait_for_pixel_;
455 };
456
457 // For running tests on GPU:
458 class ThroughputTestGPU : public ThroughputTest {
459  public:
460   ThroughputTestGPU() : ThroughputTest(kGPU) {}
461 };
462
463 // For running tests on GPU with the compositor thread:
464 class ThroughputTestThread : public ThroughputTest {
465  public:
466   ThroughputTestThread() : ThroughputTest(kGPU | kCompositorThread) {}
467 };
468
469 // For running tests on Software:
470 class ThroughputTestSW : public ThroughputTest {
471  public:
472   ThroughputTestSW() : ThroughputTest(kSW) {}
473 };
474
475 ////////////////////////////////////////////////////////////////////////////////
476 /// Tests
477
478 #if defined(OS_WIN) && defined(USE_AURA)
479 // crbug.com/292897
480 #define MAYBE(x) DISABLED_ ## x
481 #else
482 #define MAYBE(x) x
483 #endif
484
485 // Run this test with a URL on the command line:
486 // performance_browser_tests --gtest_also_run_disabled_tests --enable-gpu
487 //     --gtest_filter=ThroughputTest*URL --extra-chrome-flags=http://...
488 // or, specify a json file with a list of tests, and the index of the test:
489 //     --extra-chrome-flags=path/to/tests.json:0
490 // The json format is an array of tests, for example:
491 // [
492 // {"url":"http://...",
493 //  "spinup_time":5,
494 //  "run_time":10,
495 //  "local_path":"path/to/disk-cache-dir",
496 //  "wait_pixel":{"x":10,"y":10,"op":"!=","color":[24,24,24]}},
497 // {"url":"http://..."}
498 // ]
499 // The only required argument is url. If local_path is set, the test goes into
500 // playback-mode and only loads files from the specified cache. If wait_pixel is
501 // specified, then after spinup_time the test waits for the color at the
502 // specified pixel coordinate to match the given color with the given operator.
503 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_TestURL) {
504   RunTestWithURL(kAllowExternalDNS);
505 }
506
507 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DISABLED_TestURL) {
508   RunTestWithURL(kAllowExternalDNS);
509 }
510
511 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(Particles)) {
512   RunTest("particles", kInternal);
513 }
514
515 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, MAYBE(Particles)) {
516   RunTest("particles", kInternal);
517 }
518
519 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(CanvasDemoSW)) {
520   RunTest("canvas-demo", kInternal);
521 }
522
523 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasDemoGPU)) {
524   RunTest("canvas-demo", kInternal | kIsGpuCanvasTest);
525 }
526
527 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, MAYBE(CanvasDemoGPU)) {
528   RunTest("canvas-demo", kInternal | kIsGpuCanvasTest);
529 }
530
531 // CompositingHugeDivSW timed out on Mac Intel Release GPU bot
532 // See crbug.com/114781
533 // Stopped producing results in SW: crbug.com/127621
534 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_CompositingHugeDivSW) {
535   RunTest("compositing_huge_div", kNone);
536 }
537
538 // Failing with insufficient frames: crbug.com/127595
539 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DISABLED_CompositingHugeDivGPU) {
540   RunTest("compositing_huge_div", kNone);
541 }
542
543 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(DrawImageShadowSW)) {
544   RunTest("canvas2d_balls_with_shadow", kNone);
545 }
546
547 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(DrawImageShadowGPU)) {
548   // TODO(junov): Fix test flakiness crbug.com/272383
549   RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
550 }
551
552 // Intermittent failure, should be fixed by converting to telemetry.
553 // See crbug.com/276500 for more details.
554 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, DISABLED_DrawImageShadowGPU) {
555   // TODO(junov): Fix test flakiness crbug.com/272383
556   RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
557 }
558
559 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(CanvasToCanvasDrawSW)) {
560   if (IsGpuAvailable() &&
561       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
562     return;
563   RunTest("canvas2d_balls_draw_from_canvas", kNone);
564 }
565
566 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasToCanvasDrawGPU)) {
567   if (IsGpuAvailable() &&
568       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
569     return;
570   RunTest("canvas2d_balls_draw_from_canvas", kNone | kIsGpuCanvasTest);
571 }
572
573 // Failing on windows GPU bots: crbug.com/255192
574 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_CanvasTextSW) {
575   if (IsGpuAvailable() &&
576       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
577     return;
578   RunTest("canvas2d_balls_text", kNone);
579 }
580
581 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasTextGPU)) {
582   RunTest("canvas2d_balls_text", kNone | kIsGpuCanvasTest);
583 }
584
585 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(CanvasFillPathSW)) {
586   RunTest("canvas2d_balls_fill_path", kNone);
587 }
588
589 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasFillPathGPU)) {
590   RunTest("canvas2d_balls_fill_path", kNone | kIsGpuCanvasTest);
591 }
592
593 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(CanvasSingleImageSW)) {
594   RunCanvasBenchTest("single_image", kNone);
595 }
596
597 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasSingleImageGPU)) {
598   if (IsGpuAvailable() &&
599       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
600     return;
601   RunCanvasBenchTest("single_image", kNone | kIsGpuCanvasTest);
602 }
603
604 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, MAYBE(CanvasManyImagesSW)) {
605   RunCanvasBenchTest("many_images", kNone);
606 }
607
608 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, MAYBE(CanvasManyImagesGPU)) {
609   RunCanvasBenchTest("many_images", kNone | kIsGpuCanvasTest);
610 }
611
612 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, MAYBE(CanvasManyImagesGPU)) {
613   RunCanvasBenchTest("many_images", kNone | kIsGpuCanvasTest);
614 }
615
616 }  // namespace