OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/trace_event.h" | 5 #include "base/debug/trace_event.h" |
6 | 6 |
7 #if defined(OS_WIN) | |
8 #include "base/debug/trace_event_win.h" | |
9 #endif | |
7 #include "base/format_macros.h" | 10 #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/process_util.h" | 11 #include "base/process_util.h" |
12 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
13 #include "base/threading/platform_thread.h" | |
14 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
15 #include "base/time.h" | 14 #include "base/time.h" |
16 | 15 |
17 #define USE_UNRELIABLE_NOW | 16 #define USE_UNRELIABLE_NOW |
18 | 17 |
19 namespace base { | 18 namespace base { |
20 namespace debug { | 19 namespace debug { |
21 | 20 |
22 static const char* kEventTypeNames[] = { | 21 #define GPU_TRACE_MAX_EVENTS_TO_BUFFER 16384 |
rvargas (doing something else)
2011/02/25 23:38:33
?
| |
23 "BEGIN", | 22 |
24 "END", | 23 //////////////////////////////////////////////////////////////////////////////// |
25 "INSTANT" | 24 // |
26 }; | 25 // TraceLog::Category |
27 | 26 // |
28 static const FilePath::CharType* kLogFileName = | 27 //////////////////////////////////////////////////////////////////////////////// |
29 FILE_PATH_LITERAL("trace_%d.log"); | 28 TraceCategory::TraceCategory(const char* name, bool enabled) |
29 : name_(name) { | |
30 base::subtle::NoBarrier_Store(&enabled_, | |
31 static_cast<base::subtle::Atomic32>(enabled)); | |
32 } | |
33 | |
34 TraceCategory::~TraceCategory() { | |
35 base::subtle::NoBarrier_Store(&enabled_, | |
36 static_cast<base::subtle::Atomic32>(0)); | |
37 } | |
38 | |
39 //////////////////////////////////////////////////////////////////////////////// | |
40 // | |
41 // TraceEvent | |
42 // | |
43 //////////////////////////////////////////////////////////////////////////////// | |
44 | |
45 namespace { | |
46 const char* GetPhaseStr(TraceEventPhase phase) { | |
47 if (phase== TRACE_EVENT_PHASE_BEGIN) { | |
48 return "B"; | |
49 } else if (phase == TRACE_EVENT_PHASE_INSTANT) { | |
50 return "I"; | |
51 } else if (phase == TRACE_EVENT_PHASE_END) { | |
52 return "E"; | |
53 } else { | |
54 DCHECK(false); | |
55 return "?"; | |
56 } | |
57 } | |
58 } | |
59 | |
60 void TraceEvent::AppendAsJSON(std::string& out, | |
61 const std::vector<TraceEvent>& events) { | |
62 out += "["; | |
63 for (size_t i = 0; i < events.size(); ++i) { | |
64 if (i > 0) | |
65 out += ","; | |
66 events[i].AppendAsJSON(out); | |
67 } | |
68 out += "]"; | |
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Are there more efficient ways of building up C++ s
| |
69 } | |
70 | |
71 void TraceEvent::AppendAsJSON(std::string& out) const { | |
72 int nargs = 0; | |
73 for (int i = 0; i < TRACE_MAX_NUM_ARGS; ++i) { | |
74 if (argNames[i] == NULL) | |
75 break; | |
76 nargs += 1; | |
77 } | |
78 | |
79 const char* phaseStr = GetPhaseStr(phase); | |
80 int64 time_int64 = timestamp.ToInternalValue(); | |
81 long long unsigned int time_llui = | |
82 static_cast<long long unsigned int>(time_int64); | |
83 StringAppendF(&out, | |
84 "{cat:'%s',pid:%i,tid:%i,ts:0x%llx,ph:'%s',name:'%s',args:{", | |
85 category->name(), | |
86 static_cast<int>(processId), | |
87 static_cast<int>(threadId), | |
88 time_llui, | |
89 phaseStr, | |
90 name); | |
91 for (int i = 0; i < nargs; ++i) { | |
92 if (i > 0) | |
93 out += ","; | |
94 out += argNames[i]; | |
95 out += ":'"; | |
96 out += argValues[i]; | |
97 out += "'"; | |
98 } | |
99 out += "}}"; | |
100 } | |
101 | |
102 //////////////////////////////////////////////////////////////////////////////// | |
103 // | |
104 // TraceLog | |
105 // | |
106 //////////////////////////////////////////////////////////////////////////////// | |
30 | 107 |
31 // static | 108 // static |
32 TraceLog* TraceLog::GetInstance() { | 109 TraceLog* TraceLog::GetInstance() { |
33 return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get(); | 110 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); |
34 } | 111 } |
35 | 112 |
36 // static | 113 TraceLog::TraceLog() |
37 bool TraceLog::IsTracing() { | 114 : enabled_(false) |
38 return TraceLog::GetInstance()->enabled_; | 115 { |
39 } | 116 logged_events_.reserve(1024); |
40 | 117 } |
41 // static | 118 |
42 bool TraceLog::StartTracing() { | 119 TraceLog::~TraceLog() { |
43 return TraceLog::GetInstance()->Start(); | 120 } |
44 } | 121 |
45 | 122 TraceCategory* TraceLog::GetCategory(const char* name) { |
46 // static | 123 AutoLock lock(lock_); |
47 void TraceLog::StopTracing() { | 124 // TODO(nduca) replace with a hash_map |
48 return TraceLog::GetInstance()->Stop(); | 125 for (int i = categories_.size() - 1; i >= 0; i-- ) { |
49 } | 126 if (strcmp(categories_[i]->name(), name) == 0) |
50 | 127 return categories_[i]; |
51 void TraceLog::Trace(const std::string& name, | 128 } |
52 EventType type, | 129 TraceCategory* category = new TraceCategory(name, enabled_); |
53 const void* id, | 130 categories_.push_back(category); |
54 const std::wstring& extra, | 131 return category; |
55 const char* file, | 132 } |
56 int line) { | 133 |
57 if (!enabled_) | 134 void TraceLog::SetEnabled(bool enabled) { |
135 AutoLock lock(lock_); | |
136 if (enabled == enabled_) | |
58 return; | 137 return; |
59 Trace(name, type, id, WideToUTF8(extra), file, line); | 138 if (enabled) { |
60 } | 139 /* enable all categories */ |
61 | 140 enabled_ = true; |
62 void TraceLog::Trace(const std::string& name, | 141 for (size_t i = 0; i < categories_.size(); i++) { |
63 EventType type, | 142 base::subtle::NoBarrier_Store(&categories_[i]->enabled_, |
64 const void* id, | 143 static_cast<base::subtle::Atomic32>(1)); |
65 const std::string& extra, | 144 } |
66 const char* file, | 145 } else { |
67 int line) { | 146 /* disable all categories */ |
68 if (!enabled_) | 147 for (size_t i = 0; i < categories_.size(); i++) { |
69 return; | 148 base::subtle::NoBarrier_Store(&categories_[i]->enabled_, |
70 | 149 static_cast<base::subtle::Atomic32>(0)); |
150 } | |
151 enabled_ = false; | |
152 FlushWithLockAlreadyHeld(); | |
153 } | |
154 } | |
155 | |
156 void TraceLog::SetOutputCallback(TraceLog::OutputCallback* cb) { | |
157 AutoLock lock(lock_); | |
158 if (enabled_) { | |
159 FlushWithLockAlreadyHeld(); | |
160 } | |
161 output_callback_.reset(cb); | |
162 } | |
163 | |
164 void TraceLog::AddRemotelyCollectedData(const std::string& json_events) { | |
165 AutoLock lock(lock_); | |
166 if (output_callback_.get()) | |
167 output_callback_->Run(json_events); | |
168 } | |
169 | |
170 void TraceLog::Flush() { | |
171 AutoLock lock(lock_); | |
172 FlushWithLockAlreadyHeld(); | |
173 } | |
174 | |
175 void TraceLog::FlushWithLockAlreadyHeld() { | |
176 if (output_callback_.get() && logged_events_.size()) { | |
177 std::string json_events; | |
178 TraceEvent::AppendAsJSON(json_events, logged_events_); | |
179 output_callback_->Run(json_events); | |
180 } | |
181 logged_events_.erase(logged_events_.begin(), logged_events_.end()); | |
182 } | |
183 | |
184 void TraceLog::AddTraceEvent(TraceEventPhase phase, | |
185 const char* file, int line, | |
186 TraceCategory* category, | |
187 const char* name, | |
188 const char* arg1name, const char* arg1val, | |
189 const char* arg2name, const char* arg2val) { | |
190 DCHECK(file && name); | |
71 #ifdef USE_UNRELIABLE_NOW | 191 #ifdef USE_UNRELIABLE_NOW |
72 TimeTicks tick = TimeTicks::HighResNow(); | 192 TimeTicks now = TimeTicks::HighResNow(); |
73 #else | 193 #else |
74 TimeTicks tick = TimeTicks::Now(); | 194 TimeTicks now = TimeTicks::Now(); |
75 #endif | 195 #endif |
76 TimeDelta delta = tick - trace_start_time_; | 196 //static_cast<unsigned long>(base::GetCurrentProcId()), |
77 int64 usec = delta.InMicroseconds(); | 197 AutoLock lock(lock_); |
78 std::string msg = | 198 logged_events_.push_back(TraceEvent()); |
79 StringPrintf("{'pid':'0x%lx', 'tid':'0x%lx', 'type':'%s', " | 199 TraceEvent& event = logged_events_.back(); |
80 "'name':'%s', 'id':'%p', 'extra':'%s', 'file':'%s', " | 200 event.processId = static_cast<unsigned long>(base::GetCurrentProcId()); |
81 "'line_number':'%d', 'usec_begin': %" PRId64 "},\n", | 201 event.threadId = PlatformThread::CurrentId(); |
82 static_cast<unsigned long>(base::GetCurrentProcId()), | 202 event.timestamp = now; |
83 static_cast<unsigned long>(PlatformThread::CurrentId()), | 203 event.phase = phase; |
84 kEventTypeNames[type], | 204 event.category = category; |
85 name.c_str(), | 205 event.name = name; |
86 id, | 206 event.argNames[0] = arg1name; |
87 extra.c_str(), | 207 event.argValues[0] = arg1name ? arg1val : ""; |
88 file, | 208 event.argNames[1] = arg2name; |
89 line, | 209 event.argValues[1] = arg2name ? arg2val : ""; |
90 usec); | 210 COMPILE_ASSERT(TRACE_MAX_NUM_ARGS == 2, TraceEvent_arc_count_out_of_sync); |
91 | 211 |
92 Log(msg); | 212 if (logged_events_.size() > GPU_TRACE_MAX_EVENTS_TO_BUFFER) |
93 } | 213 FlushWithLockAlreadyHeld(); |
94 | 214 } |
95 TraceLog::TraceLog() : enabled_(false), log_file_(NULL) { | 215 |
96 base::ProcessHandle proc = base::GetCurrentProcessHandle(); | 216 void TraceLog::AddTraceEventLegacy(TraceEventPhase phase, |
97 #if !defined(OS_MACOSX) | 217 const char* file, int line, |
98 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc)); | 218 const char* name, |
99 #else | 219 const void* id, |
100 // The default port provider is sufficient to get data for the current | 220 const char* extra) { |
101 // process. | 221 // Legacy trace points on windows called to ETW |
102 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc, | 222 #if defined(OS_WIN) |
103 NULL)); | 223 TraceEventETWProvider::Trace(name, phase, id, extra); |
104 #endif | 224 #endif |
105 } | 225 |
106 | 226 // Also add new trace event behavior |
107 TraceLog::~TraceLog() { | 227 static TraceCategory* category = GetCategory("Legacy Trace Event"); |
108 Stop(); | 228 if (category->enabled_) { |
109 } | 229 AddTraceEvent(phase, file, line, category, name, |
110 | 230 "id", StringPrintf("%p", id).c_str(), |
111 bool TraceLog::OpenLogFile() { | 231 "extra", extra ? extra : ""); |
112 FilePath::StringType pid_filename = | 232 } |
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 } | 233 } |
166 | 234 |
167 } // namespace debug | 235 } // namespace debug |
168 } // namespace base | 236 } // namespace base |
OLD | NEW |