1// Copyright 2013 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/debug/trace_event_system_stats_monitor.h"
6
7#include "base/debug/leak_annotations.h"
8#include "base/debug/trace_event.h"
9#include "base/json/json_writer.h"
10#include "base/lazy_instance.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_util.h"
15#include "base/thread_task_runner_handle.h"
16#include "base/threading/thread_local_storage.h"
17
18namespace base {
19namespace debug {
20
21namespace {
22
23/////////////////////////////////////////////////////////////////////////////
24// Holds profiled system stats until the tracing system needs to serialize it.
25class SystemStatsHolder : public base::debug::ConvertableToTraceFormat {
26 public:
27  SystemStatsHolder() { }
28
29  // Fills system_metrics_ with profiled system memory and disk stats.
30  // Uses the previous stats to compute rates if this is not the first profile.
31  void GetSystemProfilingStats();
32
33  // base::debug::ConvertableToTraceFormat overrides:
34  virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
35    AppendSystemProfileAsTraceFormat(system_stats_, out);
36  }
37
38 private:
39  virtual ~SystemStatsHolder() { }
40
41  SystemMetrics system_stats_;
42
43  DISALLOW_COPY_AND_ASSIGN(SystemStatsHolder);
44};
45
46void SystemStatsHolder::GetSystemProfilingStats() {
47  system_stats_ = SystemMetrics::Sample();
48}
49
50}  // namespace
51
52//////////////////////////////////////////////////////////////////////////////
53
54TraceEventSystemStatsMonitor::TraceEventSystemStatsMonitor(
55    scoped_refptr<SingleThreadTaskRunner> task_runner)
56    : task_runner_(task_runner),
57      weak_factory_(this) {
58  // Force the "system_stats" category to show up in the trace viewer.
59  TraceLog::GetCategoryGroupEnabled(TRACE_DISABLED_BY_DEFAULT("system_stats"));
60
61  // Allow this to be instantiated on unsupported platforms, but don't run.
62  TraceLog::GetInstance()->AddEnabledStateObserver(this);
63}
64
65TraceEventSystemStatsMonitor::~TraceEventSystemStatsMonitor() {
66  if (dump_timer_.IsRunning())
67    StopProfiling();
68  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
69}
70
71void TraceEventSystemStatsMonitor::OnTraceLogEnabled() {
72  // Check to see if system tracing is enabled.
73  bool enabled;
74
75  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT(
76                                     "system_stats"), &enabled);
77  if (!enabled)
78    return;
79  task_runner_->PostTask(
80      FROM_HERE,
81      base::Bind(&TraceEventSystemStatsMonitor::StartProfiling,
82                 weak_factory_.GetWeakPtr()));
83}
84
85void TraceEventSystemStatsMonitor::OnTraceLogDisabled() {
86  task_runner_->PostTask(
87      FROM_HERE,
88      base::Bind(&TraceEventSystemStatsMonitor::StopProfiling,
89                 weak_factory_.GetWeakPtr()));
90}
91
92void TraceEventSystemStatsMonitor::StartProfiling() {
93  // Watch for the tracing framework sending enabling more than once.
94  if (dump_timer_.IsRunning())
95    return;
96
97  dump_timer_.Start(FROM_HERE,
98                    TimeDelta::FromMilliseconds(TraceEventSystemStatsMonitor::
99                                                kSamplingIntervalMilliseconds),
100                    base::Bind(&TraceEventSystemStatsMonitor::
101                               DumpSystemStats,
102                               weak_factory_.GetWeakPtr()));
103}
104
105// If system tracing is enabled, dumps a profile to the tracing system.
106void TraceEventSystemStatsMonitor::DumpSystemStats() {
107  scoped_refptr<SystemStatsHolder> dump_holder = new SystemStatsHolder();
108  dump_holder->GetSystemProfilingStats();
109
110  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
111      TRACE_DISABLED_BY_DEFAULT("system_stats"),
112      "base::TraceEventSystemStatsMonitor::SystemStats",
113      this,
114      scoped_refptr<ConvertableToTraceFormat>(dump_holder));
115}
116
117void TraceEventSystemStatsMonitor::StopProfiling() {
118  dump_timer_.Stop();
119}
120
121bool TraceEventSystemStatsMonitor::IsTimerRunningForTest() const {
122  return dump_timer_.IsRunning();
123}
124
125void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
126                                      std::string* output) {
127  std::string tmp;
128  base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp);
129  *output += tmp;
130}
131
132}  // namespace debug
133}  // namespace base
134