Home | History | Annotate | Download | only in rendering
      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 "third_party/skia/include/core/SkBitmap.h"
     38 #include "third_party/skia/include/core/SkColor.h"
     39 #include "ui/gfx/codec/png_codec.h"
     40 #include "ui/gl/gl_switches.h"
     41 #include "url/gurl.h"
     42 
     43 #if defined(OS_WIN)
     44 #include "base/win/windows_version.h"
     45 #endif
     46 
     47 namespace {
     48 
     49 enum RunTestFlags {
     50   kNone = 0,
     51   kInternal = 1 << 0,         // Test uses internal test data.
     52   kAllowExternalDNS = 1 << 1, // Test needs external DNS lookup.
     53   kIsGpuCanvasTest = 1 << 2   // Test uses GPU accelerated canvas features.
     54 };
     55 
     56 enum ThroughputTestFlags {
     57   kSW = 0,
     58   kGPU = 1 << 0,
     59   kCompositorThread = 1 << 1
     60 };
     61 
     62 const int kSpinUpTimeMs = 4 * 1000;
     63 const int kRunTimeMs = 10 * 1000;
     64 const int kIgnoreSomeFrames = 3;
     65 
     66 class ThroughputTest : public BrowserPerfTest {
     67  public:
     68   explicit ThroughputTest(int flags) :
     69       use_gpu_(flags & kGPU),
     70       use_compositor_thread_(flags & kCompositorThread),
     71       spinup_time_ms_(kSpinUpTimeMs),
     72       run_time_ms_(kRunTimeMs) {}
     73 
     74   // This indicates running on GPU bots, not necessarily using the GPU.
     75   bool IsGpuAvailable() const {
     76     return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
     77   }
     78 
     79   // Parse flags from JSON to control the test behavior.
     80   bool ParseFlagsFromJSON(const base::FilePath& json_dir,
     81                           const std::string& json,
     82                           int index) {
     83     scoped_ptr<base::Value> root;
     84     root.reset(base::JSONReader::Read(json));
     85 
     86     ListValue* root_list = NULL;
     87     if (!root.get() || !root->GetAsList(&root_list)) {
     88       LOG(ERROR) << "JSON missing root list element";
     89       return false;
     90     }
     91 
     92     DictionaryValue* item = NULL;
     93     if (!root_list->GetDictionary(index, &item)) {
     94       LOG(ERROR) << "index " << index << " not found in JSON";
     95       return false;
     96     }
     97 
     98     std::string str;
     99     if (item->GetStringASCII("url", &str)) {
    100       gurl_ = GURL(str);
    101     } else if (item->GetStringASCII("file", &str)) {
    102       base::FilePath empty;
    103       gurl_ = URLFixerUpper::FixupRelativeFile(empty, empty.AppendASCII(str));
    104     } else {
    105       LOG(ERROR) << "missing url or file";
    106       return false;
    107     }
    108 
    109     if (!gurl_.is_valid()) {
    110       LOG(ERROR) << "invalid url: " << gurl_.possibly_invalid_spec();
    111       return false;
    112     }
    113 
    114     base::FilePath::StringType cache_dir;
    115     if (item->GetString("local_path", &cache_dir))
    116       local_cache_path_ = json_dir.Append(cache_dir);
    117 
    118     int num;
    119     if (item->GetInteger("spinup_time", &num))
    120       spinup_time_ms_ = num * 1000;
    121     if (item->GetInteger("run_time", &num))
    122       run_time_ms_ = num * 1000;
    123 
    124     DictionaryValue* pixel = NULL;
    125     if (item->GetDictionary("wait_pixel", &pixel)) {
    126       int x, y, r, g, b;
    127       ListValue* color;
    128       if (pixel->GetInteger("x", &x) &&
    129           pixel->GetInteger("y", &y) &&
    130           pixel->GetString("op", &str) &&
    131           pixel->GetList("color", &color) &&
    132           color->GetInteger(0, &r) &&
    133           color->GetInteger(1, &g) &&
    134           color->GetInteger(2, &b)) {
    135         wait_for_pixel_.reset(new WaitPixel(x, y, r, g, b, str));
    136       } else {
    137         LOG(ERROR) << "invalid wait_pixel args";
    138         return false;
    139       }
    140     }
    141     return true;
    142   }
    143 
    144   // Parse extra-chrome-flags for extra command line flags.
    145   void ParseFlagsFromCommandLine() {
    146     if (!CommandLine::ForCurrentProcess()->HasSwitch(
    147         switches::kExtraChromeFlags))
    148       return;
    149     CommandLine::StringType flags =
    150         CommandLine::ForCurrentProcess()->GetSwitchValueNative(
    151             switches::kExtraChromeFlags);
    152     if (MatchPattern(flags, FILE_PATH_LITERAL("*.json:*"))) {
    153       CommandLine::StringType::size_type colon_pos = flags.find_last_of(':');
    154       CommandLine::StringType::size_type num_pos = colon_pos + 1;
    155       int index;
    156       ASSERT_TRUE(base::StringToInt(
    157           flags.substr(num_pos, flags.size() - num_pos), &index));
    158       base::FilePath filepath(flags.substr(0, colon_pos));
    159       std::string json;
    160       ASSERT_TRUE(file_util::ReadFileToString(filepath, &json));
    161       ASSERT_TRUE(ParseFlagsFromJSON(filepath.DirName(), json, index));
    162     } else {
    163       gurl_ = GURL(flags);
    164     }
    165   }
    166 
    167   void AllowExternalDNS() {
    168     net::RuleBasedHostResolverProc* resolver =
    169         new net::RuleBasedHostResolverProc(host_resolver());
    170     resolver->AllowDirectLookup("*");
    171     host_resolver_override_.reset(
    172         new net::ScopedDefaultHostResolverProc(resolver));
    173   }
    174 
    175   void ResetAllowExternalDNS() {
    176     host_resolver_override_.reset();
    177   }
    178 
    179   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    180     BrowserPerfTest::SetUpCommandLine(command_line);
    181     ParseFlagsFromCommandLine();
    182     if (!local_cache_path_.value().empty()) {
    183       // If --record-mode is already specified, don't set playback-mode.
    184       if (!command_line->HasSwitch(switches::kRecordMode))
    185         command_line->AppendSwitch(switches::kPlaybackMode);
    186       command_line->AppendSwitchNative(switches::kDiskCacheDir,
    187                                        local_cache_path_.value());
    188       LOG(INFO) << local_cache_path_.value();
    189     }
    190     // We are measuring throughput, so we don't want any FPS throttling.
    191     command_line->AppendSwitch(switches::kDisableGpuVsync);
    192     command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
    193     // Enable or disable GPU acceleration.
    194     if (use_gpu_) {
    195       command_line->AppendSwitch(switches::kForceCompositingMode);
    196     } else {
    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     ASSERT_GT(frames->size(), 20u);
    373     // Cull a few leading and trailing events as they might be unreliable.
    374     TraceEventVector rate_events(frames->begin() + kIgnoreSomeFrames,
    375                                  frames->end() - kIgnoreSomeFrames);
    376     trace_analyzer::RateStats stats;
    377     ASSERT_TRUE(GetRateStats(rate_events, &stats, NULL));
    378     LOG(INFO) << "FPS = " << 1000000.0 / stats.mean_us;
    379 
    380     // Print perf results.
    381     double mean_ms = stats.mean_us / 1000.0;
    382     double std_dev_ms = stats.standard_deviation_us / 1000.0 / 1000.0;
    383     std::string trace_name = use_compositor_thread_? "gpu_thread" :
    384                              ran_on_gpu ? "gpu" : "software";
    385     std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
    386                                                     std_dev_ms);
    387     perf_test::PrintResultMeanAndError(test_name,
    388                                        std::string(),
    389                                        trace_name,
    390                                        mean_and_error,
    391                                        "frame_time",
    392                                        true);
    393 
    394     if (flags & kAllowExternalDNS)
    395       ResetAllowExternalDNS();
    396 
    397     // Close the tab so that we can quit without timing out during the
    398     // wait-for-idle stage in browser_test framework.
    399     browser()->tab_strip_model()->GetActiveWebContents()->Close();
    400   }
    401 
    402  private:
    403   // WaitPixel checks a color against the color at the given pixel coordinates
    404   // of an SkBitmap.
    405   class WaitPixel {
    406    enum Operator {
    407      EQUAL,
    408      NOT_EQUAL
    409    };
    410    public:
    411     WaitPixel(int x, int y, int r, int g, int b, const std::string& op) :
    412         x_(x), y_(y), r_(r), g_(g), b_(b) {
    413       if (op == "!=")
    414         op_ = EQUAL;
    415       else if (op == "==")
    416         op_ = NOT_EQUAL;
    417       else
    418         CHECK(false) << "op value \"" << op << "\" is not supported";
    419     }
    420     bool IsDone(const SkBitmap& bitmap) {
    421       SkColor color = bitmap.getColor(x_, y_);
    422       int r = SkColorGetR(color);
    423       int g = SkColorGetG(color);
    424       int b = SkColorGetB(color);
    425       LOG(INFO) << "color("  << x_ << "," << y_ << "): " <<
    426                    r << "," << g << "," << b;
    427       switch (op_) {
    428         case EQUAL:
    429           return r != r_ || g != g_ || b != b_;
    430         case NOT_EQUAL:
    431           return r == r_ && g == g_ && b == b_;
    432         default:
    433           return false;
    434       }
    435     }
    436    private:
    437     int x_;
    438     int y_;
    439     int r_;
    440     int g_;
    441     int b_;
    442     Operator op_;
    443   };
    444 
    445   bool use_gpu_;
    446   bool use_compositor_thread_;
    447   int spinup_time_ms_;
    448   int run_time_ms_;
    449   base::FilePath local_cache_path_;
    450   GURL gurl_;
    451   scoped_ptr<net::ScopedDefaultHostResolverProc> host_resolver_override_;
    452   scoped_ptr<WaitPixel> wait_for_pixel_;
    453 };
    454 
    455 // For running tests on GPU:
    456 class ThroughputTestGPU : public ThroughputTest {
    457  public:
    458   ThroughputTestGPU() : ThroughputTest(kGPU) {}
    459 };
    460 
    461 // For running tests on GPU with the compositor thread:
    462 class ThroughputTestThread : public ThroughputTest {
    463  public:
    464   ThroughputTestThread() : ThroughputTest(kGPU | kCompositorThread) {}
    465 };
    466 
    467 // For running tests on Software:
    468 class ThroughputTestSW : public ThroughputTest {
    469  public:
    470   ThroughputTestSW() : ThroughputTest(kSW) {}
    471 };
    472 
    473 ////////////////////////////////////////////////////////////////////////////////
    474 /// Tests
    475 
    476 // Run this test with a URL on the command line:
    477 // performance_browser_tests --gtest_also_run_disabled_tests --enable-gpu
    478 //     --gtest_filter=ThroughputTest*URL --extra-chrome-flags=http://...
    479 // or, specify a json file with a list of tests, and the index of the test:
    480 //     --extra-chrome-flags=path/to/tests.json:0
    481 // The json format is an array of tests, for example:
    482 // [
    483 // {"url":"http://...",
    484 //  "spinup_time":5,
    485 //  "run_time":10,
    486 //  "local_path":"path/to/disk-cache-dir",
    487 //  "wait_pixel":{"x":10,"y":10,"op":"!=","color":[24,24,24]}},
    488 // {"url":"http://..."}
    489 // ]
    490 // The only required argument is url. If local_path is set, the test goes into
    491 // playback-mode and only loads files from the specified cache. If wait_pixel is
    492 // specified, then after spinup_time the test waits for the color at the
    493 // specified pixel coordinate to match the given color with the given operator.
    494 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_TestURL) {
    495   RunTestWithURL(kAllowExternalDNS);
    496 }
    497 
    498 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DISABLED_TestURL) {
    499   RunTestWithURL(kAllowExternalDNS);
    500 }
    501 
    502 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, Particles) {
    503   RunTest("particles", kInternal);
    504 }
    505 
    506 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, Particles) {
    507   RunTest("particles", kInternal);
    508 }
    509 
    510 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasDemoSW) {
    511   RunTest("canvas-demo", kInternal);
    512 }
    513 
    514 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasDemoGPU) {
    515   RunTest("canvas-demo", kInternal | kIsGpuCanvasTest);
    516 }
    517 
    518 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, CanvasDemoGPU) {
    519   RunTest("canvas-demo", kInternal | kIsGpuCanvasTest);
    520 }
    521 
    522 // CompositingHugeDivSW timed out on Mac Intel Release GPU bot
    523 // See crbug.com/114781
    524 // Stopped producing results in SW: crbug.com/127621
    525 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_CompositingHugeDivSW) {
    526   RunTest("compositing_huge_div", kNone);
    527 }
    528 
    529 // Failing with insufficient frames: crbug.com/127595
    530 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DISABLED_CompositingHugeDivGPU) {
    531   RunTest("compositing_huge_div", kNone);
    532 }
    533 
    534 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DrawImageShadowSW) {
    535   RunTest("canvas2d_balls_with_shadow", kNone);
    536 }
    537 
    538 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DrawImageShadowGPU) {
    539   RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest);
    540 }
    541 
    542 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, DrawImageShadowGPU) {
    543   RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest);
    544 }
    545 
    546 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasToCanvasDrawSW) {
    547   if (IsGpuAvailable() &&
    548       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
    549     return;
    550   RunTest("canvas2d_balls_draw_from_canvas", kNone);
    551 }
    552 
    553 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasToCanvasDrawGPU) {
    554   if (IsGpuAvailable() &&
    555       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
    556     return;
    557   RunTest("canvas2d_balls_draw_from_canvas", kNone | kIsGpuCanvasTest);
    558 }
    559 
    560 // Failing on windows GPU bots: crbug.com/255192
    561 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, DISABLED_CanvasTextSW) {
    562   if (IsGpuAvailable() &&
    563       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
    564     return;
    565   RunTest("canvas2d_balls_text", kNone);
    566 }
    567 
    568 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasTextGPU) {
    569   RunTest("canvas2d_balls_text", kNone | kIsGpuCanvasTest);
    570 }
    571 
    572 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasFillPathSW) {
    573   RunTest("canvas2d_balls_fill_path", kNone);
    574 }
    575 
    576 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasFillPathGPU) {
    577   RunTest("canvas2d_balls_fill_path", kNone | kIsGpuCanvasTest);
    578 }
    579 
    580 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasSingleImageSW) {
    581   RunCanvasBenchTest("single_image", kNone);
    582 }
    583 
    584 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasSingleImageGPU) {
    585   if (IsGpuAvailable() &&
    586       gpu::GPUTestBotConfig::CurrentConfigMatches("MAC AMD"))
    587     return;
    588   RunCanvasBenchTest("single_image", kNone | kIsGpuCanvasTest);
    589 }
    590 
    591 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasManyImagesSW) {
    592   RunCanvasBenchTest("many_images", kNone);
    593 }
    594 
    595 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, CanvasManyImagesGPU) {
    596   RunCanvasBenchTest("many_images", kNone | kIsGpuCanvasTest);
    597 }
    598 
    599 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, CanvasManyImagesGPU) {
    600   RunCanvasBenchTest("many_images", kNone | kIsGpuCanvasTest);
    601 }
    602 
    603 }  // namespace
    604