[TaskScheduler] Introduce HeartbeatLatencyMicroseconds metric.

Put the timer on the service thread to avoid depending on the main
thread (want to record the metric even if -- especially if -- the main
thread is too busy for its timers to fire).

Move the impl to service_thread.cc to be able to use post_task.h and
test the full stack (also allows documenting "service thread" in its
new header which was never a well documented concept of task scheduler's
internals).

Kept reporting logic in task_tracker.cc to centralize traits-based
metrics reporting logic.

[email protected], [email protected]

Bug: 810746
Change-Id: Ie866d521c734bc63941836319d6c1258253cb8c5
Reviewed-on: https://chromium-review.googlesource.com/1059459
Commit-Queue: Gabriel Charette <[email protected]>
Reviewed-by: Jesse Doherty <[email protected]>
Reviewed-by: Timothy Dresser <[email protected]>
Reviewed-by: François Doray <[email protected]>
Cr-Commit-Position: refs/heads/master@{#560052}
diff --git a/base/task_scheduler/service_thread.cc b/base/task_scheduler/service_thread.cc
new file mode 100644
index 0000000..40f217f
--- /dev/null
+++ b/base/task_scheduler/service_thread.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task_scheduler/service_thread.h"
+
+#include "base/debug/alias.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_tracker.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+ServiceThread::ServiceThread(const TaskTracker* task_tracker)
+    : Thread("TaskSchedulerServiceThread"), task_tracker_(task_tracker) {}
+
+void ServiceThread::Init() {
+  if (task_tracker_) {
+    heartbeat_latency_timer_.Start(
+        FROM_HERE, TimeDelta::FromSeconds(5),
+        BindRepeating(&ServiceThread::PerformHeartbeatLatencyReport,
+                      Unretained(this)));
+  }
+}
+
+NOINLINE void ServiceThread::Run(RunLoop* run_loop) {
+  const int line_number = __LINE__;
+  Thread::Run(run_loop);
+  base::debug::Alias(&line_number);
+}
+
+void ServiceThread::PerformHeartbeatLatencyReport() const {
+  static constexpr TaskTraits kReportedTraits[] = {
+      {TaskPriority::BACKGROUND},    {TaskPriority::BACKGROUND, MayBlock()},
+      {TaskPriority::USER_VISIBLE},  {TaskPriority::USER_VISIBLE, MayBlock()},
+      {TaskPriority::USER_BLOCKING}, {TaskPriority::USER_BLOCKING, MayBlock()}};
+
+  for (auto& traits : kReportedTraits) {
+    // Post through the static API to time the full stack. Use a new Now() for
+    // every set of traits in case PostTaskWithTraits() itself is slow.
+    base::PostTaskWithTraits(
+        FROM_HERE, traits,
+        BindOnce(&TaskTracker::RecordLatencyHistogram,
+                 Unretained(task_tracker_),
+                 TaskTracker::LatencyHistogramType::HEARTBEAT_LATENCY, traits,
+                 TimeTicks::Now()));
+  }
+}
+
+}  // namespace internal
+}  // namespace base