blob: 40ccddf1aea6414ce7c339ee0703dd1a16f538b9 [file] [log] [blame]
Gabriel Charette3fb9e4f2018-05-18 21:34:431// 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
Gabriel Charette52fa3ae2019-04-15 21:44:375#include "base/task/thread_pool/service_thread.h"
Gabriel Charette3fb9e4f2018-05-18 21:34:436
Gabriel Charette7e7dd552018-05-28 13:39:217#include "base/bind.h"
8#include "base/bind_helpers.h"
Gabriel Charette3fb9e4f2018-05-18 21:34:439#include "base/debug/alias.h"
Gabriel Charette7e7dd552018-05-28 13:39:2110#include "base/rand_util.h"
11#include "base/stl_util.h"
Gabriel Charette04b138f2018-08-06 00:03:2212#include "base/task/post_task.h"
Gabriel Charette04b138f2018-08-06 00:03:2213#include "base/task/task_traits.h"
Gabriel Charette52fa3ae2019-04-15 21:44:3714#include "base/task/thread_pool/task_tracker.h"
15#include "base/task/thread_pool/thread_pool.h"
Gabriel Charette3fb9e4f2018-05-18 21:34:4316
17namespace base {
18namespace internal {
19
Gabriel Charette7e7dd552018-05-28 13:39:2120namespace {
21
Gabriel Charette510d34372018-07-27 20:05:3622TimeDelta g_heartbeat_for_testing = TimeDelta();
Gabriel Charette7e7dd552018-05-28 13:39:2123
24} // namespace
25
Etienne Pierre-doray730a9392018-08-13 22:39:3126ServiceThread::ServiceThread(const TaskTracker* task_tracker,
27 RepeatingClosure report_heartbeat_metrics_callback)
Gabriel Charette52fa3ae2019-04-15 21:44:3728 : Thread("ThreadPoolServiceThread"),
Etienne Pierre-doray730a9392018-08-13 22:39:3129 task_tracker_(task_tracker),
30 report_heartbeat_metrics_callback_(
31 std::move(report_heartbeat_metrics_callback)) {}
32
33ServiceThread::~ServiceThread() = default;
Gabriel Charette3fb9e4f2018-05-18 21:34:4334
Gabriel Charette7e7dd552018-05-28 13:39:2135// static
36void ServiceThread::SetHeartbeatIntervalForTesting(TimeDelta heartbeat) {
37 g_heartbeat_for_testing = heartbeat;
38}
39
Gabriel Charette3fb9e4f2018-05-18 21:34:4340void ServiceThread::Init() {
Gabriel Charette52fa3ae2019-04-15 21:44:3741 // In unit tests we sometimes do not have a fully functional ThreadPool
Gabriel Charettebb37d4c2018-05-23 19:42:3342 // environment, do not perform the heartbeat report in that case since it
43 // relies on such an environment.
Gabriel Charette52fa3ae2019-04-15 21:44:3744 if (ThreadPool::GetInstance()) {
Gabriel Charette7e7dd552018-05-28 13:39:2145 // Compute the histogram every hour (with a slight offset to drift if that
46 // hour tick happens to line up with specific events). Once per hour per
47 // user was deemed sufficient to gather a reliable metric.
48 constexpr TimeDelta kHeartbeat = TimeDelta::FromMinutes(59);
49
Etienne Pierre-doray730a9392018-08-13 22:39:3150 heartbeat_metrics_timer_.Start(
Gabriel Charette7e7dd552018-05-28 13:39:2151 FROM_HERE,
52 g_heartbeat_for_testing.is_zero() ? kHeartbeat
53 : g_heartbeat_for_testing,
Etienne Pierre-doray730a9392018-08-13 22:39:3154 BindRepeating(&ServiceThread::ReportHeartbeatMetrics,
Gabriel Charette3fb9e4f2018-05-18 21:34:4355 Unretained(this)));
Gabriel Charette3fb9e4f2018-05-18 21:34:4356 }
57}
58
59NOINLINE void ServiceThread::Run(RunLoop* run_loop) {
60 const int line_number = __LINE__;
61 Thread::Run(run_loop);
62 base::debug::Alias(&line_number);
63}
64
Etienne Pierre-doray730a9392018-08-13 22:39:3165void ServiceThread::ReportHeartbeatMetrics() const {
66 report_heartbeat_metrics_callback_.Run();
67 PerformHeartbeatLatencyReport();
68}
69
Gabriel Charette3fb9e4f2018-05-18 21:34:4370void ServiceThread::PerformHeartbeatLatencyReport() const {
Etienne Pierre-doray730a9392018-08-13 22:39:3171 if (!task_tracker_)
72 return;
73
Gabriel Charette3fb9e4f2018-05-18 21:34:4374 static constexpr TaskTraits kReportedTraits[] = {
Gabriel Charettef042bf22018-07-27 18:01:1675 {TaskPriority::BEST_EFFORT}, {TaskPriority::BEST_EFFORT, MayBlock()},
Gabriel Charette3fb9e4f2018-05-18 21:34:4376 {TaskPriority::USER_VISIBLE}, {TaskPriority::USER_VISIBLE, MayBlock()},
77 {TaskPriority::USER_BLOCKING}, {TaskPriority::USER_BLOCKING, MayBlock()}};
78
Gabriel Charette7e7dd552018-05-28 13:39:2179 // Only record latency for one set of TaskTraits per report to avoid bias in
80 // the order in which tasks are posted (should we record all at once) as well
81 // as to avoid spinning up many worker threads to process this report if the
Gabriel Charette52fa3ae2019-04-15 21:44:3782 // thread pool is currently idle (each pool keeps at least one idle thread so
83 // a single task isn't an issue).
Gabriel Charette7e7dd552018-05-28 13:39:2184
85 // Invoke RandInt() out-of-line to ensure it's obtained before
86 // TimeTicks::Now().
87 const TaskTraits& profiled_traits =
88 kReportedTraits[RandInt(0, base::size(kReportedTraits) - 1)];
89
90 // Post through the static API to time the full stack. Use a new Now() for
91 // every set of traits in case PostTaskWithTraits() itself is slow.
92 // Bonus: this appraoch also includes the overhead of Bind() in the reported
93 // latency).
Jesse McKenna53d5e122018-09-18 16:00:4394 // TODO(jessemckenna): pass |profiled_traits| directly to
95 // RecordHeartbeatLatencyAndTasksRunWhileQueuingHistograms() once compiler
96 // error on NaCl is fixed
97 TaskPriority task_priority = profiled_traits.priority();
98 bool may_block = profiled_traits.may_block();
Gabriel Charette7e7dd552018-05-28 13:39:2199 base::PostTaskWithTraits(
100 FROM_HERE, profiled_traits,
Jesse McKenna53d5e122018-09-18 16:00:43101 BindOnce(
102 &TaskTracker::RecordHeartbeatLatencyAndTasksRunWhileQueuingHistograms,
103 Unretained(task_tracker_), task_priority, may_block, TimeTicks::Now(),
104 task_tracker_->GetNumTasksRun()));
Gabriel Charette3fb9e4f2018-05-18 21:34:43105}
106
107} // namespace internal
108} // namespace base