Make castv2 performance test work.
[chromium-blink-merge.git] / base / trace_event / memory_dump_manager.cc
blobed965fa2b312a8ccc40a0fcd95be2acc485fa8ed
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"
7 #include <algorithm>
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"
15 namespace base {
16 namespace trace_event {
18 namespace {
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) {
27 switch (dump_type) {
28 case MemoryDumpType::TASK_BEGIN:
29 return "TASK_BEGIN";
30 case MemoryDumpType::TASK_END:
31 return "TASK_END";
32 case MemoryDumpType::PERIODIC_INTERVAL:
33 return "PERIODIC_INTERVAL";
34 case MemoryDumpType::EXPLICITLY_TRIGGERED:
35 return "EXPLICITLY_TRIGGERED";
37 NOTREACHED();
38 return "UNKNOWN";
41 } // namespace
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");
48 // static
49 MemoryDumpManager* MemoryDumpManager::GetInstance() {
50 if (g_instance_for_testing)
51 return g_instance_for_testing;
53 return Singleton<MemoryDumpManager,
54 LeakySingletonTraits<MemoryDumpManager>>::get();
57 // static
58 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
59 g_instance_for_testing = instance;
62 MemoryDumpManager::MemoryDumpManager()
63 : dump_provider_currently_active_(nullptr),
64 delegate_(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) {
79 AutoLock lock(lock_);
80 DCHECK(delegate_ == nullptr);
81 delegate_ = delegate;
84 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
85 AutoLock lock(lock_);
86 if (std::find(dump_providers_registered_.begin(),
87 dump_providers_registered_.end(),
88 mdp) != dump_providers_registered_.end()) {
89 return;
91 dump_providers_registered_.push_back(mdp);
94 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
95 AutoLock lock(lock_);
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(),
106 mdp);
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_)))
116 return;
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_;
130 if (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;
159 ++it;
160 } else {
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)
174 return;
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.
192 bool enabled;
193 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
195 AutoLock lock(lock_);
196 if (enabled) {
197 dump_providers_enabled_.assign(dump_providers_registered_.begin(),
198 dump_providers_registered_.end());
199 } else {
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
212 } // namespace base