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* MemoryDumpTypeToString(const MemoryDumpType
& dump_type
) {
28 case MemoryDumpType::TASK_BEGIN
:
30 case MemoryDumpType::TASK_END
:
32 case MemoryDumpType::PERIODIC_INTERVAL
:
33 return "PERIODIC_INTERVAL";
34 case MemoryDumpType::EXPLICITLY_TRIGGERED
:
35 return "EXPLICITLY_TRIGGERED";
43 // TODO(primiano): this should be smarter and should do something similar to
44 // trace event synthetic delays.
45 const char MemoryDumpManager::kTraceCategory
[] =
46 TRACE_DISABLED_BY_DEFAULT("memory-dumps");
49 MemoryDumpManager
* MemoryDumpManager::GetInstance() {
50 if (g_instance_for_testing
)
51 return g_instance_for_testing
;
53 return Singleton
<MemoryDumpManager
,
54 LeakySingletonTraits
<MemoryDumpManager
>>::get();
58 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager
* instance
) {
59 g_instance_for_testing
= instance
;
62 MemoryDumpManager::MemoryDumpManager()
63 : dump_provider_currently_active_(nullptr),
65 memory_tracing_enabled_(0) {
66 g_next_guid
.GetNext(); // Make sure that first guid is not zero.
69 MemoryDumpManager::~MemoryDumpManager() {
70 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
73 void MemoryDumpManager::Initialize() {
74 TRACE_EVENT0(kTraceCategory
, "init"); // Add to trace-viewer category list.
75 trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
78 void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate
* delegate
) {
80 DCHECK(delegate_
== nullptr);
84 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider
* mdp
) {
86 if (std::find(dump_providers_registered_
.begin(),
87 dump_providers_registered_
.end(),
88 mdp
) != dump_providers_registered_
.end()) {
91 dump_providers_registered_
.push_back(mdp
);
94 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider
* mdp
) {
97 // Remove from the registered providers list.
98 auto it
= std::find(dump_providers_registered_
.begin(),
99 dump_providers_registered_
.end(), mdp
);
100 if (it
!= dump_providers_registered_
.end())
101 dump_providers_registered_
.erase(it
);
103 // Remove from the enabled providers list. This is to deal with the case that
104 // UnregisterDumpProvider is called while the trace is enabled.
105 it
= std::find(dump_providers_enabled_
.begin(), dump_providers_enabled_
.end(),
107 if (it
!= dump_providers_enabled_
.end())
108 dump_providers_enabled_
.erase(it
);
111 void MemoryDumpManager::RequestGlobalDump(
112 MemoryDumpType dump_type
,
113 const MemoryDumpCallback
& callback
) {
114 // Bail out immediately if tracing is not enabled at all.
115 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_
)))
118 // TODO(primiano): Make guid actually unique (cross-process) by hashing it
119 // with the PID. See crbug.com/462931 for details.
120 const uint64 guid
= g_next_guid
.GetNext();
122 // The delegate_ is supposed to be thread safe, immutable and long lived.
123 // No need to keep the lock after we ensure that a delegate has been set.
124 MemoryDumpManagerDelegate
* delegate
;
126 AutoLock
lock(lock_
);
127 delegate
= delegate_
;
131 // The delegate is in charge to coordinate the request among all the
132 // processes and call the CreateLocalDumpPoint on the local process.
133 MemoryDumpRequestArgs args
= {guid
, dump_type
};
134 delegate
->RequestGlobalMemoryDump(args
, callback
);
135 } else if (!callback
.is_null()) {
136 callback
.Run(guid
, false /* success */);
140 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type
) {
141 RequestGlobalDump(dump_type
, MemoryDumpCallback());
144 // Creates a memory dump for the current process and appends it to the trace.
145 void MemoryDumpManager::CreateProcessDump(
146 const MemoryDumpRequestArgs
& args
) {
147 bool did_any_provider_dump
= false;
148 scoped_ptr
<ProcessMemoryDump
> pmd(new ProcessMemoryDump());
150 // Serialize dump generation so that memory dump providers don't have to deal
151 // with thread safety.
153 AutoLock
lock(lock_
);
154 for (auto it
= dump_providers_enabled_
.begin();
155 it
!= dump_providers_enabled_
.end();) {
156 dump_provider_currently_active_
= *it
;
157 if (dump_provider_currently_active_
->DumpInto(pmd
.get())) {
158 did_any_provider_dump
= true;
161 LOG(ERROR
) << "The memory dumper "
162 << dump_provider_currently_active_
->GetFriendlyName()
163 << " failed, possibly due to sandboxing (crbug.com/461788), "
164 "disabling it for current process. Try restarting chrome "
165 "with the --no-sandbox switch.";
166 it
= dump_providers_enabled_
.erase(it
);
168 dump_provider_currently_active_
= nullptr;
172 // Don't create a memory dump if all the dumpers failed.
173 if (!did_any_provider_dump
)
176 scoped_refptr
<ConvertableToTraceFormat
> event_value(new TracedValue());
177 pmd
->AsValueInto(static_cast<TracedValue
*>(event_value
.get()));
178 const char* const event_name
= MemoryDumpTypeToString(args
.dump_type
);
180 TRACE_EVENT_API_ADD_TRACE_EVENT(
181 TRACE_EVENT_PHASE_MEMORY_DUMP
,
182 TraceLog::GetCategoryGroupEnabled(kTraceCategory
), event_name
,
183 args
.dump_guid
, kTraceEventNumArgs
, kTraceEventArgNames
,
184 kTraceEventArgTypes
, nullptr /* arg_values */, &event_value
,
185 TRACE_EVENT_FLAG_HAS_ID
);
188 void MemoryDumpManager::OnTraceLogEnabled() {
189 // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
190 // to figure out (and cache) which dumpers should be enabled or not.
191 // For the moment piggy back everything on the generic "memory" category.
193 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory
, &enabled
);
195 AutoLock
lock(lock_
);
197 dump_providers_enabled_
.assign(dump_providers_registered_
.begin(),
198 dump_providers_registered_
.end());
200 dump_providers_enabled_
.clear();
202 subtle::NoBarrier_Store(&memory_tracing_enabled_
, 1);
205 void MemoryDumpManager::OnTraceLogDisabled() {
206 AutoLock
lock(lock_
);
207 dump_providers_enabled_
.clear();
208 subtle::NoBarrier_Store(&memory_tracing_enabled_
, 0);
211 } // namespace trace_event