OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_impl.h" | 5 #include "base/debug/trace_event_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/base_switches.h" | 9 #include "base/base_switches.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/debug/leak_annotations.h" | 12 #include "base/debug/leak_annotations.h" |
13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
| 14 #include "base/debug/trace_event_synthetic_delay.h" |
14 #include "base/format_macros.h" | 15 #include "base/format_macros.h" |
15 #include "base/json/string_escape.h" | 16 #include "base/json/string_escape.h" |
16 #include "base/lazy_instance.h" | 17 #include "base/lazy_instance.h" |
17 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
18 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
19 #include "base/process/process_metrics.h" | 20 #include "base/process/process_metrics.h" |
20 #include "base/stl_util.h" | 21 #include "base/stl_util.h" |
21 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" |
22 #include "base/strings/string_split.h" | 23 #include "base/strings/string_split.h" |
23 #include "base/strings/string_tokenizer.h" | 24 #include "base/strings/string_tokenizer.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 // Can store results for 30 seconds with 1 ms sampling interval. | 66 // Can store results for 30 seconds with 1 ms sampling interval. |
66 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize; | 67 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize; |
67 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events. | 68 // ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events. |
68 const size_t kEchoToConsoleTraceEventBufferChunks = 256; | 69 const size_t kEchoToConsoleTraceEventBufferChunks = 256; |
69 | 70 |
70 const int kThreadFlushTimeoutMs = 3000; | 71 const int kThreadFlushTimeoutMs = 3000; |
71 | 72 |
72 // These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575. | 73 // These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575. |
73 const char kEchoToConsoleCategoryFilter[] = "-ipc,-task"; | 74 const char kEchoToConsoleCategoryFilter[] = "-ipc,-task"; |
74 | 75 |
| 76 const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY("; |
| 77 |
75 #define MAX_CATEGORY_GROUPS 100 | 78 #define MAX_CATEGORY_GROUPS 100 |
76 | 79 |
77 // Parallel arrays g_category_groups and g_category_group_enabled are separate | 80 // Parallel arrays g_category_groups and g_category_group_enabled are separate |
78 // so that a pointer to a member of g_category_group_enabled can be easily | 81 // so that a pointer to a member of g_category_group_enabled can be easily |
79 // converted to an index into g_category_groups. This allows macros to deal | 82 // converted to an index into g_category_groups. This allows macros to deal |
80 // only with char enabled pointers from g_category_group_enabled, and we can | 83 // only with char enabled pointers from g_category_group_enabled, and we can |
81 // convert internally to determine the category name from the char enabled | 84 // convert internally to determine the category name from the char enabled |
82 // pointer. | 85 // pointer. |
83 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { | 86 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { |
84 "tracing already shutdown", | 87 "tracing already shutdown", |
(...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1202 event_callback_category_filter_.IsCategoryGroupEnabled(category_group)) | 1205 event_callback_category_filter_.IsCategoryGroupEnabled(category_group)) |
1203 enabled_flag |= ENABLED_FOR_EVENT_CALLBACK; | 1206 enabled_flag |= ENABLED_FOR_EVENT_CALLBACK; |
1204 g_category_group_enabled[category_index] = enabled_flag; | 1207 g_category_group_enabled[category_index] = enabled_flag; |
1205 } | 1208 } |
1206 | 1209 |
1207 void TraceLog::UpdateCategoryGroupEnabledFlags() { | 1210 void TraceLog::UpdateCategoryGroupEnabledFlags() { |
1208 for (int i = 0; i < g_category_index; i++) | 1211 for (int i = 0; i < g_category_index; i++) |
1209 UpdateCategoryGroupEnabledFlag(i); | 1212 UpdateCategoryGroupEnabledFlag(i); |
1210 } | 1213 } |
1211 | 1214 |
| 1215 void TraceLog::UpdateSyntheticDelaysFromCategoryFilter() { |
| 1216 ResetTraceEventSyntheticDelays(); |
| 1217 const CategoryFilter::DelayValueList& delays = |
| 1218 category_filter_.GetSyntheticDelayValues(); |
| 1219 CategoryFilter::DelayValueList::const_iterator ci; |
| 1220 for (ci = delays.begin(); ci != delays.end(); ++ci) { |
| 1221 TraceEventSyntheticDelay* delay = |
| 1222 TraceEventSyntheticDelay::Lookup(ci->first); |
| 1223 StringTokenizer tokens(ci->second, ";"); |
| 1224 while (tokens.GetNext()) { |
| 1225 double target_duration; |
| 1226 if (StringToDouble(tokens.token(), &target_duration)) { |
| 1227 delay->SetTargetDuration( |
| 1228 TimeDelta::FromMicroseconds(target_duration * 1e6)); |
| 1229 } else if (tokens.token() == "static") { |
| 1230 delay->SetMode(TraceEventSyntheticDelay::STATIC); |
| 1231 } else if (tokens.token() == "oneshot") { |
| 1232 delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT); |
| 1233 } else if (tokens.token() == "alternating") { |
| 1234 delay->SetMode(TraceEventSyntheticDelay::ALTERNATING); |
| 1235 } |
| 1236 } |
| 1237 } |
| 1238 } |
| 1239 |
1212 const unsigned char* TraceLog::GetCategoryGroupEnabledInternal( | 1240 const unsigned char* TraceLog::GetCategoryGroupEnabledInternal( |
1213 const char* category_group) { | 1241 const char* category_group) { |
1214 DCHECK(!strchr(category_group, '"')) << | 1242 DCHECK(!strchr(category_group, '"')) << |
1215 "Category groups may not contain double quote"; | 1243 "Category groups may not contain double quote"; |
1216 AutoLock lock(lock_); | 1244 AutoLock lock(lock_); |
1217 | 1245 |
1218 unsigned char* category_group_enabled = NULL; | 1246 unsigned char* category_group_enabled = NULL; |
1219 // Search for pre-existing category group. | 1247 // Search for pre-existing category group. |
1220 for (int i = 0; i < g_category_index; i++) { | 1248 for (int i = 0; i < g_category_index; i++) { |
1221 if (strcmp(g_category_groups[i], category_group) == 0) { | 1249 if (strcmp(g_category_groups[i], category_group) == 0) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1296 | 1324 |
1297 if (options != old_options) { | 1325 if (options != old_options) { |
1298 subtle::NoBarrier_Store(&trace_options_, options); | 1326 subtle::NoBarrier_Store(&trace_options_, options); |
1299 UseNextTraceBuffer(); | 1327 UseNextTraceBuffer(); |
1300 } | 1328 } |
1301 | 1329 |
1302 num_traces_recorded_++; | 1330 num_traces_recorded_++; |
1303 | 1331 |
1304 category_filter_ = CategoryFilter(category_filter); | 1332 category_filter_ = CategoryFilter(category_filter); |
1305 UpdateCategoryGroupEnabledFlags(); | 1333 UpdateCategoryGroupEnabledFlags(); |
| 1334 UpdateSyntheticDelaysFromCategoryFilter(); |
1306 | 1335 |
1307 if (options & ENABLE_SAMPLING) { | 1336 if (options & ENABLE_SAMPLING) { |
1308 sampling_thread_.reset(new TraceSamplingThread); | 1337 sampling_thread_.reset(new TraceSamplingThread); |
1309 sampling_thread_->RegisterSampleBucket( | 1338 sampling_thread_->RegisterSampleBucket( |
1310 &g_trace_state[0], | 1339 &g_trace_state[0], |
1311 "bucket0", | 1340 "bucket0", |
1312 Bind(&TraceSamplingThread::DefaultSamplingCallback)); | 1341 Bind(&TraceSamplingThread::DefaultSamplingCallback)); |
1313 sampling_thread_->RegisterSampleBucket( | 1342 sampling_thread_->RegisterSampleBucket( |
1314 &g_trace_state[1], | 1343 &g_trace_state[1], |
1315 "bucket1", | 1344 "bucket1", |
(...skipping 853 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2169 CategoryFilter::CategoryFilter(const std::string& filter_string) { | 2198 CategoryFilter::CategoryFilter(const std::string& filter_string) { |
2170 if (!filter_string.empty()) | 2199 if (!filter_string.empty()) |
2171 Initialize(filter_string); | 2200 Initialize(filter_string); |
2172 else | 2201 else |
2173 Initialize(CategoryFilter::kDefaultCategoryFilterString); | 2202 Initialize(CategoryFilter::kDefaultCategoryFilterString); |
2174 } | 2203 } |
2175 | 2204 |
2176 CategoryFilter::CategoryFilter(const CategoryFilter& cf) | 2205 CategoryFilter::CategoryFilter(const CategoryFilter& cf) |
2177 : included_(cf.included_), | 2206 : included_(cf.included_), |
2178 disabled_(cf.disabled_), | 2207 disabled_(cf.disabled_), |
2179 excluded_(cf.excluded_) { | 2208 excluded_(cf.excluded_), |
| 2209 delays_(cf.delays_) { |
2180 } | 2210 } |
2181 | 2211 |
2182 CategoryFilter::~CategoryFilter() { | 2212 CategoryFilter::~CategoryFilter() { |
2183 } | 2213 } |
2184 | 2214 |
2185 CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) { | 2215 CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) { |
2186 if (this == &rhs) | 2216 if (this == &rhs) |
2187 return *this; | 2217 return *this; |
2188 | 2218 |
2189 included_ = rhs.included_; | 2219 included_ = rhs.included_; |
2190 disabled_ = rhs.disabled_; | 2220 disabled_ = rhs.disabled_; |
2191 excluded_ = rhs.excluded_; | 2221 excluded_ = rhs.excluded_; |
| 2222 delays_ = rhs.delays_; |
2192 return *this; | 2223 return *this; |
2193 } | 2224 } |
2194 | 2225 |
2195 void CategoryFilter::Initialize(const std::string& filter_string) { | 2226 void CategoryFilter::Initialize(const std::string& filter_string) { |
2196 // Tokenize list of categories, delimited by ','. | 2227 // Tokenize list of categories, delimited by ','. |
2197 StringTokenizer tokens(filter_string, ","); | 2228 StringTokenizer tokens(filter_string, ","); |
2198 // Add each token to the appropriate list (included_,excluded_). | 2229 // Add each token to the appropriate list (included_,excluded_). |
2199 while (tokens.GetNext()) { | 2230 while (tokens.GetNext()) { |
2200 std::string category = tokens.token(); | 2231 std::string category = tokens.token(); |
2201 // Ignore empty categories. | 2232 // Ignore empty categories. |
2202 if (category.empty()) | 2233 if (category.empty()) |
2203 continue; | 2234 continue; |
2204 // Excluded categories start with '-'. | 2235 // Synthetic delays are of the form 'DELAY(delay;option;option;...)'. |
2205 if (category.at(0) == '-') { | 2236 if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 && |
| 2237 category.at(category.size() - 1) == ')') { |
| 2238 category = category.substr( |
| 2239 strlen(kSyntheticDelayCategoryFilterPrefix), |
| 2240 category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1); |
| 2241 size_t name_length = category.find(';'); |
| 2242 if (name_length != std::string::npos && name_length > 0 && |
| 2243 name_length != category.size() - 1) { |
| 2244 delays_.push_back(DelayValue(category.substr(0, name_length), |
| 2245 category.substr(name_length + 1))); |
| 2246 } |
| 2247 } else if (category.at(0) == '-') { |
| 2248 // Excluded categories start with '-'. |
2206 // Remove '-' from category string. | 2249 // Remove '-' from category string. |
2207 category = category.substr(1); | 2250 category = category.substr(1); |
2208 excluded_.push_back(category); | 2251 excluded_.push_back(category); |
2209 } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), | 2252 } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), |
2210 TRACE_DISABLED_BY_DEFAULT("")) == 0) { | 2253 TRACE_DISABLED_BY_DEFAULT("")) == 0) { |
2211 disabled_.push_back(category); | 2254 disabled_.push_back(category); |
2212 } else { | 2255 } else { |
2213 included_.push_back(category); | 2256 included_.push_back(category); |
2214 } | 2257 } |
2215 } | 2258 } |
2216 } | 2259 } |
2217 | 2260 |
2218 void CategoryFilter::WriteString(const StringList& values, | 2261 void CategoryFilter::WriteString(const StringList& values, |
2219 std::string* out, | 2262 std::string* out, |
2220 bool included) const { | 2263 bool included) const { |
2221 bool prepend_comma = !out->empty(); | 2264 bool prepend_comma = !out->empty(); |
2222 int token_cnt = 0; | 2265 int token_cnt = 0; |
2223 for (StringList::const_iterator ci = values.begin(); | 2266 for (StringList::const_iterator ci = values.begin(); |
2224 ci != values.end(); ++ci) { | 2267 ci != values.end(); ++ci) { |
2225 if (token_cnt > 0 || prepend_comma) | 2268 if (token_cnt > 0 || prepend_comma) |
2226 StringAppendF(out, ","); | 2269 StringAppendF(out, ","); |
2227 StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str()); | 2270 StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str()); |
2228 ++token_cnt; | 2271 ++token_cnt; |
2229 } | 2272 } |
2230 } | 2273 } |
2231 | 2274 |
| 2275 void CategoryFilter::WriteString(const DelayValueList& delays, |
| 2276 std::string* out) const { |
| 2277 bool prepend_comma = !out->empty(); |
| 2278 int token_cnt = 0; |
| 2279 for (DelayValueList::const_iterator ci = delays.begin(); |
| 2280 ci != delays.end(); ++ci) { |
| 2281 if (token_cnt > 0 || prepend_comma) |
| 2282 StringAppendF(out, ","); |
| 2283 StringAppendF(out, "%s%s;%s)", kSyntheticDelayCategoryFilterPrefix, |
| 2284 ci->first.c_str(), ci->second.c_str()); |
| 2285 ++token_cnt; |
| 2286 } |
| 2287 } |
| 2288 |
2232 std::string CategoryFilter::ToString() const { | 2289 std::string CategoryFilter::ToString() const { |
2233 std::string filter_string; | 2290 std::string filter_string; |
2234 WriteString(included_, &filter_string, true); | 2291 WriteString(included_, &filter_string, true); |
2235 WriteString(disabled_, &filter_string, true); | 2292 WriteString(disabled_, &filter_string, true); |
2236 WriteString(excluded_, &filter_string, false); | 2293 WriteString(excluded_, &filter_string, false); |
| 2294 WriteString(delays_, &filter_string); |
2237 return filter_string; | 2295 return filter_string; |
2238 } | 2296 } |
2239 | 2297 |
2240 bool CategoryFilter::IsCategoryGroupEnabled( | 2298 bool CategoryFilter::IsCategoryGroupEnabled( |
2241 const char* category_group_name) const { | 2299 const char* category_group_name) const { |
2242 // TraceLog should call this method only as part of enabling/disabling | 2300 // TraceLog should call this method only as part of enabling/disabling |
2243 // categories. | 2301 // categories. |
2244 StringList::const_iterator ci; | 2302 StringList::const_iterator ci; |
2245 | 2303 |
2246 // Check the disabled- filters and the disabled-* wildcard first so that a | 2304 // Check the disabled- filters and the disabled-* wildcard first so that a |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2282 } else { | 2340 } else { |
2283 included_.clear(); | 2341 included_.clear(); |
2284 } | 2342 } |
2285 | 2343 |
2286 disabled_.insert(disabled_.end(), | 2344 disabled_.insert(disabled_.end(), |
2287 nested_filter.disabled_.begin(), | 2345 nested_filter.disabled_.begin(), |
2288 nested_filter.disabled_.end()); | 2346 nested_filter.disabled_.end()); |
2289 excluded_.insert(excluded_.end(), | 2347 excluded_.insert(excluded_.end(), |
2290 nested_filter.excluded_.begin(), | 2348 nested_filter.excluded_.begin(), |
2291 nested_filter.excluded_.end()); | 2349 nested_filter.excluded_.end()); |
| 2350 delays_.insert(delays_.end(), |
| 2351 nested_filter.delays_.begin(), |
| 2352 nested_filter.delays_.end()); |
2292 } | 2353 } |
2293 | 2354 |
2294 void CategoryFilter::Clear() { | 2355 void CategoryFilter::Clear() { |
2295 included_.clear(); | 2356 included_.clear(); |
2296 disabled_.clear(); | 2357 disabled_.clear(); |
2297 excluded_.clear(); | 2358 excluded_.clear(); |
2298 } | 2359 } |
2299 | 2360 |
| 2361 const CategoryFilter::DelayValueList& |
| 2362 CategoryFilter::GetSyntheticDelayValues() const { |
| 2363 return delays_; |
| 2364 } |
| 2365 |
2300 } // namespace debug | 2366 } // namespace debug |
2301 } // namespace base | 2367 } // namespace base |
2302 | 2368 |
2303 namespace trace_event_internal { | 2369 namespace trace_event_internal { |
2304 | 2370 |
2305 ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( | 2371 ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( |
2306 const char* category_group, const char* name) { | 2372 const char* category_group, const char* name) { |
2307 // The single atom works because for now the category_group can only be "gpu". | 2373 // The single atom works because for now the category_group can only be "gpu". |
2308 DCHECK(strcmp(category_group, "gpu") == 0); | 2374 DCHECK(strcmp(category_group, "gpu") == 0); |
2309 static TRACE_EVENT_API_ATOMIC_WORD atomic = 0; | 2375 static TRACE_EVENT_API_ATOMIC_WORD atomic = 0; |
(...skipping 12 matching lines...) Expand all Loading... |
2322 } | 2388 } |
2323 | 2389 |
2324 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { | 2390 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { |
2325 if (*category_group_enabled_) { | 2391 if (*category_group_enabled_) { |
2326 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, | 2392 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, |
2327 name_, event_handle_); | 2393 name_, event_handle_); |
2328 } | 2394 } |
2329 } | 2395 } |
2330 | 2396 |
2331 } // namespace trace_event_internal | 2397 } // namespace trace_event_internal |
OLD | NEW |