• 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/string_split.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/memory_dump_request_args.h"
17 #include "base/trace_event/trace_event.h"
18 
19 namespace base {
20 namespace trace_event {
21 
22 namespace {
23 
24 // String options that can be used to initialize TraceOptions.
25 const char kRecordUntilFull[] = "record-until-full";
26 const char kRecordContinuously[] = "record-continuously";
27 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
28 const char kTraceToConsole[] = "trace-to-console";
29 const char kEnableSystrace[] = "enable-systrace";
30 const char kEnableArgumentFilter[] = "enable-argument-filter";
31 
32 // String parameters that can be used to parse the trace config string.
33 const char kRecordModeParam[] = "record_mode";
34 const char kEnableSystraceParam[] = "enable_systrace";
35 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
36 
37 // String parameters that is used to parse memory dump config in trace config
38 // string.
39 const char kMemoryDumpConfigParam[] = "memory_dump_config";
40 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
41 const char kTriggersParam[] = "triggers";
42 const char kTriggerModeParam[] = "mode";
43 const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
44 const char kTriggerTypeParam[] = "type";
45 const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
46 const char kHeapProfilerOptions[] = "heap_profiler_options";
47 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
48 
49 // String parameters used to parse category event filters.
50 const char kEventFiltersParam[] = "event_filters";
51 const char kFilterPredicateParam[] = "filter_predicate";
52 const char kFilterArgsParam[] = "filter_args";
53 
54 // Default configuration of memory dumps.
55 const TraceConfig::MemoryDumpConfig::Trigger kDefaultHeavyMemoryDumpTrigger = {
56     2000,  // min_time_between_dumps_ms
57     MemoryDumpLevelOfDetail::DETAILED, MemoryDumpType::PERIODIC_INTERVAL};
58 const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
59     250,  // min_time_between_dumps_ms
60     MemoryDumpLevelOfDetail::LIGHT, MemoryDumpType::PERIODIC_INTERVAL};
61 
62 class ConvertableTraceConfigToTraceFormat
63     : public base::trace_event::ConvertableToTraceFormat {
64  public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)65   explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
66       : trace_config_(trace_config) {}
67 
~ConvertableTraceConfigToTraceFormat()68   ~ConvertableTraceConfigToTraceFormat() override {}
69 
AppendAsTraceFormat(std::string * out) const70   void AppendAsTraceFormat(std::string* out) const override {
71     out->append(trace_config_.ToString());
72   }
73 
74  private:
75   const TraceConfig trace_config_;
76 };
77 
GetDefaultAllowedMemoryDumpModes()78 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
79   std::set<MemoryDumpLevelOfDetail> all_modes;
80   for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
81        mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
82     all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
83   }
84   return all_modes;
85 }
86 
87 }  // namespace
88 
HeapProfiler()89 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
90     : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
91 
Clear()92 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
93   breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
94 }
95 
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)96 void TraceConfig::ResetMemoryDumpConfig(
97     const TraceConfig::MemoryDumpConfig& memory_dump_config) {
98   memory_dump_config_.Clear();
99   memory_dump_config_ = memory_dump_config;
100 }
101 
MemoryDumpConfig()102 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() {}
103 
104 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
105     const MemoryDumpConfig& other) = default;
106 
~MemoryDumpConfig()107 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() {}
108 
Clear()109 void TraceConfig::MemoryDumpConfig::Clear() {
110   allowed_dump_modes.clear();
111   triggers.clear();
112   heap_profiler_options.Clear();
113 }
114 
Merge(const TraceConfig::MemoryDumpConfig & config)115 void TraceConfig::MemoryDumpConfig::Merge(
116     const TraceConfig::MemoryDumpConfig& config) {
117   triggers.insert(triggers.end(), config.triggers.begin(),
118                   config.triggers.end());
119   allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
120                             config.allowed_dump_modes.end());
121   heap_profiler_options.breakdown_threshold_bytes =
122       std::min(heap_profiler_options.breakdown_threshold_bytes,
123                config.heap_profiler_options.breakdown_threshold_bytes);
124 }
125 
EventFilterConfig(const std::string & predicate_name)126 TraceConfig::EventFilterConfig::EventFilterConfig(
127     const std::string& predicate_name)
128     : predicate_name_(predicate_name) {}
129 
~EventFilterConfig()130 TraceConfig::EventFilterConfig::~EventFilterConfig() {}
131 
EventFilterConfig(const EventFilterConfig & tc)132 TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
133   *this = tc;
134 }
135 
operator =(const TraceConfig::EventFilterConfig & rhs)136 TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
137     const TraceConfig::EventFilterConfig& rhs) {
138   if (this == &rhs)
139     return *this;
140 
141   predicate_name_ = rhs.predicate_name_;
142   category_filter_ = rhs.category_filter_;
143 
144   if (rhs.args_)
145     args_ = rhs.args_->CreateDeepCopy();
146 
147   return *this;
148 }
149 
InitializeFromConfigDict(const base::DictionaryValue * event_filter)150 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
151     const base::DictionaryValue* event_filter) {
152   category_filter_.InitializeFromConfigDict(*event_filter);
153 
154   const base::DictionaryValue* args_dict = nullptr;
155   if (event_filter->GetDictionary(kFilterArgsParam, &args_dict))
156     args_ = args_dict->CreateDeepCopy();
157 }
158 
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)159 void TraceConfig::EventFilterConfig::SetCategoryFilter(
160     const TraceConfigCategoryFilter& category_filter) {
161   category_filter_ = category_filter;
162 }
163 
ToDict(DictionaryValue * filter_dict) const164 void TraceConfig::EventFilterConfig::ToDict(
165     DictionaryValue* filter_dict) const {
166   filter_dict->SetString(kFilterPredicateParam, predicate_name());
167 
168   category_filter_.ToDict(filter_dict);
169 
170   if (args_)
171     filter_dict->Set(kFilterArgsParam, args_->CreateDeepCopy());
172 }
173 
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const174 bool TraceConfig::EventFilterConfig::GetArgAsSet(
175     const char* key,
176     std::unordered_set<std::string>* out_set) const {
177   const ListValue* list = nullptr;
178   if (!args_->GetList(key, &list))
179     return false;
180   for (size_t i = 0; i < list->GetSize(); ++i) {
181     std::string value;
182     if (list->GetString(i, &value))
183       out_set->insert(value);
184   }
185   return true;
186 }
187 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const188 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
189     const StringPiece& category_group_name) const {
190   return category_filter_.IsCategoryGroupEnabled(category_group_name);
191 }
192 
TraceConfig()193 TraceConfig::TraceConfig() {
194   InitializeDefault();
195 }
196 
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)197 TraceConfig::TraceConfig(StringPiece category_filter_string,
198                          StringPiece trace_options_string) {
199   InitializeFromStrings(category_filter_string, trace_options_string);
200 }
201 
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)202 TraceConfig::TraceConfig(StringPiece category_filter_string,
203                          TraceRecordMode record_mode) {
204   std::string trace_options_string;
205   switch (record_mode) {
206     case RECORD_UNTIL_FULL:
207       trace_options_string = kRecordUntilFull;
208       break;
209     case RECORD_CONTINUOUSLY:
210       trace_options_string = kRecordContinuously;
211       break;
212     case RECORD_AS_MUCH_AS_POSSIBLE:
213       trace_options_string = kRecordAsMuchAsPossible;
214       break;
215     case ECHO_TO_CONSOLE:
216       trace_options_string = kTraceToConsole;
217       break;
218     default:
219       NOTREACHED();
220   }
221   InitializeFromStrings(category_filter_string, trace_options_string);
222 }
223 
TraceConfig(const DictionaryValue & config)224 TraceConfig::TraceConfig(const DictionaryValue& config) {
225   InitializeFromConfigDict(config);
226 }
227 
TraceConfig(StringPiece config_string)228 TraceConfig::TraceConfig(StringPiece config_string) {
229   if (!config_string.empty())
230     InitializeFromConfigString(config_string);
231   else
232     InitializeDefault();
233 }
234 
TraceConfig(const TraceConfig & tc)235 TraceConfig::TraceConfig(const TraceConfig& tc)
236     : record_mode_(tc.record_mode_),
237       enable_systrace_(tc.enable_systrace_),
238       enable_argument_filter_(tc.enable_argument_filter_),
239       category_filter_(tc.category_filter_),
240       memory_dump_config_(tc.memory_dump_config_),
241       event_filters_(tc.event_filters_) {}
242 
~TraceConfig()243 TraceConfig::~TraceConfig() {
244 }
245 
operator =(const TraceConfig & rhs)246 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
247   if (this == &rhs)
248     return *this;
249 
250   record_mode_ = rhs.record_mode_;
251   enable_systrace_ = rhs.enable_systrace_;
252   enable_argument_filter_ = rhs.enable_argument_filter_;
253   category_filter_ = rhs.category_filter_;
254   memory_dump_config_ = rhs.memory_dump_config_;
255   event_filters_ = rhs.event_filters_;
256   return *this;
257 }
258 
GetSyntheticDelayValues() const259 const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
260   return category_filter_.synthetic_delays();
261 }
262 
ToString() const263 std::string TraceConfig::ToString() const {
264   std::unique_ptr<DictionaryValue> dict = ToDict();
265   std::string json;
266   JSONWriter::Write(*dict, &json);
267   return json;
268 }
269 
270 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const271 TraceConfig::AsConvertableToTraceFormat() const {
272   return MakeUnique<ConvertableTraceConfigToTraceFormat>(*this);
273 }
274 
ToCategoryFilterString() const275 std::string TraceConfig::ToCategoryFilterString() const {
276   return category_filter_.ToFilterString();
277 }
278 
IsCategoryGroupEnabled(const StringPiece & category_group_name) const279 bool TraceConfig::IsCategoryGroupEnabled(
280     const StringPiece& category_group_name) const {
281   // TraceLog should call this method only as part of enabling/disabling
282   // categories.
283   return category_filter_.IsCategoryGroupEnabled(category_group_name);
284 }
285 
Merge(const TraceConfig & config)286 void TraceConfig::Merge(const TraceConfig& config) {
287   if (record_mode_ != config.record_mode_
288       || enable_systrace_ != config.enable_systrace_
289       || enable_argument_filter_ != config.enable_argument_filter_) {
290     DLOG(ERROR) << "Attempting to merge trace config with a different "
291                 << "set of options.";
292   }
293 
294   category_filter_.Merge(config.category_filter_);
295 
296   memory_dump_config_.Merge(config.memory_dump_config_);
297 
298   event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
299                         config.event_filters().end());
300 }
301 
Clear()302 void TraceConfig::Clear() {
303   record_mode_ = RECORD_UNTIL_FULL;
304   enable_systrace_ = false;
305   enable_argument_filter_ = false;
306   category_filter_.Clear();
307   memory_dump_config_.Clear();
308   event_filters_.clear();
309 }
310 
InitializeDefault()311 void TraceConfig::InitializeDefault() {
312   record_mode_ = RECORD_UNTIL_FULL;
313   enable_systrace_ = false;
314   enable_argument_filter_ = false;
315 }
316 
InitializeFromConfigDict(const DictionaryValue & dict)317 void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
318   record_mode_ = RECORD_UNTIL_FULL;
319   std::string record_mode;
320   if (dict.GetString(kRecordModeParam, &record_mode)) {
321     if (record_mode == kRecordUntilFull) {
322       record_mode_ = RECORD_UNTIL_FULL;
323     } else if (record_mode == kRecordContinuously) {
324       record_mode_ = RECORD_CONTINUOUSLY;
325     } else if (record_mode == kTraceToConsole) {
326       record_mode_ = ECHO_TO_CONSOLE;
327     } else if (record_mode == kRecordAsMuchAsPossible) {
328       record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
329     }
330   }
331 
332   bool val;
333   enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
334   enable_argument_filter_ =
335       dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
336 
337   category_filter_.InitializeFromConfigDict(dict);
338 
339   const base::ListValue* category_event_filters = nullptr;
340   if (dict.GetList(kEventFiltersParam, &category_event_filters))
341     SetEventFiltersFromConfigList(*category_event_filters);
342 
343   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
344     // If dump triggers not set, the client is using the legacy with just
345     // category enabled. So, use the default periodic dump config.
346     const DictionaryValue* memory_dump_config = nullptr;
347     if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
348       SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
349     else
350       SetDefaultMemoryDumpConfig();
351   }
352 }
353 
InitializeFromConfigString(StringPiece config_string)354 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
355   auto dict = DictionaryValue::From(JSONReader::Read(config_string));
356   if (dict)
357     InitializeFromConfigDict(*dict);
358   else
359     InitializeDefault();
360 }
361 
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)362 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
363                                         StringPiece trace_options_string) {
364   if (!category_filter_string.empty())
365     category_filter_.InitializeFromString(category_filter_string);
366 
367   record_mode_ = RECORD_UNTIL_FULL;
368   enable_systrace_ = false;
369   enable_argument_filter_ = false;
370   if (!trace_options_string.empty()) {
371     std::vector<std::string> split =
372         SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
373     for (const std::string& token : split) {
374       if (token == kRecordUntilFull) {
375         record_mode_ = RECORD_UNTIL_FULL;
376       } else if (token == kRecordContinuously) {
377         record_mode_ = RECORD_CONTINUOUSLY;
378       } else if (token == kTraceToConsole) {
379         record_mode_ = ECHO_TO_CONSOLE;
380       } else if (token == kRecordAsMuchAsPossible) {
381         record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
382       } else if (token == kEnableSystrace) {
383         enable_systrace_ = true;
384       } else if (token == kEnableArgumentFilter) {
385         enable_argument_filter_ = true;
386       }
387     }
388   }
389 
390   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
391     SetDefaultMemoryDumpConfig();
392   }
393 }
394 
SetMemoryDumpConfigFromConfigDict(const DictionaryValue & memory_dump_config)395 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
396     const DictionaryValue& memory_dump_config) {
397   // Set allowed dump modes.
398   memory_dump_config_.allowed_dump_modes.clear();
399   const ListValue* allowed_modes_list;
400   if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
401     for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
402       std::string level_of_detail_str;
403       allowed_modes_list->GetString(i, &level_of_detail_str);
404       memory_dump_config_.allowed_dump_modes.insert(
405           StringToMemoryDumpLevelOfDetail(level_of_detail_str));
406     }
407   } else {
408     // If allowed modes param is not given then allow all modes by default.
409     memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
410   }
411 
412   // Set triggers
413   memory_dump_config_.triggers.clear();
414   const ListValue* trigger_list = nullptr;
415   if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
416       trigger_list->GetSize() > 0) {
417     for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
418       const DictionaryValue* trigger = nullptr;
419       if (!trigger_list->GetDictionary(i, &trigger))
420         continue;
421 
422       MemoryDumpConfig::Trigger dump_config;
423       int interval = 0;
424       if (!trigger->GetInteger(kMinTimeBetweenDumps, &interval)) {
425         // If "min_time_between_dumps_ms" param was not given, then the trace
426         // config uses old format where only periodic dumps are supported.
427         trigger->GetInteger(kPeriodicIntervalLegacyParam, &interval);
428         dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
429       } else {
430         std::string trigger_type_str;
431         trigger->GetString(kTriggerTypeParam, &trigger_type_str);
432         dump_config.trigger_type = StringToMemoryDumpType(trigger_type_str);
433       }
434       DCHECK_GT(interval, 0);
435       dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(interval);
436 
437       std::string level_of_detail_str;
438       trigger->GetString(kTriggerModeParam, &level_of_detail_str);
439       dump_config.level_of_detail =
440           StringToMemoryDumpLevelOfDetail(level_of_detail_str);
441 
442       memory_dump_config_.triggers.push_back(dump_config);
443     }
444   }
445 
446   // Set heap profiler options
447   const DictionaryValue* heap_profiler_options = nullptr;
448   if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
449                                        &heap_profiler_options)) {
450     int min_size_bytes = 0;
451     if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
452                                          &min_size_bytes)
453         && min_size_bytes >= 0) {
454       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
455           static_cast<size_t>(min_size_bytes);
456     } else {
457       memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
458           MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
459     }
460   }
461 }
462 
SetDefaultMemoryDumpConfig()463 void TraceConfig::SetDefaultMemoryDumpConfig() {
464   memory_dump_config_.Clear();
465   memory_dump_config_.triggers.push_back(kDefaultHeavyMemoryDumpTrigger);
466   memory_dump_config_.triggers.push_back(kDefaultLightMemoryDumpTrigger);
467   memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
468 }
469 
SetEventFiltersFromConfigList(const base::ListValue & category_event_filters)470 void TraceConfig::SetEventFiltersFromConfigList(
471     const base::ListValue& category_event_filters) {
472   event_filters_.clear();
473 
474   for (size_t event_filter_index = 0;
475        event_filter_index < category_event_filters.GetSize();
476        ++event_filter_index) {
477     const base::DictionaryValue* event_filter = nullptr;
478     if (!category_event_filters.GetDictionary(event_filter_index,
479                                               &event_filter))
480       continue;
481 
482     std::string predicate_name;
483     CHECK(event_filter->GetString(kFilterPredicateParam, &predicate_name))
484         << "Invalid predicate name in category event filter.";
485 
486     EventFilterConfig new_config(predicate_name);
487     new_config.InitializeFromConfigDict(event_filter);
488     event_filters_.push_back(new_config);
489   }
490 }
491 
ToDict() const492 std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
493   auto dict = MakeUnique<DictionaryValue>();
494   switch (record_mode_) {
495     case RECORD_UNTIL_FULL:
496       dict->SetString(kRecordModeParam, kRecordUntilFull);
497       break;
498     case RECORD_CONTINUOUSLY:
499       dict->SetString(kRecordModeParam, kRecordContinuously);
500       break;
501     case RECORD_AS_MUCH_AS_POSSIBLE:
502       dict->SetString(kRecordModeParam, kRecordAsMuchAsPossible);
503       break;
504     case ECHO_TO_CONSOLE:
505       dict->SetString(kRecordModeParam, kTraceToConsole);
506       break;
507     default:
508       NOTREACHED();
509   }
510 
511   dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
512   dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
513 
514   category_filter_.ToDict(dict.get());
515 
516   if (!event_filters_.empty()) {
517     std::unique_ptr<base::ListValue> filter_list(new base::ListValue());
518     for (const EventFilterConfig& filter : event_filters_) {
519       std::unique_ptr<base::DictionaryValue> filter_dict(
520           new base::DictionaryValue());
521       filter.ToDict(filter_dict.get());
522       filter_list->Append(std::move(filter_dict));
523     }
524     dict->Set(kEventFiltersParam, std::move(filter_list));
525   }
526 
527   if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
528     auto allowed_modes = MakeUnique<ListValue>();
529     for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
530       allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
531 
532     auto memory_dump_config = MakeUnique<DictionaryValue>();
533     memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
534 
535     auto triggers_list = MakeUnique<ListValue>();
536     for (const auto& config : memory_dump_config_.triggers) {
537       auto trigger_dict = MakeUnique<DictionaryValue>();
538       trigger_dict->SetString(kTriggerTypeParam,
539                               MemoryDumpTypeToString(config.trigger_type));
540       trigger_dict->SetInteger(
541           kMinTimeBetweenDumps,
542           static_cast<int>(config.min_time_between_dumps_ms));
543       trigger_dict->SetString(
544           kTriggerModeParam,
545           MemoryDumpLevelOfDetailToString(config.level_of_detail));
546       triggers_list->Append(std::move(trigger_dict));
547     }
548 
549     // Empty triggers will still be specified explicitly since it means that
550     // the periodic dumps are not enabled.
551     memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
552 
553     if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
554         MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
555       auto options = MakeUnique<DictionaryValue>();
556       options->SetInteger(
557           kBreakdownThresholdBytes,
558           memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
559       memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
560     }
561     dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
562   }
563   return dict;
564 }
565 
ToTraceOptionsString() const566 std::string TraceConfig::ToTraceOptionsString() const {
567   std::string ret;
568   switch (record_mode_) {
569     case RECORD_UNTIL_FULL:
570       ret = kRecordUntilFull;
571       break;
572     case RECORD_CONTINUOUSLY:
573       ret = kRecordContinuously;
574       break;
575     case RECORD_AS_MUCH_AS_POSSIBLE:
576       ret = kRecordAsMuchAsPossible;
577       break;
578     case ECHO_TO_CONSOLE:
579       ret = kTraceToConsole;
580       break;
581     default:
582       NOTREACHED();
583   }
584   if (enable_systrace_)
585     ret = ret + "," + kEnableSystrace;
586   if (enable_argument_filter_)
587     ret = ret + "," + kEnableArgumentFilter;
588   return ret;
589 }
590 
591 }  // namespace trace_event
592 }  // namespace base
593