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 19 namespace base { 20 namespace debug { 21 22 static const char* kEventTypeNames[] = { 23 "BEGIN", 24 "END", 25 "INSTANT" 26 }; 27 28 static const FilePath::CharType* kLogFileName = 29 FILE_PATH_LITERAL("trace_%d.log"); 30 31 // static 32 TraceLog* TraceLog::GetInstance() { 33 return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get(); 34 } 35 36 // static 37 bool TraceLog::IsTracing() { 38 return TraceLog::GetInstance()->enabled_; 39 } 40 41 // static 42 bool TraceLog::StartTracing() { 43 return TraceLog::GetInstance()->Start(); 44 } 45 46 // static 47 void TraceLog::StopTracing() { 48 return TraceLog::GetInstance()->Stop(); 49 } 50 51 void 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 62 void 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 95 TraceLog::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 107 TraceLog::~TraceLog() { 108 Stop(); 109 } 110 111 bool 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 129 void TraceLog::CloseLogFile() { 130 if (log_file_) { 131 file_util::CloseFile(log_file_); 132 } 133 } 134 135 bool 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 147 void TraceLog::Stop() { 148 if (enabled_) { 149 enabled_ = false; 150 Log("];\n"); 151 CloseLogFile(); 152 timer_.Stop(); 153 } 154 } 155 156 void TraceLog::Heartbeat() { 157 std::string cpu = StringPrintf("%.0f", process_metrics_->GetCPUUsage()); 158 TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu); 159 } 160 161 void 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