1 // Copyright 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/memory_dump_manager.h"
9 #include "base/atomic_sequence_num.h"
10 #include "base/compiler_specific.h"
11 #include "base/trace_event/memory_dump_provider.h"
12 #include "base/trace_event/process_memory_dump.h"
13 #include "base/trace_event/trace_event_argument.h"
16 namespace trace_event
{
20 MemoryDumpManager
* g_instance_for_testing
= nullptr;
21 const int kTraceEventNumArgs
= 1;
22 const char* kTraceEventArgNames
[] = {"dumps"};
23 const unsigned char kTraceEventArgTypes
[] = {TRACE_VALUE_TYPE_CONVERTABLE
};
24 StaticAtomicSequenceNumber g_next_guid
;
26 const char* DumpPointTypeToString(const DumpPointType
& dump_point_type
) {
27 switch (dump_point_type
) {
28 case DumpPointType::TASK_BEGIN
:
30 case DumpPointType::TASK_END
:
32 case DumpPointType::PERIODIC_INTERVAL
:
33 return "PERIODIC_INTERVAL";
34 case DumpPointType::EXPLICITLY_TRIGGERED
:
35 return "EXPLICITLY_TRIGGERED";
42 // TODO(primiano): this should be smarter and should do something similar to
43 // trace event synthetic delays.
44 const char MemoryDumpManager::kTraceCategory
[] =
45 TRACE_DISABLED_BY_DEFAULT("memory-dumps");
48 MemoryDumpManager
* MemoryDumpManager::GetInstance() {
49 if (g_instance_for_testing
)
50 return g_instance_for_testing
;
52 return Singleton
<MemoryDumpManager
,
53 LeakySingletonTraits
<MemoryDumpManager
>>::get();
57 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager
* instance
) {
58 g_instance_for_testing
= instance
;
61 MemoryDumpManager::MemoryDumpManager() : memory_tracing_enabled_(0) {
64 MemoryDumpManager::~MemoryDumpManager() {
65 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
68 void MemoryDumpManager::Initialize() {
69 TRACE_EVENT0(kTraceCategory
, "init"); // Add to trace-viewer category list.
70 trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
73 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider
* mdp
) {
75 if (std::find(dump_providers_registered_
.begin(),
76 dump_providers_registered_
.end(),
77 mdp
) != dump_providers_registered_
.end()) {
80 dump_providers_registered_
.push_back(mdp
);
83 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider
* mdp
) {
86 // Remove from the registered providers list.
87 auto it
= std::find(dump_providers_registered_
.begin(),
88 dump_providers_registered_
.end(), mdp
);
89 if (it
!= dump_providers_registered_
.end())
90 dump_providers_registered_
.erase(it
);
92 // Remove from the enabled providers list. This is to deal with the case that
93 // UnregisterDumpProvider is called while the trace is enabled.
94 it
= std::find(dump_providers_enabled_
.begin(), dump_providers_enabled_
.end(),
96 if (it
!= dump_providers_enabled_
.end())
97 dump_providers_enabled_
.erase(it
);
100 void MemoryDumpManager::RequestDumpPoint(DumpPointType dump_point_type
) {
101 // TODO(primiano): this will have more logic to coordinate dump points across
102 // multiple processes via IPC. See crbug.com/462930.
104 // Bail out immediately if tracing is not enabled at all.
105 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_
)))
108 // TODO(primiano): Make guid actually unique (cross-process) by hashing it
109 // with the PID. See crbug.com/462931 for details.
110 const uint64 guid
= g_next_guid
.GetNext();
111 CreateLocalDumpPoint(dump_point_type
, guid
);
114 void MemoryDumpManager::BroadcastDumpRequest() {
115 NOTREACHED(); // TODO(primiano): implement IPC synchronization.
118 // Creates a dump point for the current process and appends it to the trace.
119 void MemoryDumpManager::CreateLocalDumpPoint(DumpPointType dump_point_type
,
121 bool did_any_provider_dump
= false;
122 scoped_ptr
<ProcessMemoryDump
> pmd(new ProcessMemoryDump());
124 // Serialize dump point generation so that memory dump providers don't have to
125 // deal with thread safety.
127 AutoLock
lock(lock_
);
128 for (auto it
= dump_providers_enabled_
.begin();
129 it
!= dump_providers_enabled_
.end();) {
130 MemoryDumpProvider
* dump_provider
= *it
;
131 if (dump_provider
->DumpInto(pmd
.get())) {
132 did_any_provider_dump
= true;
135 LOG(ERROR
) << "The memory dumper " << dump_provider
->GetFriendlyName()
136 << " failed, possibly due to sandboxing (crbug.com/461788), "
137 "disabling it for current process. Try restarting chrome "
138 "with the --no-sandbox switch.";
139 it
= dump_providers_enabled_
.erase(it
);
144 // Don't create a dump point if all the dumpers failed.
145 if (!did_any_provider_dump
)
148 scoped_refptr
<ConvertableToTraceFormat
> event_value(new TracedValue());
149 pmd
->AsValueInto(static_cast<TracedValue
*>(event_value
.get()));
150 const char* const event_name
= DumpPointTypeToString(dump_point_type
);
152 TRACE_EVENT_API_ADD_TRACE_EVENT(
153 TRACE_EVENT_PHASE_MEMORY_DUMP
,
154 TraceLog::GetCategoryGroupEnabled(kTraceCategory
), event_name
, guid
,
155 kTraceEventNumArgs
, kTraceEventArgNames
, kTraceEventArgTypes
,
156 NULL
/* arg_values */, &event_value
, TRACE_EVENT_FLAG_HAS_ID
);
159 void MemoryDumpManager::OnTraceLogEnabled() {
160 // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
161 // to figure out (and cache) which dumpers should be enabled or not.
162 // For the moment piggy back everything on the generic "memory" category.
164 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory
, &enabled
);
166 AutoLock
lock(lock_
);
168 dump_providers_enabled_
.assign(dump_providers_registered_
.begin(),
169 dump_providers_registered_
.end());
171 dump_providers_enabled_
.clear();
173 subtle::NoBarrier_Store(&memory_tracing_enabled_
, 1);
176 void MemoryDumpManager::OnTraceLogDisabled() {
177 AutoLock
lock(lock_
);
178 dump_providers_enabled_
.clear();
179 subtle::NoBarrier_Store(&memory_tracing_enabled_
, 0);
182 } // namespace trace_event