Cleanup setting of 'sysroot' in common.gypi
[chromium-blink-merge.git] / base / trace_event / trace_config.cc
blob9f0367bd2a21b09789ac81f060639f375caf1f73
1 // Copyright (c) 2015 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.
5 #include "base/trace_event/trace_config.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/strings/pattern.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_tokenizer.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/trace_event/memory_dump_manager.h"
14 #include "base/trace_event/memory_dump_request_args.h"
15 #include "base/trace_event/trace_event.h"
17 namespace base {
18 namespace trace_event {
20 namespace {
22 // String options that can be used to initialize TraceOptions.
23 const char kRecordUntilFull[] = "record-until-full";
24 const char kRecordContinuously[] = "record-continuously";
25 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
26 const char kTraceToConsole[] = "trace-to-console";
27 const char kEnableSampling[] = "enable-sampling";
28 const char kEnableSystrace[] = "enable-systrace";
29 const char kEnableArgumentFilter[] = "enable-argument-filter";
31 // String parameters that can be used to parse the trace config string.
32 const char kRecordModeParam[] = "record_mode";
33 const char kEnableSamplingParam[] = "enable_sampling";
34 const char kEnableSystraceParam[] = "enable_systrace";
35 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
36 const char kIncludedCategoriesParam[] = "included_categories";
37 const char kExcludedCategoriesParam[] = "excluded_categories";
38 const char kSyntheticDelaysParam[] = "synthetic_delays";
40 const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
42 // String parameters that is used to parse memory dump config in trace config
43 // string.
44 const char kMemoryDumpConfigParam[] = "memory_dump_config";
45 const char kTriggersParam[] = "triggers";
46 const char kPeriodicIntervalParam[] = "periodic_interval_ms";
47 const char kModeParam[] = "mode";
49 // Default configuration of memory dumps.
50 const TraceConfig::MemoryDumpTriggerConfig kDefaultHeavyMemoryDumpTrigger = {
51 2000, // periodic_interval_ms
52 MemoryDumpLevelOfDetail::DETAILED};
53 const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = {
54 250, // periodic_interval_ms
55 MemoryDumpLevelOfDetail::LIGHT};
57 } // namespace
59 TraceConfig::TraceConfig() {
60 InitializeDefault();
63 TraceConfig::TraceConfig(const std::string& category_filter_string,
64 const std::string& trace_options_string) {
65 InitializeFromStrings(category_filter_string, trace_options_string);
68 TraceConfig::TraceConfig(const std::string& category_filter_string,
69 TraceRecordMode record_mode) {
70 std::string trace_options_string;
71 switch (record_mode) {
72 case RECORD_UNTIL_FULL:
73 trace_options_string = kRecordUntilFull;
74 break;
75 case RECORD_CONTINUOUSLY:
76 trace_options_string = kRecordContinuously;
77 break;
78 case RECORD_AS_MUCH_AS_POSSIBLE:
79 trace_options_string = kRecordAsMuchAsPossible;
80 break;
81 case ECHO_TO_CONSOLE:
82 trace_options_string = kTraceToConsole;
83 break;
84 default:
85 NOTREACHED();
87 InitializeFromStrings(category_filter_string, trace_options_string);
90 TraceConfig::TraceConfig(const std::string& config_string) {
91 if (!config_string.empty())
92 InitializeFromConfigString(config_string);
93 else
94 InitializeDefault();
97 TraceConfig::TraceConfig(const TraceConfig& tc)
98 : record_mode_(tc.record_mode_),
99 enable_sampling_(tc.enable_sampling_),
100 enable_systrace_(tc.enable_systrace_),
101 enable_argument_filter_(tc.enable_argument_filter_),
102 memory_dump_config_(tc.memory_dump_config_),
103 included_categories_(tc.included_categories_),
104 disabled_categories_(tc.disabled_categories_),
105 excluded_categories_(tc.excluded_categories_),
106 synthetic_delays_(tc.synthetic_delays_) {}
108 TraceConfig::~TraceConfig() {
111 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
112 if (this == &rhs)
113 return *this;
115 record_mode_ = rhs.record_mode_;
116 enable_sampling_ = rhs.enable_sampling_;
117 enable_systrace_ = rhs.enable_systrace_;
118 enable_argument_filter_ = rhs.enable_argument_filter_;
119 memory_dump_config_ = rhs.memory_dump_config_;
120 included_categories_ = rhs.included_categories_;
121 disabled_categories_ = rhs.disabled_categories_;
122 excluded_categories_ = rhs.excluded_categories_;
123 synthetic_delays_ = rhs.synthetic_delays_;
124 return *this;
127 const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
128 return synthetic_delays_;
131 std::string TraceConfig::ToString() const {
132 base::DictionaryValue dict;
133 ToDict(dict);
135 std::string json;
136 base::JSONWriter::Write(dict, &json);
138 return json;
141 std::string TraceConfig::ToCategoryFilterString() const {
142 std::string filter_string;
143 WriteCategoryFilterString(included_categories_, &filter_string, true);
144 WriteCategoryFilterString(disabled_categories_, &filter_string, true);
145 WriteCategoryFilterString(excluded_categories_, &filter_string, false);
146 WriteCategoryFilterString(synthetic_delays_, &filter_string);
147 return filter_string;
150 bool TraceConfig::IsCategoryGroupEnabled(
151 const char* category_group_name) const {
152 // TraceLog should call this method only as part of enabling/disabling
153 // categories.
155 bool had_enabled_by_default = false;
156 DCHECK(category_group_name);
157 CStringTokenizer category_group_tokens(
158 category_group_name, category_group_name + strlen(category_group_name),
159 ",");
160 while (category_group_tokens.GetNext()) {
161 std::string category_group_token = category_group_tokens.token();
162 // Don't allow empty tokens, nor tokens with leading or trailing space.
163 DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
164 category_group_token))
165 << "Disallowed category string";
166 if (IsCategoryEnabled(category_group_token.c_str())) {
167 return true;
169 if (!base::MatchPattern(category_group_token.c_str(),
170 TRACE_DISABLED_BY_DEFAULT("*")))
171 had_enabled_by_default = true;
173 // Do a second pass to check for explicitly disabled categories
174 // (those explicitly enabled have priority due to first pass).
175 category_group_tokens.Reset();
176 bool category_group_disabled = false;
177 while (category_group_tokens.GetNext()) {
178 std::string category_group_token = category_group_tokens.token();
179 for (StringList::const_iterator ci = excluded_categories_.begin();
180 ci != excluded_categories_.end();
181 ++ci) {
182 if (base::MatchPattern(category_group_token.c_str(), ci->c_str())) {
183 // Current token of category_group_name is present in excluded_list.
184 // Flag the exclusion and proceed further to check if any of the
185 // remaining categories of category_group_name is not present in the
186 // excluded_ list.
187 category_group_disabled = true;
188 break;
190 // One of the category of category_group_name is not present in
191 // excluded_ list. So, it has to be included_ list. Enable the
192 // category_group_name for recording.
193 category_group_disabled = false;
195 // One of the categories present in category_group_name is not present in
196 // excluded_ list. Implies this category_group_name group can be enabled
197 // for recording, since one of its groups is enabled for recording.
198 if (!category_group_disabled)
199 break;
201 // If the category group is not excluded, and there are no included patterns
202 // we consider this category group enabled, as long as it had categories
203 // other than disabled-by-default.
204 return !category_group_disabled &&
205 included_categories_.empty() && had_enabled_by_default;
208 void TraceConfig::Merge(const TraceConfig& config) {
209 if (record_mode_ != config.record_mode_
210 || enable_sampling_ != config.enable_sampling_
211 || enable_systrace_ != config.enable_systrace_
212 || enable_argument_filter_ != config.enable_argument_filter_) {
213 DLOG(ERROR) << "Attempting to merge trace config with a different "
214 << "set of options.";
217 // Keep included patterns only if both filters have an included entry.
218 // Otherwise, one of the filter was specifying "*" and we want to honor the
219 // broadest filter.
220 if (HasIncludedPatterns() && config.HasIncludedPatterns()) {
221 included_categories_.insert(included_categories_.end(),
222 config.included_categories_.begin(),
223 config.included_categories_.end());
224 } else {
225 included_categories_.clear();
228 memory_dump_config_.insert(memory_dump_config_.end(),
229 config.memory_dump_config_.begin(),
230 config.memory_dump_config_.end());
232 disabled_categories_.insert(disabled_categories_.end(),
233 config.disabled_categories_.begin(),
234 config.disabled_categories_.end());
235 excluded_categories_.insert(excluded_categories_.end(),
236 config.excluded_categories_.begin(),
237 config.excluded_categories_.end());
238 synthetic_delays_.insert(synthetic_delays_.end(),
239 config.synthetic_delays_.begin(),
240 config.synthetic_delays_.end());
243 void TraceConfig::Clear() {
244 record_mode_ = RECORD_UNTIL_FULL;
245 enable_sampling_ = false;
246 enable_systrace_ = false;
247 enable_argument_filter_ = false;
248 included_categories_.clear();
249 disabled_categories_.clear();
250 excluded_categories_.clear();
251 synthetic_delays_.clear();
252 memory_dump_config_.clear();
255 void TraceConfig::InitializeDefault() {
256 record_mode_ = RECORD_UNTIL_FULL;
257 enable_sampling_ = false;
258 enable_systrace_ = false;
259 enable_argument_filter_ = false;
260 excluded_categories_.push_back("*Debug");
261 excluded_categories_.push_back("*Test");
264 void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
265 scoped_ptr<base::Value> value(base::JSONReader::Read(config_string));
266 if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
267 InitializeDefault();
268 return;
270 scoped_ptr<base::DictionaryValue> dict(
271 static_cast<base::DictionaryValue*>(value.release()));
273 record_mode_ = RECORD_UNTIL_FULL;
274 std::string record_mode;
275 if (dict->GetString(kRecordModeParam, &record_mode)) {
276 if (record_mode == kRecordUntilFull) {
277 record_mode_ = RECORD_UNTIL_FULL;
278 } else if (record_mode == kRecordContinuously) {
279 record_mode_ = RECORD_CONTINUOUSLY;
280 } else if (record_mode == kTraceToConsole) {
281 record_mode_ = ECHO_TO_CONSOLE;
282 } else if (record_mode == kRecordAsMuchAsPossible) {
283 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
287 bool enable_sampling;
288 if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling))
289 enable_sampling_ = false;
290 else
291 enable_sampling_ = enable_sampling;
293 bool enable_systrace;
294 if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace))
295 enable_systrace_ = false;
296 else
297 enable_systrace_ = enable_systrace;
299 bool enable_argument_filter;
300 if (!dict->GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter))
301 enable_argument_filter_ = false;
302 else
303 enable_argument_filter_ = enable_argument_filter;
305 base::ListValue* category_list = nullptr;
306 if (dict->GetList(kIncludedCategoriesParam, &category_list))
307 SetCategoriesFromIncludedList(*category_list);
308 if (dict->GetList(kExcludedCategoriesParam, &category_list))
309 SetCategoriesFromExcludedList(*category_list);
310 if (dict->GetList(kSyntheticDelaysParam, &category_list))
311 SetSyntheticDelaysFromList(*category_list);
313 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
314 // If dump triggers not set, the client is using the legacy with just
315 // category enabled. So, use the default periodic dump config.
316 base::DictionaryValue* memory_dump_config = nullptr;
317 if (dict->GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
318 SetMemoryDumpConfig(*memory_dump_config);
319 else
320 SetDefaultMemoryDumpConfig();
324 void TraceConfig::InitializeFromStrings(
325 const std::string& category_filter_string,
326 const std::string& trace_options_string) {
327 if (!category_filter_string.empty()) {
328 std::vector<std::string> split = base::SplitString(
329 category_filter_string, ",", base::TRIM_WHITESPACE,
330 base::SPLIT_WANT_ALL);
331 std::vector<std::string>::iterator iter;
332 for (iter = split.begin(); iter != split.end(); ++iter) {
333 std::string category = *iter;
334 // Ignore empty categories.
335 if (category.empty())
336 continue;
337 // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
338 if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 &&
339 category.at(category.size() - 1) == ')') {
340 category = category.substr(
341 strlen(kSyntheticDelayCategoryFilterPrefix),
342 category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
343 size_t name_length = category.find(';');
344 if (name_length != std::string::npos && name_length > 0 &&
345 name_length != category.size() - 1) {
346 synthetic_delays_.push_back(category);
348 } else if (category.at(0) == '-') {
349 // Excluded categories start with '-'.
350 // Remove '-' from category string.
351 category = category.substr(1);
352 excluded_categories_.push_back(category);
353 } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
354 TRACE_DISABLED_BY_DEFAULT("")) == 0) {
355 disabled_categories_.push_back(category);
356 } else {
357 included_categories_.push_back(category);
362 record_mode_ = RECORD_UNTIL_FULL;
363 enable_sampling_ = false;
364 enable_systrace_ = false;
365 enable_argument_filter_ = false;
366 if(!trace_options_string.empty()) {
367 std::vector<std::string> split = base::SplitString(
368 trace_options_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
369 std::vector<std::string>::iterator iter;
370 for (iter = split.begin(); iter != split.end(); ++iter) {
371 if (*iter == kRecordUntilFull) {
372 record_mode_ = RECORD_UNTIL_FULL;
373 } else if (*iter == kRecordContinuously) {
374 record_mode_ = RECORD_CONTINUOUSLY;
375 } else if (*iter == kTraceToConsole) {
376 record_mode_ = ECHO_TO_CONSOLE;
377 } else if (*iter == kRecordAsMuchAsPossible) {
378 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
379 } else if (*iter == kEnableSampling) {
380 enable_sampling_ = true;
381 } else if (*iter == kEnableSystrace) {
382 enable_systrace_ = true;
383 } else if (*iter == kEnableArgumentFilter) {
384 enable_argument_filter_ = true;
389 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
390 SetDefaultMemoryDumpConfig();
394 void TraceConfig::SetCategoriesFromIncludedList(
395 const base::ListValue& included_list) {
396 included_categories_.clear();
397 for (size_t i = 0; i < included_list.GetSize(); ++i) {
398 std::string category;
399 if (!included_list.GetString(i, &category))
400 continue;
401 if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
402 TRACE_DISABLED_BY_DEFAULT("")) == 0) {
403 disabled_categories_.push_back(category);
404 } else {
405 included_categories_.push_back(category);
410 void TraceConfig::SetCategoriesFromExcludedList(
411 const base::ListValue& excluded_list) {
412 excluded_categories_.clear();
413 for (size_t i = 0; i < excluded_list.GetSize(); ++i) {
414 std::string category;
415 if (excluded_list.GetString(i, &category))
416 excluded_categories_.push_back(category);
420 void TraceConfig::SetSyntheticDelaysFromList(const base::ListValue& list) {
421 synthetic_delays_.clear();
422 for (size_t i = 0; i < list.GetSize(); ++i) {
423 std::string delay;
424 if (!list.GetString(i, &delay))
425 continue;
426 // Synthetic delays are of the form "delay;option;option;...".
427 size_t name_length = delay.find(';');
428 if (name_length != std::string::npos && name_length > 0 &&
429 name_length != delay.size() - 1) {
430 synthetic_delays_.push_back(delay);
435 void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict,
436 const char* param,
437 const StringList& categories) const {
438 if (categories.empty())
439 return;
441 scoped_ptr<base::ListValue> list(new base::ListValue());
442 for (StringList::const_iterator ci = categories.begin();
443 ci != categories.end();
444 ++ci) {
445 list->AppendString(*ci);
448 dict.Set(param, list.Pass());
451 void TraceConfig::SetMemoryDumpConfig(
452 const base::DictionaryValue& memory_dump_config) {
453 memory_dump_config_.clear();
455 const base::ListValue* trigger_list = nullptr;
456 if (!memory_dump_config.GetList(kTriggersParam, &trigger_list) ||
457 trigger_list->GetSize() == 0) {
458 return;
461 for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
462 const base::DictionaryValue* trigger = nullptr;
463 if (!trigger_list->GetDictionary(i, &trigger))
464 continue;
466 MemoryDumpTriggerConfig dump_config;
467 int interval = 0;
469 if (!trigger->GetInteger(kPeriodicIntervalParam, &interval)) {
470 continue;
472 DCHECK_GT(interval, 0);
473 dump_config.periodic_interval_ms = static_cast<uint32>(interval);
474 std::string level_of_detail_str;
475 trigger->GetString(kModeParam, &level_of_detail_str);
476 dump_config.level_of_detail =
477 StringToMemoryDumpLevelOfDetail(level_of_detail_str);
478 memory_dump_config_.push_back(dump_config);
482 void TraceConfig::SetDefaultMemoryDumpConfig() {
483 memory_dump_config_.clear();
484 memory_dump_config_.push_back(kDefaultHeavyMemoryDumpTrigger);
485 memory_dump_config_.push_back(kDefaultLightMemoryDumpTrigger);
488 void TraceConfig::ToDict(base::DictionaryValue& dict) const {
489 switch (record_mode_) {
490 case RECORD_UNTIL_FULL:
491 dict.SetString(kRecordModeParam, kRecordUntilFull);
492 break;
493 case RECORD_CONTINUOUSLY:
494 dict.SetString(kRecordModeParam, kRecordContinuously);
495 break;
496 case RECORD_AS_MUCH_AS_POSSIBLE:
497 dict.SetString(kRecordModeParam, kRecordAsMuchAsPossible);
498 break;
499 case ECHO_TO_CONSOLE:
500 dict.SetString(kRecordModeParam, kTraceToConsole);
501 break;
502 default:
503 NOTREACHED();
506 if (enable_sampling_)
507 dict.SetBoolean(kEnableSamplingParam, true);
508 else
509 dict.SetBoolean(kEnableSamplingParam, false);
511 if (enable_systrace_)
512 dict.SetBoolean(kEnableSystraceParam, true);
513 else
514 dict.SetBoolean(kEnableSystraceParam, false);
516 if (enable_argument_filter_)
517 dict.SetBoolean(kEnableArgumentFilterParam, true);
518 else
519 dict.SetBoolean(kEnableArgumentFilterParam, false);
521 StringList categories(included_categories_);
522 categories.insert(categories.end(),
523 disabled_categories_.begin(),
524 disabled_categories_.end());
525 AddCategoryToDict(dict, kIncludedCategoriesParam, categories);
526 AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_);
527 AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_);
529 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
530 scoped_ptr<base::DictionaryValue> memory_dump_config(
531 new base::DictionaryValue());
532 scoped_ptr<base::ListValue> triggers_list(new base::ListValue());
533 for (const MemoryDumpTriggerConfig& config : memory_dump_config_) {
534 scoped_ptr<base::DictionaryValue> trigger_dict(
535 new base::DictionaryValue());
536 trigger_dict->SetInteger(kPeriodicIntervalParam,
537 static_cast<int>(config.periodic_interval_ms));
538 trigger_dict->SetString(
539 kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
540 triggers_list->Append(trigger_dict.Pass());
543 // Empty triggers will still be specified explicitly since it means that
544 // the periodic dumps are not enabled.
545 memory_dump_config->Set(kTriggersParam, triggers_list.Pass());
546 dict.Set(kMemoryDumpConfigParam, memory_dump_config.Pass());
550 std::string TraceConfig::ToTraceOptionsString() const {
551 std::string ret;
552 switch (record_mode_) {
553 case RECORD_UNTIL_FULL:
554 ret = kRecordUntilFull;
555 break;
556 case RECORD_CONTINUOUSLY:
557 ret = kRecordContinuously;
558 break;
559 case RECORD_AS_MUCH_AS_POSSIBLE:
560 ret = kRecordAsMuchAsPossible;
561 break;
562 case ECHO_TO_CONSOLE:
563 ret = kTraceToConsole;
564 break;
565 default:
566 NOTREACHED();
568 if (enable_sampling_)
569 ret = ret + "," + kEnableSampling;
570 if (enable_systrace_)
571 ret = ret + "," + kEnableSystrace;
572 if (enable_argument_filter_)
573 ret = ret + "," + kEnableArgumentFilter;
574 return ret;
577 void TraceConfig::WriteCategoryFilterString(const StringList& values,
578 std::string* out,
579 bool included) const {
580 bool prepend_comma = !out->empty();
581 int token_cnt = 0;
582 for (StringList::const_iterator ci = values.begin();
583 ci != values.end(); ++ci) {
584 if (token_cnt > 0 || prepend_comma)
585 StringAppendF(out, ",");
586 StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str());
587 ++token_cnt;
591 void TraceConfig::WriteCategoryFilterString(const StringList& delays,
592 std::string* out) const {
593 bool prepend_comma = !out->empty();
594 int token_cnt = 0;
595 for (StringList::const_iterator ci = delays.begin();
596 ci != delays.end(); ++ci) {
597 if (token_cnt > 0 || prepend_comma)
598 StringAppendF(out, ",");
599 StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
600 ci->c_str());
601 ++token_cnt;
605 bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
606 StringList::const_iterator ci;
608 // Check the disabled- filters and the disabled-* wildcard first so that a
609 // "*" filter does not include the disabled.
610 for (ci = disabled_categories_.begin();
611 ci != disabled_categories_.end();
612 ++ci) {
613 if (base::MatchPattern(category_name, ci->c_str()))
614 return true;
617 if (base::MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
618 return false;
620 for (ci = included_categories_.begin();
621 ci != included_categories_.end();
622 ++ci) {
623 if (base::MatchPattern(category_name, ci->c_str()))
624 return true;
627 return false;
630 bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
631 const std::string& str) {
632 return str.empty() ||
633 str.at(0) == ' ' ||
634 str.at(str.length() - 1) == ' ';
637 bool TraceConfig::HasIncludedPatterns() const {
638 return !included_categories_.empty();
641 } // namespace trace_event
642 } // namespace base