1// Copyright (c) 2010 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.h"
6
7#include "base/format_macros.h"
8#include "base/file_path.h"
9#include "base/file_util.h"
10#include "base/path_service.h"
11#include "base/platform_thread.h"
12#include "base/process_util.h"
13#include "base/stringprintf.h"
14#include "base/utf_string_conversions.h"
15#include "base/time.h"
16
17#define USE_UNRELIABLE_NOW
18
19namespace base {
20namespace debug {
21
22static const char* kEventTypeNames[] = {
23  "BEGIN",
24  "END",
25  "INSTANT"
26};
27
28static const FilePath::CharType* kLogFileName =
29    FILE_PATH_LITERAL("trace_%d.log");
30
31// static
32TraceLog* TraceLog::GetInstance() {
33  return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get();
34}
35
36// static
37bool TraceLog::IsTracing() {
38  return TraceLog::GetInstance()->enabled_;
39}
40
41// static
42bool TraceLog::StartTracing() {
43  return TraceLog::GetInstance()->Start();
44}
45
46// static
47void TraceLog::StopTracing() {
48  return TraceLog::GetInstance()->Stop();
49}
50
51void TraceLog::Trace(const std::string& name,
52                     EventType type,
53                     const void* id,
54                     const std::wstring& extra,
55                     const char* file,
56                     int line) {
57  if (!enabled_)
58    return;
59  Trace(name, type, id, WideToUTF8(extra), file, line);
60}
61
62void TraceLog::Trace(const std::string& name,
63                     EventType type,
64                     const void* id,
65                     const std::string& extra,
66                     const char* file,
67                     int line) {
68  if (!enabled_)
69    return;
70
71#ifdef USE_UNRELIABLE_NOW
72  TimeTicks tick = TimeTicks::HighResNow();
73#else
74  TimeTicks tick = TimeTicks::Now();
75#endif
76  TimeDelta delta = tick - trace_start_time_;
77  int64 usec = delta.InMicroseconds();
78  std::string msg =
79    StringPrintf("{'pid':'0x%lx', 'tid':'0x%lx', 'type':'%s', "
80                 "'name':'%s', 'id':'%p', 'extra':'%s', 'file':'%s', "
81                 "'line_number':'%d', 'usec_begin': %" PRId64 "},\n",
82                 static_cast<unsigned long>(base::GetCurrentProcId()),
83                 static_cast<unsigned long>(PlatformThread::CurrentId()),
84                 kEventTypeNames[type],
85                 name.c_str(),
86                 id,
87                 extra.c_str(),
88                 file,
89                 line,
90                 usec);
91
92  Log(msg);
93}
94
95TraceLog::TraceLog() : enabled_(false), log_file_(NULL) {
96  base::ProcessHandle proc = base::GetCurrentProcessHandle();
97#if !defined(OS_MACOSX)
98  process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc));
99#else
100  // The default port provider is sufficient to get data for the current
101  // process.
102  process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc,
103                                                                    NULL));
104#endif
105}
106
107TraceLog::~TraceLog() {
108  Stop();
109}
110
111bool TraceLog::OpenLogFile() {
112  FilePath::StringType pid_filename =
113      StringPrintf(kLogFileName, base::GetCurrentProcId());
114  FilePath log_file_path;
115  if (!PathService::Get(base::DIR_EXE, &log_file_path))
116    return false;
117  log_file_path = log_file_path.Append(pid_filename);
118  log_file_ = file_util::OpenFile(log_file_path, "a");
119  if (!log_file_) {
120    // try the current directory
121    log_file_ = file_util::OpenFile(FilePath(pid_filename), "a");
122    if (!log_file_) {
123      return false;
124    }
125  }
126  return true;
127}
128
129void TraceLog::CloseLogFile() {
130  if (log_file_) {
131    file_util::CloseFile(log_file_);
132  }
133}
134
135bool TraceLog::Start() {
136  if (enabled_)
137    return true;
138  enabled_ = OpenLogFile();
139  if (enabled_) {
140    Log("var raw_trace_events = [\n");
141    trace_start_time_ = TimeTicks::Now();
142    timer_.Start(TimeDelta::FromMilliseconds(250), this, &TraceLog::Heartbeat);
143  }
144  return enabled_;
145}
146
147void TraceLog::Stop() {
148  if (enabled_) {
149    enabled_ = false;
150    Log("];\n");
151    CloseLogFile();
152    timer_.Stop();
153  }
154}
155
156void TraceLog::Heartbeat() {
157  std::string cpu = StringPrintf("%.0f", process_metrics_->GetCPUUsage());
158  TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu);
159}
160
161void TraceLog::Log(const std::string& msg) {
162  AutoLock lock(file_lock_);
163
164  fprintf(log_file_, "%s", msg.c_str());
165}
166
167}  // namespace debug
168}  // namespace base
169