• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/debug/alias.h"
10 #include "base/rand_util.h"
11 #include "base/stl_util.h"
12 #include "base/task_scheduler/post_task.h"
13 #include "base/task_scheduler/task_scheduler.h"
14 #include "base/task_scheduler/task_tracker.h"
15 #include "base/task_scheduler/task_traits.h"
16 #include "build/build_config.h"
17 
18 namespace base {
19 namespace internal {
20 
21 namespace {
22 
23 TimeDelta g_heartbeat_for_testing = TimeDelta();
24 
25 }  // namespace
26 
ServiceThread(const TaskTracker * task_tracker)27 ServiceThread::ServiceThread(const TaskTracker* task_tracker)
28     : Thread("TaskSchedulerServiceThread"), task_tracker_(task_tracker) {}
29 
30 // static
SetHeartbeatIntervalForTesting(TimeDelta heartbeat)31 void ServiceThread::SetHeartbeatIntervalForTesting(TimeDelta heartbeat) {
32   g_heartbeat_for_testing = heartbeat;
33 }
34 
Init()35 void ServiceThread::Init() {
36   // In unit tests we sometimes do not have a fully functional TaskScheduler
37   // environment, do not perform the heartbeat report in that case since it
38   // relies on such an environment.
39   if (task_tracker_ && TaskScheduler::GetInstance()) {
40 // Seemingly causing power regression on Android, disable to see if truly at
41 // fault : https://crbug.com/848255
42 #if !defined(OS_ANDROID)
43     // Compute the histogram every hour (with a slight offset to drift if that
44     // hour tick happens to line up with specific events). Once per hour per
45     // user was deemed sufficient to gather a reliable metric.
46     constexpr TimeDelta kHeartbeat = TimeDelta::FromMinutes(59);
47 
48     heartbeat_latency_timer_.Start(
49         FROM_HERE,
50         g_heartbeat_for_testing.is_zero() ? kHeartbeat
51                                           : g_heartbeat_for_testing,
52         BindRepeating(&ServiceThread::PerformHeartbeatLatencyReport,
53                       Unretained(this)));
54 #endif
55   }
56 }
57 
Run(RunLoop * run_loop)58 NOINLINE void ServiceThread::Run(RunLoop* run_loop) {
59   const int line_number = __LINE__;
60   Thread::Run(run_loop);
61   base::debug::Alias(&line_number);
62 }
63 
PerformHeartbeatLatencyReport() const64 void ServiceThread::PerformHeartbeatLatencyReport() const {
65   static constexpr TaskTraits kReportedTraits[] = {
66       {TaskPriority::BACKGROUND},    {TaskPriority::BACKGROUND, MayBlock()},
67       {TaskPriority::USER_VISIBLE},  {TaskPriority::USER_VISIBLE, MayBlock()},
68       {TaskPriority::USER_BLOCKING}, {TaskPriority::USER_BLOCKING, MayBlock()}};
69 
70   // Only record latency for one set of TaskTraits per report to avoid bias in
71   // the order in which tasks are posted (should we record all at once) as well
72   // as to avoid spinning up many worker threads to process this report if the
73   // scheduler is currently idle (each pool keeps at least one idle thread so a
74   // single task isn't an issue).
75 
76   // Invoke RandInt() out-of-line to ensure it's obtained before
77   // TimeTicks::Now().
78   const TaskTraits& profiled_traits =
79       kReportedTraits[RandInt(0, base::size(kReportedTraits) - 1)];
80 
81   // Post through the static API to time the full stack. Use a new Now() for
82   // every set of traits in case PostTaskWithTraits() itself is slow.
83   // Bonus: this appraoch also includes the overhead of Bind() in the reported
84   // latency).
85   base::PostTaskWithTraits(
86       FROM_HERE, profiled_traits,
87       BindOnce(&TaskTracker::RecordLatencyHistogram, Unretained(task_tracker_),
88                TaskTracker::LatencyHistogramType::HEARTBEAT_LATENCY,
89                profiled_traits, TimeTicks::Now()));
90 }
91 
92 }  // namespace internal
93 }  // namespace base
94