• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "base/trace_event/trace_config.h"
6 
7 #include <stddef.h>
8 
9 #include <utility>
10 
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/pattern.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_tokenizer.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/trace_event/memory_dump_manager.h"
20 #include "base/trace_event/memory_dump_request_args.h"
21 #include "base/trace_event/trace_event.h"
22 
23 namespace base {
24 namespace trace_event {
25 
26 namespace {
27 
28 // String options that can be used to initialize TraceOptions.
29 const char kRecordUntilFull[] = "record-until-full";
30 const char kRecordContinuously[] = "record-continuously";
31 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
32 const char kTraceToConsole[] = "trace-to-console";
33 const char kEnableSampling[] = "enable-sampling";
34 const char kEnableSystrace[] = "enable-systrace";
35 const char kEnableArgumentFilter[] = "enable-argument-filter";
36 
37 // String parameters that can be used to parse the trace config string.
38 const char kRecordModeParam[] = "record_mode";
39 const char kEnableSamplingParam[] = "enable_sampling";
40 const char kEnableSystraceParam[] = "enable_systrace";
41 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
42 const char kIncludedCategoriesParam[] = "included_categories";
43 const char kExcludedCategoriesParam[] = "excluded_categories";
44 const char kSyntheticDelaysParam[] = "synthetic_delays";
45 
46 const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
47 
48 // String parameters that is used to parse memory dump config in trace config
49 // string.
50 const char kMemoryDumpConfigParam[] = "memory_dump_config";
51 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
52 const char kTriggersParam[] = "triggers";
53 const char kPeriodicIntervalParam[] = "periodic_interval_ms";
54 const char kModeParam[] = "mode";
55 const char kHeapProfilerOptions[] = "heap_profiler_options";
56 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
57 
58 // Default configuration of memory dumps.
59 const TraceConfig::MemoryDumpConfig::Trigger kDefaultHeavyMemoryDumpTrigger = {
60     2000,  // periodic_interval_ms
61     MemoryDumpLevelOfDetail::DETAILED};
62 const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
63     250,  // periodic_interval_ms
64     MemoryDumpLevelOfDetail::LIGHT};
65 
66 class ConvertableTraceConfigToTraceFormat
67     : public base::trace_event::ConvertableToTraceFormat {
68  public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)69   explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
70       : trace_config_(trace_config) {}
~ConvertableTraceConfigToTraceFormat()71   ~ConvertableTraceConfigToTraceFormat() override {}
72 
AppendAsTraceFormat(std::string * out) const73   void AppendAsTraceFormat(std::string* out) const override {
74     out->append(trace_config_.ToString());
75   }
76 
77  private:
78   const TraceConfig trace_config_;
79 };
80 
GetDefaultAllowedMemoryDumpModes()81 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
82   std::set<MemoryDumpLevelOfDetail> all_modes;
83   for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
84        mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
85     all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
86   }
87   return all_modes;
88 }
89 
90 }  // namespace
91 
HeapProfiler()92 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
93     : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
94 
Clear()95 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
96   breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
97 }
98 
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)99 void TraceConfig::ResetMemoryDumpConfig(
100     const TraceConfig::MemoryDumpConfig& memory_dump_config) {
101   memory_dump_config_.Clear();
102   memory_dump_config_ = memory_dump_config;
103 }
104 
MemoryDumpConfig()105 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() {}
106 
107 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
108     const MemoryDumpConfig& other) = default;
109 
~MemoryDumpConfig()110 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() {}
111 
Clear()112 void TraceConfig::MemoryDumpConfig::Clear() {
113   allowed_dump_modes.clear();
114   triggers.clear();
115   heap_profiler_options.Clear();
116 }
117 
TraceConfig()118 TraceConfig::TraceConfig() {
119   InitializeDefault();
120 }
121 
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)122 TraceConfig::TraceConfig(StringPiece category_filter_string,
123                          StringPiece trace_options_string) {
124   InitializeFromStrings(category_filter_string, trace_options_string);
125 }
126 
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)127 TraceConfig::TraceConfig(StringPiece category_filter_string,
128                          TraceRecordMode record_mode) {
129   std::string trace_options_string;
130   switch (record_mode) {
131     case RECORD_UNTIL_FULL:
132       trace_options_string = kRecordUntilFull;
133       break;
134     case RECORD_CONTINUOUSLY:
135       trace_options_string = kRecordContinuously;
136       break;
137     case RECORD_AS_MUCH_AS_POSSIBLE:
138       trace_options_string = kRecordAsMuchAsPossible;
139       break;
140     case ECHO_TO_CONSOLE:
141       trace_options_string = kTraceToConsole;
142       break;
143     default:
144       NOTREACHED();
145   }
146   InitializeFromStrings(category_filter_string, trace_options_string);
147 }
148 
TraceConfig(const DictionaryValue & config)149 TraceConfig::TraceConfig(const DictionaryValue& config) {
150   InitializeFromConfigDict(config);
151 }
152 
TraceConfig(StringPiece config_string)153 TraceConfig::TraceConfig(StringPiece config_string) {
154   if (!config_string.empty())
155     InitializeFromConfigString(config_string);
156   else
157     InitializeDefault();
158 }
159 
TraceConfig(const TraceConfig & tc)160 TraceConfig::TraceConfig(const TraceConfig& tc)
161     : record_mode_(tc.record_mode_),
162       enable_sampling_(tc.enable_sampling_),
163       enable_systrace_(tc.enable_systrace_),
164       enable_argument_filter_(tc.enable_argument_filter_),
165       memory_dump_config_(tc.memory_dump_config_),
166       included_categories_(tc.included_categories_),
167       disabled_categories_(tc.disabled_categories_),
168       excluded_categories_(tc.excluded_categories_),
169       synthetic_delays_(tc.synthetic_delays_) {}
170 
~TraceConfig()171 TraceConfig::~TraceConfig() {
172 }
173 
operator =(const TraceConfig & rhs)174 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
175   if (this == &rhs)
176     return *this;
177 
178   record_mode_ = rhs.record_mode_;
179   enable_sampling_ = rhs.enable_sampling_;
180   enable_systrace_ = rhs.enable_systrace_;
181   enable_argument_filter_ = rhs.enable_argument_filter_;
182   memory_dump_config_ = rhs.memory_dump_config_;
183   included_categories_ = rhs.included_categories_;
184   disabled_categories_ = rhs.disabled_categories_;
185   excluded_categories_ = rhs.excluded_categories_;
186   synthetic_delays_ = rhs.synthetic_delays_;
187   return *this;
188 }
189 
GetSyntheticDelayValues() const190 const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
191   return synthetic_delays_;
192 }
193 
ToString() const194 std::string TraceConfig::ToString() const {
195   std::unique_ptr<DictionaryValue> dict = ToDict();
196   std::string json;
197   JSONWriter::Write(*dict, &json);
198   return json;
199 }
200 
201 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const202 TraceConfig::AsConvertableToTraceFormat() const {
203   return WrapUnique(new ConvertableTraceConfigToTraceFormat(*this));
204 }
205 
ToCategoryFilterString() const206 std::string TraceConfig::ToCategoryFilterString() const {
207   std::string filter_string;
208   WriteCategoryFilterString(included_categories_, &filter_string, true);
209   WriteCategoryFilterString(disabled_categories_, &filter_string, true);
210   WriteCategoryFilterString(excluded_categories_, &filter_string, false);
211   WriteCategoryFilterString(synthetic_delays_, &filter_string);
212   return filter_string;
213 }
214 
IsCategoryGroupEnabled(const char * category_group_name) const215 bool TraceConfig::IsCategoryGroupEnabled(
216     const char* category_group_name) const {
217   // TraceLog should call this method only as part of enabling/disabling
218   // categories.
219 
220   bool had_enabled_by_default = false;
221   DCHECK(category_group_name);
222   std::string category_group_name_str = category_group_name;
223   StringTokenizer category_group_tokens(category_group_name_str, ",");
224   while (category_group_tokens.GetNext()) {
225     std::string category_group_token = category_group_tokens.token();
226     // Don't allow empty tokens, nor tokens with leading or trailing space.
227     DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
228                category_group_token))
229         << "Disallowed category string";
230     if (IsCategoryEnabled(category_group_token.c_str()))
231       return true;
232 
233     if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*")))
234       had_enabled_by_default = true;
235   }
236   // Do a second pass to check for explicitly disabled categories
237   // (those explicitly enabled have priority due to first pass).
238   category_group_tokens.Reset();
239   bool category_group_disabled = false;
240   while (category_group_tokens.GetNext()) {
241     std::string category_group_token = category_group_tokens.token();
242     for (const std::string& category : excluded_categories_) {
243       if (MatchPattern(category_group_token, category)) {
244         // Current token of category_group_name is present in excluded_list.
245         // Flag the exclusion and proceed further to check if any of the
246         // remaining categories of category_group_name is not present in the
247         // excluded_ list.
248         category_group_disabled = true;
249         break;
250       }
251       // One of the category of category_group_name is not present in
252       // excluded_ list. So, if it's not a disabled-by-default category,
253       // it has to be included_ list. Enable the category_group_name
254       // for recording.
255       if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*"))) {
256         category_group_disabled = false;
257       }
258     }
259     // One of the categories present in category_group_name is not present in
260     // excluded_ list. Implies this category_group_name group can be enabled
261     // for recording, since one of its groups is enabled for recording.
262     if (!category_group_disabled)
263       break;
264   }
265   // If the category group is not excluded, and there are no included patterns
266   // we consider this category group enabled, as long as it had categories
267   // other than disabled-by-default.
268   return !category_group_disabled && had_enabled_by_default &&
269          included_categories_.empty();
270 }
271 
Merge(const TraceConfig & config)272 void TraceConfig::Merge(const TraceConfig& config) {
273   if (record_mode_ != config.record_mode_
274       || enable_sampling_ != config.enable_sampling_
275       || enable_systrace_ != config.enable_systrace_
276       || enable_argument_filter_ != config.enable_argument_filter_) {
277     DLOG(ERROR) << "Attempting to merge trace config with a different "
278                 << "set of options.";
279   }
280 
281   // Keep included patterns only if both filters have an included entry.
282   // Otherwise, one of the filter was specifying "*" and we want to honor the
283   // broadest filter.
284   if (HasIncludedPatterns() && config.HasIncludedPatterns()) {
285     included_categories_.insert(included_categories_.end(),
286                                 config.included_categories_.begin(),
287                                 config.included_categories_.end());
288   } else {
289     included_categories_.clear();
290   }
291 
292   memory_dump_config_.triggers.insert(memory_dump_config_.triggers.end(),
293                              config.memory_dump_config_.triggers.begin(),
294                              config.memory_dump_config_.triggers.end());
295 
296   disabled_categories_.insert(disabled_categories_.end(),
297                               config.disabled_categories_.begin(),
298                               config.disabled_categories_.end());
299   excluded_categories_.insert(excluded_categories_.end(),
300                               config.excluded_categories_.begin(),
301                               config.excluded_categories_.end());
302   synthetic_delays_.insert(synthetic_delays_.end(),
303                            config.synthetic_delays_.begin(),
304                            config.synthetic_delays_.end());
305 }
306 
Clear()307 void TraceConfig::Clear() {
308   record_mode_ = RECORD_UNTIL_FULL;
309   enable_sampling_ = false;
310   enable_systrace_ = false;
311   enable_argument_filter_ = false;
312   included_categories_.clear();
313   disabled_categories_.clear();
314   excluded_categories_.clear();
315   synthetic_delays_.clear();
316   memory_dump_config_.Clear();
317 }
318 
InitializeDefault()319 void TraceConfig::InitializeDefault() {
320   record_mode_ = RECORD_UNTIL_FULL;
321   enable_sampling_ = false;
322   enable_systrace_ = false;
323   enable_argument_filter_ = false;
324 }
325 
InitializeFromConfigDict(const DictionaryValue & dict)326 void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
327   record_mode_ = RECORD_UNTIL_FULL;
328   std::string record_mode;
329   if (dict.GetString(kRecordModeParam, &record_mode)) {
330     if (record_mode == kRecordUntilFull) {
331       record_mode_ = RECORD_UNTIL_FULL;
332     } else if (record_mode == kRecordContinuously) {
333       record_mode_ = RECORD_CONTINUOUSLY;
334     } else if (record_mode == kTraceToConsole) {
335       record_mode_ = ECHO_TO_CONSOLE;
336     } else if (record_mode == kRecordAsMuchAsPossible) {
337       record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
338     }
339   }
340 
341   bool val;
342   enable_sampling_ = dict.GetBoolean(kEnableSamplingParam, &val) ? val : false;
343   enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
344   enable_argument_filter_ =
345       dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
346 
347   const ListValue* category_list = nullptr;
348   if (dict.GetList(kIncludedCategoriesParam, &category_list))
349     SetCategoriesFromIncludedList(*category_list);
350   if (dict.GetList(kExcludedCategoriesParam, &category_list))
351     SetCategoriesFromExcludedList(*category_list);
352   if (dict.GetList(kSyntheticDelaysParam, &category_list))
353     SetSyntheticDelaysFromList(*category_list);
354 
355   if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
356     // If dump triggers not set, the client is using the legacy with just
357     // category enabled. So, use the default periodic dump config.
358     const DictionaryValue* memory_dump_config = nullptr;
359     if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
360       SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
361     else
362       SetDefaultMemoryDumpConfig();
363   }
364 }
365 
InitializeFromConfigString(StringPiece config_string)366 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
367   auto dict = DictionaryValue::From(JSONReader::Read(config_string));
368   if (dict)
369     InitializeFromConfigDict(*dict);
370   else
371     InitializeDefault();
372 }
373 
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)374 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
375                                         StringPiece trace_options_string) {
376   if (!category_filter_string.empty()) {
377     std::vector<std::string> split = SplitString(
378         category_filter_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
379     for (const std::string& category : split) {
380       // Ignore empty categories.
381       if (category.empty())
382         continue;
383       // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
384       if (StartsWith(category, kSyntheticDelayCategoryFilterPrefix,
385                      CompareCase::SENSITIVE) &&
386           category.back() == ')') {
387         std::string synthetic_category = category.substr(
388             strlen(kSyntheticDelayCategoryFilterPrefix),
389             category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
390         size_t name_length = synthetic_category.find(';');
391         if (name_length != std::string::npos && name_length > 0 &&
392             name_length != synthetic_category.size() - 1) {
393           synthetic_delays_.push_back(synthetic_category);
394         }
395       } else if (category.front() == '-') {
396         // Excluded categories start with '-'.
397         // Remove '-' from category string.
398         excluded_categories_.push_back(category.substr(1));
399       } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
400                                   TRACE_DISABLED_BY_DEFAULT("")) == 0) {
401         disabled_categories_.push_back(category);
402       } else {
403         included_categories_.push_back(category);
404       }
405     }
406   }
407 
408   record_mode_ = RECORD_UNTIL_FULL;
409   enable_sampling_ = false;
410   enable_systrace_ = false;
411   enable_argument_filter_ = false;
412   if (!trace_options_string.empty()) {
413     std::vector<std::string> split =
414         SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
415     for (const std::string& token : split) {
416       if (token == kRecordUntilFull) {
417         record_mode_ = RECORD_UNTIL_FULL;
418       } else if (token == kRecordContinuously) {
419         record_mode_ = RECORD_CONTINUOUSLY;
420       } else if (token == kTraceToConsole) {
421         record_mode_ = ECHO_TO_CONSOLE;
422       } else if (token == kRecordAsMuchAsPossible) {
423         record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
424       } else if (token == kEnableSampling) {
425         enable_sampling_ = true;
426       } else if (token == kEnableSystrace) {
427         enable_systrace_ = true;
428       } else if (token == kEnableArgumentFilter) {
429         enable_argument_filter_ = true;
430       }
431     }
432   }
433 
434   if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
435     SetDefaultMemoryDumpConfig();
436   }
437 }
438 
SetCategoriesFromIncludedList(const ListValue & included_list)439 void TraceConfig::SetCategoriesFromIncludedList(
440     const ListValue& included_list) {
441   included_categories_.clear();
442   for (size_t i = 0; i < included_list.GetSize(); ++i) {
443     std::string category;
444     if (!included_list.GetString(i, &category))
445       continue;
446     if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
447                          TRACE_DISABLED_BY_DEFAULT("")) == 0) {
448       disabled_categories_.push_back(category);
449     } else {
450       included_categories_.push_back(category);
451     }
452   }
453 }
454 
SetCategoriesFromExcludedList(const ListValue & excluded_list)455 void TraceConfig::SetCategoriesFromExcludedList(
456     const ListValue& excluded_list) {
457   excluded_categories_.clear();
458   for (size_t i = 0; i < excluded_list.GetSize(); ++i) {
459     std::string category;
460     if (excluded_list.GetString(i, &category))
461       excluded_categories_.push_back(category);
462   }
463 }
464 
SetSyntheticDelaysFromList(const ListValue & list)465 void TraceConfig::SetSyntheticDelaysFromList(const ListValue& list) {
466   synthetic_delays_.clear();
467   for (size_t i = 0; i < list.GetSize(); ++i) {
468     std::string delay;
469     if (!list.GetString(i, &delay))
470       continue;
471     // Synthetic delays are of the form "delay;option;option;...".
472     size_t name_length = delay.find(';');
473     if (name_length != std::string::npos && name_length > 0 &&
474         name_length != delay.size() - 1) {
475       synthetic_delays_.push_back(delay);
476     }
477   }
478 }
479 
AddCategoryToDict(DictionaryValue * dict,const char * param,const StringList & categories) const480 void TraceConfig::AddCategoryToDict(DictionaryValue* dict,
481                                     const char* param,
482                                     const StringList& categories) const {
483   if (categories.empty())
484     return;
485 
486   auto list = MakeUnique<ListValue>();
487   for (const std::string& category : categories)
488     list->AppendString(category);
489   dict->Set(param, std::move(list));
490 }
491 
SetMemoryDumpConfigFromConfigDict(const DictionaryValue & memory_dump_config)492 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
493     const DictionaryValue& memory_dump_config) {
494   // Set allowed dump modes.
495   memory_dump_config_.allowed_dump_modes.clear();
496   const ListValue* allowed_modes_list;
497   if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
498     for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
499       std::string level_of_detail_str;
500       allowed_modes_list->GetString(i, &level_of_detail_str);
501       memory_dump_config_.allowed_dump_modes.insert(
502           StringToMemoryDumpLevelOfDetail(level_of_detail_str));
503     }
504   } else {
505     // If allowed modes param is not given then allow all modes by default.
506     memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
507   }
508 
509   // Set triggers
510   memory_dump_config_.triggers.clear();
511   const ListValue* trigger_list = nullptr;
512   if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
513       trigger_list->GetSize() > 0) {
514     for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
515       const DictionaryValue* trigger = nullptr;
516       if (!trigger_list->GetDictionary(i, &trigger))
517         continue;
518 
519       int interval = 0;
520       if (!trigger->GetInteger(kPeriodicIntervalParam, &interval))
521         continue;
522 
523       DCHECK_GT(interval, 0);
524       MemoryDumpConfig::Trigger dump_config;
525       dump_config.periodic_interval_ms = static_cast<uint32_t>(interval);
526       std::string level_of_detail_str;
527       trigger->GetString(kModeParam, &level_of_detail_str);
528       dump_config.level_of_detail =
529           StringToMemoryDumpLevelOfDetail(level_of_detail_str);
530       memory_dump_config_.triggers.push_back(dump_config);
531     }
532   }
533 
534   // Set heap profiler options
535   const DictionaryValue* heap_profiler_options = nullptr;
536   if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
537                                        &heap_profiler_options)) {
538     int min_size_bytes = 0;
539     if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
540                                          &min_size_bytes)
541         && min_size_bytes >= 0) {
542       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
543           static_cast<size_t>(min_size_bytes);
544     } else {
545       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
546           MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
547     }
548   }
549 }
550 
SetDefaultMemoryDumpConfig()551 void TraceConfig::SetDefaultMemoryDumpConfig() {
552   memory_dump_config_.Clear();
553   memory_dump_config_.triggers.push_back(kDefaultHeavyMemoryDumpTrigger);
554   memory_dump_config_.triggers.push_back(kDefaultLightMemoryDumpTrigger);
555   memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
556 }
557 
ToDict() const558 std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
559   auto dict = MakeUnique<DictionaryValue>();
560   switch (record_mode_) {
561     case RECORD_UNTIL_FULL:
562       dict->SetString(kRecordModeParam, kRecordUntilFull);
563       break;
564     case RECORD_CONTINUOUSLY:
565       dict->SetString(kRecordModeParam, kRecordContinuously);
566       break;
567     case RECORD_AS_MUCH_AS_POSSIBLE:
568       dict->SetString(kRecordModeParam, kRecordAsMuchAsPossible);
569       break;
570     case ECHO_TO_CONSOLE:
571       dict->SetString(kRecordModeParam, kTraceToConsole);
572       break;
573     default:
574       NOTREACHED();
575   }
576 
577   dict->SetBoolean(kEnableSamplingParam, enable_sampling_);
578   dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
579   dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
580 
581   StringList categories(included_categories_);
582   categories.insert(categories.end(),
583                     disabled_categories_.begin(),
584                     disabled_categories_.end());
585   AddCategoryToDict(dict.get(), kIncludedCategoriesParam, categories);
586   AddCategoryToDict(dict.get(), kExcludedCategoriesParam, excluded_categories_);
587   AddCategoryToDict(dict.get(), kSyntheticDelaysParam, synthetic_delays_);
588 
589   if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
590     auto allowed_modes = MakeUnique<ListValue>();
591     for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
592       allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
593 
594     auto memory_dump_config = MakeUnique<DictionaryValue>();
595     memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
596 
597     auto triggers_list = MakeUnique<ListValue>();
598     for (const auto& config : memory_dump_config_.triggers) {
599       auto trigger_dict = MakeUnique<DictionaryValue>();
600       trigger_dict->SetInteger(kPeriodicIntervalParam,
601                                static_cast<int>(config.periodic_interval_ms));
602       trigger_dict->SetString(
603           kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
604       triggers_list->Append(std::move(trigger_dict));
605     }
606 
607     // Empty triggers will still be specified explicitly since it means that
608     // the periodic dumps are not enabled.
609     memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
610 
611     if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
612         MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
613       auto options = MakeUnique<DictionaryValue>();
614       options->SetInteger(
615           kBreakdownThresholdBytes,
616           memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
617       memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
618     }
619     dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
620   }
621   return dict;
622 }
623 
ToTraceOptionsString() const624 std::string TraceConfig::ToTraceOptionsString() const {
625   std::string ret;
626   switch (record_mode_) {
627     case RECORD_UNTIL_FULL:
628       ret = kRecordUntilFull;
629       break;
630     case RECORD_CONTINUOUSLY:
631       ret = kRecordContinuously;
632       break;
633     case RECORD_AS_MUCH_AS_POSSIBLE:
634       ret = kRecordAsMuchAsPossible;
635       break;
636     case ECHO_TO_CONSOLE:
637       ret = kTraceToConsole;
638       break;
639     default:
640       NOTREACHED();
641   }
642   if (enable_sampling_)
643     ret = ret + "," + kEnableSampling;
644   if (enable_systrace_)
645     ret = ret + "," + kEnableSystrace;
646   if (enable_argument_filter_)
647     ret = ret + "," + kEnableArgumentFilter;
648   return ret;
649 }
650 
WriteCategoryFilterString(const StringList & values,std::string * out,bool included) const651 void TraceConfig::WriteCategoryFilterString(const StringList& values,
652                                             std::string* out,
653                                             bool included) const {
654   bool prepend_comma = !out->empty();
655   int token_cnt = 0;
656   for (const std::string& category : values) {
657     if (token_cnt > 0 || prepend_comma)
658       StringAppendF(out, ",");
659     StringAppendF(out, "%s%s", (included ? "" : "-"), category.c_str());
660     ++token_cnt;
661   }
662 }
663 
WriteCategoryFilterString(const StringList & delays,std::string * out) const664 void TraceConfig::WriteCategoryFilterString(const StringList& delays,
665                                             std::string* out) const {
666   bool prepend_comma = !out->empty();
667   int token_cnt = 0;
668   for (const std::string& category : delays) {
669     if (token_cnt > 0 || prepend_comma)
670       StringAppendF(out, ",");
671     StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
672                   category.c_str());
673     ++token_cnt;
674   }
675 }
676 
IsCategoryEnabled(const char * category_name) const677 bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
678   // Check the disabled- filters and the disabled-* wildcard first so that a
679   // "*" filter does not include the disabled.
680   for (const std::string& category : disabled_categories_) {
681     if (MatchPattern(category_name, category))
682       return true;
683   }
684 
685   if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
686     return false;
687 
688   for (const std::string& category : included_categories_) {
689     if (MatchPattern(category_name, category))
690       return true;
691   }
692 
693   return false;
694 }
695 
IsEmptyOrContainsLeadingOrTrailingWhitespace(StringPiece str)696 bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
697     StringPiece str) {
698   return str.empty() || str.front() == ' ' || str.back() == ' ';
699 }
700 
HasIncludedPatterns() const701 bool TraceConfig::HasIncludedPatterns() const {
702   return !included_categories_.empty();
703 }
704 
705 }  // namespace trace_event
706 }  // namespace base
707