1 // Copyright 2018 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/task_scheduler/service_thread.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/debug/stack_trace.h"
11 #include "base/task_scheduler/task_scheduler.h"
12 #include "base/task_scheduler/task_scheduler_impl.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/time/time.h"
16 #include "build/build_config.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace base {
20 namespace internal {
21 
22 namespace {
23 
24 // Verifies that |query| is found on the current stack. Ignores failures if this
25 // configuration doesn't have symbols.
VerifyHasStringOnStack(const std::string & query)26 void VerifyHasStringOnStack(const std::string& query) {
27   const std::string stack = debug::StackTrace().ToString();
28   SCOPED_TRACE(stack);
29   const bool found_on_stack = stack.find(query) != std::string::npos;
30   const bool stack_has_symbols =
31       stack.find("SchedulerWorker") != std::string::npos;
32   EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query;
33 }
34 
35 }  // namespace
36 
37 #if defined(OS_POSIX)
38 // Many POSIX bots flakily crash on |debug::StackTrace().ToString()|,
39 // https://crbug.com/840429.
40 #define MAYBE_StackHasIdentifyingFrame DISABLED_StackHasIdentifyingFrame
41 #else
42 #define MAYBE_StackHasIdentifyingFrame StackHasIdentifyingFrame
43 #endif
44 
TEST(TaskSchedulerServiceThreadTest,MAYBE_StackHasIdentifyingFrame)45 TEST(TaskSchedulerServiceThreadTest, MAYBE_StackHasIdentifyingFrame) {
46   ServiceThread service_thread(nullptr);
47   service_thread.Start();
48 
49   service_thread.task_runner()->PostTask(
50       FROM_HERE, BindOnce(&VerifyHasStringOnStack, "ServiceThread"));
51 
52   service_thread.FlushForTesting();
53 }
54 
55 #if defined(OS_ANDROID)
56 // The heartbeat latency report has been temporarily disabled on Android per
57 // https://crbug.com/848255.
58 #define MAYBE_HeartbeatLatencyReport DISABLED_HeartbeatLatencyReport
59 #else
60 #define MAYBE_HeartbeatLatencyReport HeartbeatLatencyReport
61 #endif
62 
63 // Integration test verifying that a service thread running in a fully
64 // integrated TaskScheduler environment results in reporting
65 // HeartbeatLatencyMicroseconds metrics.
TEST(TaskSchedulerServiceThreadIntegrationTest,MAYBE_HeartbeatLatencyReport)66 TEST(TaskSchedulerServiceThreadIntegrationTest, MAYBE_HeartbeatLatencyReport) {
67   ServiceThread::SetHeartbeatIntervalForTesting(TimeDelta::FromMilliseconds(1));
68 
69   TaskScheduler::SetInstance(
70       std::make_unique<internal::TaskSchedulerImpl>("Test"));
71   TaskScheduler::GetInstance()->StartWithDefaultParams();
72 
73   static constexpr const char* kExpectedMetrics[] = {
74       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
75       "UserBlockingTaskPriority",
76       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
77       "UserBlockingTaskPriority_MayBlock",
78       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
79       "UserVisibleTaskPriority",
80       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
81       "UserVisibleTaskPriority_MayBlock",
82       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
83       "BackgroundTaskPriority",
84       "TaskScheduler.HeartbeatLatencyMicroseconds.Test."
85       "BackgroundTaskPriority_MayBlock"};
86 
87   // Each report hits a single histogram above (randomly selected). But 1000
88   // reports should touch all histograms at least once the vast majority of the
89   // time.
90   constexpr TimeDelta kReasonableTimeout = TimeDelta::FromSeconds(1);
91   constexpr TimeDelta kBusyWaitTime = TimeDelta::FromMilliseconds(100);
92 
93   const TimeTicks start_time = TimeTicks::Now();
94 
95   HistogramTester tester;
96   for (const char* expected_metric : kExpectedMetrics) {
97     while (tester.GetAllSamples(expected_metric).empty()) {
98       if (TimeTicks::Now() - start_time > kReasonableTimeout)
99         LOG(WARNING) << "Waiting a while for " << expected_metric;
100       PlatformThread::Sleep(kBusyWaitTime);
101     }
102   }
103 
104   TaskScheduler::GetInstance()->JoinForTesting();
105   TaskScheduler::SetInstance(nullptr);
106 
107   ServiceThread::SetHeartbeatIntervalForTesting(TimeDelta());
108 }
109 
110 }  // namespace internal
111 }  // namespace base
112