chromium/gpu/ipc/service/gpu_watchdog_thread_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/ipc/service/gpu_watchdog_thread.h"

#include <memory>
#include <string>

#include "base/test/task_environment.h"

#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_source.h"
#include "base/system/sys_info.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/power_monitor_test.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif

namespace gpu {

namespace {
// |kExtraGPUJobTimeForTesting| is the extra time the gpu main/test thread
// spends after GpuWatchdogTimeout. Theoretically, any extra time such as 1 ms
// should be enough to trigger the watchdog kill. However, it can cause test
// flakiness when the time is too short.

constexpr auto kGpuWatchdogTimeoutForTesting =;
constexpr auto kExtraGPUJobTimeForTesting =;

// For slow machines like Win 7, Mac 10.xx and Android L/M/N.
[[maybe_unused]] constexpr auto kGpuWatchdogTimeoutForTestingSlow =;
[[maybe_unused]] constexpr auto kExtraGPUJobTimeForTestingSlow =;

// For Fuchsia in which GpuWatchdogTest.GpuInitializationAndRunningTasks test
// is flaky.
[[maybe_unused]] constexpr auto kGpuWatchdogTimeoutForTestingSlowest =;
[[maybe_unused]] constexpr auto kExtraGPUJobTimeForTestingSlowest =;

// On Windows, the gpu watchdog check if the main thread has used the full
// thread time. We want to detect the case in which the main thread is swapped
// out by the OS scheduler. The task on windows is simiulated by reading
// TimeTicks instead of Sleep().
void SimpleTask(base::TimeDelta duration, base::TimeDelta extra_time) {}
}  // namespace

class GpuWatchdogTest : public testing::Test {};

class GpuWatchdogPowerTest : public GpuWatchdogTest {};

void GpuWatchdogTest::SetUp() {}

void GpuWatchdogPowerTest::SetUp() {}

void GpuWatchdogPowerTest::TearDown() {}

// This task will run for duration_ms milliseconds. It will also call watchdog
// ReportProgress() every report_delta_ms milliseconds.
void GpuWatchdogTest::LongTaskWithReportProgress(base::TimeDelta duration,
                                                 base::TimeDelta report_delta) {}

#if BUILDFLAG(IS_ANDROID)
void GpuWatchdogTest::LongTaskFromBackgroundToForeground(
    base::TimeDelta duration,
    base::TimeDelta extra_time,
    base::TimeDelta time_to_switch_to_foreground) {
  // Chrome is running in the background first.
  watchdog_thread_->OnBackgrounded();
  SimpleTask(time_to_switch_to_foreground, /*extra_time=*/base::TimeDelta());
  // Now switch Chrome to the foreground after the specified time
  watchdog_thread_->OnForegrounded();
  SimpleTask(duration, extra_time);
}
#endif

void GpuWatchdogPowerTest::LongTaskOnResume(
    base::TimeDelta duration,
    base::TimeDelta extra_time,
    base::TimeDelta time_to_power_resume) {}

// Normal GPU Initialization.
TEST_F(GpuWatchdogTest, GpuInitializationComplete) {}

// GPU Hang In Initialization.
TEST_F(GpuWatchdogTest, GpuInitializationHang) {}

// Normal GPU Initialization and Running Task.
TEST_F(GpuWatchdogTest, GpuInitializationAndRunningTasks) {}

// GPU Hang when running a task.
TEST_F(GpuWatchdogTest, GpuRunningATaskHang) {}

#if BUILDFLAG(IS_ANDROID)
TEST_F(GpuWatchdogTest, ChromeInBackground) {
  // Chrome starts in the background.
  watchdog_thread_->OnBackgrounded();

  // Gpu init takes longer than 6x watchdog |timeout_|. This is normal since
  // Chrome is running in the background.
  auto normal_long_task_time = timeout_ * 6;
  SimpleTask(normal_long_task_time, /*extra_time=*/base::TimeDelta());

  // Report GPU init complete.
  watchdog_thread_->OnInitComplete();

  // Run a task that takes 6x watchdog |timeout_| longer.This is normal since
  // Chrome is running in the background.
  task_environment_.GetMainThreadTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&SimpleTask, normal_long_task_time,
                                /*extra_time=*/base::TimeDelta()));
  task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
                                                        run_loop.QuitClosure());
  run_loop.Run();

  // The gpu might be slow when running in the background. This is ok.
  bool result = watchdog_thread_->IsGpuHangDetectedForTesting();
  EXPECT_FALSE(result);
}

TEST_F(GpuWatchdogTest, GpuSwitchingToForegroundHang) {
  // Report GPU init complete.
  watchdog_thread_->OnInitComplete();

  // A task stays in the background for watchdog |timeout_| then switches to the
  // foreground and runs longer than the first-time foreground watchdog timeout
  // allowed.
  auto allowed_time = timeout_ * (kRestartFactor + 1);
  task_environment_.GetMainThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&GpuWatchdogTest::LongTaskFromBackgroundToForeground,
                     base::Unretained(this), /*duration*/ allowed_time,
                     /*extra_time=*/extra_gpu_job_time_,
                     /*time_to_switch_to_foreground*/ timeout_ / 4));

  task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
                                                        run_loop.QuitClosure());
  run_loop.Run();

  // It takes too long to finish a task after switching to the foreground.
  // A GPU hang should be detected.
  bool result = watchdog_thread_->IsGpuHangDetectedForTesting();
  EXPECT_TRUE(result);
}
#endif

TEST_F(GpuWatchdogTest, GpuInitializationPause) {}

TEST_F(GpuWatchdogPowerTest, GpuOnSuspend) {}

TEST_F(GpuWatchdogPowerTest, GpuOnResumeHang) {}

}  // namespace gpu