Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(682)

Side by Side Diff: base/trace_event/memory_dump_manager.cc

Issue 1222153004: [tracing] Simplify and improve thread-hopping logic of memory-infra (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix win Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/trace_event/memory_dump_manager.h" 5 #include "base/trace_event/memory_dump_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/atomic_sequence_num.h" 9 #include "base/atomic_sequence_num.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 const int kDumpIntervalMs = 250; 47 const int kDumpIntervalMs = 250;
48 const int kTraceEventNumArgs = 1; 48 const int kTraceEventNumArgs = 1;
49 const char* kTraceEventArgNames[] = {"dumps"}; 49 const char* kTraceEventArgNames[] = {"dumps"};
50 const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE}; 50 const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
51 51
52 StaticAtomicSequenceNumber g_next_guid; 52 StaticAtomicSequenceNumber g_next_guid;
53 uint32 g_periodic_dumps_count = 0; 53 uint32 g_periodic_dumps_count = 0;
54 MemoryDumpManager* g_instance_for_testing = nullptr; 54 MemoryDumpManager* g_instance_for_testing = nullptr;
55 MemoryDumpProvider* g_mmaps_dump_provider = nullptr; 55 MemoryDumpProvider* g_mmaps_dump_provider = nullptr;
56 56
57 // Internal class used to hold details about ProcessMemoryDump requests for the
58 // current process.
59 class ProcessMemoryDumpHolder
60 : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
61 public:
62 ProcessMemoryDumpHolder(
63 MemoryDumpRequestArgs req_args,
64 const scoped_refptr<MemoryDumpSessionState>& session_state,
65 MemoryDumpCallback callback)
66 : process_memory_dump(session_state),
67 req_args(req_args),
68 callback(callback),
69 task_runner(MessageLoop::current()->task_runner()),
70 num_pending_async_requests(0) {}
71
72 ProcessMemoryDump process_memory_dump;
73 const MemoryDumpRequestArgs req_args;
74
75 // Callback passed to the initial call to CreateProcessDump().
76 MemoryDumpCallback callback;
77
78 // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
79 // same that invoked the initial CreateProcessDump().
80 const scoped_refptr<SingleThreadTaskRunner> task_runner;
81
82 // Number of pending ContinueAsyncProcessDump() calls.
83 int num_pending_async_requests;
84
85 private:
86 friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
87 virtual ~ProcessMemoryDumpHolder() {}
88 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
89 };
90
91 void FinalizeDumpAndAddToTrace(
92 const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
93 DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
94
95 if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
96 pmd_holder->task_runner->PostTask(
97 FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
98 return;
99 }
100
101 scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
102 pmd_holder->process_memory_dump.AsValueInto(
103 static_cast<TracedValue*>(event_value.get()));
104 const char* const event_name =
105 MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
106
107 TRACE_EVENT_API_ADD_TRACE_EVENT(
108 TRACE_EVENT_PHASE_MEMORY_DUMP,
109 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
110 pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
111 kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
112 TRACE_EVENT_FLAG_HAS_ID);
113
114 if (!pmd_holder->callback.is_null()) {
115 pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
116 pmd_holder->callback.Reset();
117 }
118 }
119
120 void RequestPeriodicGlobalDump() { 57 void RequestPeriodicGlobalDump() {
121 MemoryDumpType dump_type = g_periodic_dumps_count == 0 58 MemoryDumpType dump_type = g_periodic_dumps_count == 0
122 ? MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS 59 ? MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS
123 : MemoryDumpType::PERIODIC_INTERVAL; 60 : MemoryDumpType::PERIODIC_INTERVAL;
124 if (++g_periodic_dumps_count == kHeavyMmapsDumpsRate) 61 if (++g_periodic_dumps_count == kHeavyMmapsDumpsRate)
125 g_periodic_dumps_count = 0; 62 g_periodic_dumps_count = 0;
126 63
127 MemoryDumpManager::GetInstance()->RequestGlobalDump(dump_type); 64 MemoryDumpManager::GetInstance()->RequestGlobalDump(dump_type);
128 } 65 }
129 66
130 void InitializeThreadLocalEventBufferIfSupported() {
131 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
132 }
133
134 } // namespace 67 } // namespace
135 68
136 // static 69 // static
137 const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory; 70 const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
138 71
139 // static 72 // static
140 const uint64 MemoryDumpManager::kInvalidTracingProcessId = 0; 73 const uint64 MemoryDumpManager::kInvalidTracingProcessId = 0;
141 74
142 // static 75 // static
143 const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3; 76 const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
144 77
145 // static 78 // static
146 MemoryDumpManager* MemoryDumpManager::GetInstance() { 79 MemoryDumpManager* MemoryDumpManager::GetInstance() {
147 if (g_instance_for_testing) 80 if (g_instance_for_testing)
148 return g_instance_for_testing; 81 return g_instance_for_testing;
149 82
150 return Singleton<MemoryDumpManager, 83 return Singleton<MemoryDumpManager,
151 LeakySingletonTraits<MemoryDumpManager>>::get(); 84 LeakySingletonTraits<MemoryDumpManager>>::get();
152 } 85 }
153 86
154 // static 87 // static
155 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) { 88 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
156 if (instance) 89 if (instance)
157 instance->skip_core_dumpers_auto_registration_for_testing_ = true; 90 instance->skip_core_dumpers_auto_registration_for_testing_ = true;
158 g_instance_for_testing = instance; 91 g_instance_for_testing = instance;
159 } 92 }
160 93
161 MemoryDumpManager::MemoryDumpManager() 94 MemoryDumpManager::MemoryDumpManager()
162 : delegate_(nullptr), 95 : did_unregister_dump_provider_(false),
96 delegate_(nullptr),
163 memory_tracing_enabled_(0), 97 memory_tracing_enabled_(0),
164 tracing_process_id_(kInvalidTracingProcessId), 98 tracing_process_id_(kInvalidTracingProcessId),
165 skip_core_dumpers_auto_registration_for_testing_(false) { 99 skip_core_dumpers_auto_registration_for_testing_(false) {
166 g_next_guid.GetNext(); // Make sure that first guid is not zero. 100 g_next_guid.GetNext(); // Make sure that first guid is not zero.
167 } 101 }
168 102
169 MemoryDumpManager::~MemoryDumpManager() { 103 MemoryDumpManager::~MemoryDumpManager() {
170 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); 104 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
171 } 105 }
172 106
(...skipping 26 matching lines...) Expand all
199 133
200 void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) { 134 void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
201 AutoLock lock(lock_); 135 AutoLock lock(lock_);
202 DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_); 136 DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
203 delegate_ = delegate; 137 delegate_ = delegate;
204 } 138 }
205 139
206 void MemoryDumpManager::RegisterDumpProvider( 140 void MemoryDumpManager::RegisterDumpProvider(
207 MemoryDumpProvider* mdp, 141 MemoryDumpProvider* mdp,
208 const scoped_refptr<SingleThreadTaskRunner>& task_runner) { 142 const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
209 MemoryDumpProviderInfo mdp_info(task_runner); 143 MemoryDumpProviderInfo mdp_info(mdp, task_runner);
210 AutoLock lock(lock_); 144 AutoLock lock(lock_);
211 dump_providers_.insert(std::make_pair(mdp, mdp_info)); 145 dump_providers_.insert(mdp_info);
212 } 146 }
213 147
214 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) { 148 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
215 RegisterDumpProvider(mdp, nullptr); 149 RegisterDumpProvider(mdp, nullptr);
216 } 150 }
217 151
218 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { 152 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
219 AutoLock lock(lock_); 153 AutoLock lock(lock_);
220 154
221 auto it = dump_providers_.find(mdp); 155 auto mdp_iter = dump_providers_.begin();
222 if (it == dump_providers_.end()) 156 for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
157 if (mdp_iter->dump_provider == mdp)
158 break;
159 }
160
161 if (mdp_iter == dump_providers_.end())
223 return; 162 return;
224 163
225 const MemoryDumpProviderInfo& mdp_info = it->second;
226 // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe 164 // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
227 // only if the MDP has specified a thread affinity (via task_runner()) AND 165 // only if the MDP has specified a thread affinity (via task_runner()) AND
228 // the unregistration happens on the same thread (so the MDP cannot unregister 166 // the unregistration happens on the same thread (so the MDP cannot unregister
229 // and OnMemoryDump() at the same time). 167 // and OnMemoryDump() at the same time).
230 // Otherwise, it is not possible to guarantee that its unregistration is 168 // Otherwise, it is not possible to guarantee that its unregistration is
231 // race-free. If you hit this DCHECK, your MDP has a bug. 169 // race-free. If you hit this DCHECK, your MDP has a bug.
232 DCHECK_IMPLIES( 170 DCHECK_IMPLIES(
233 subtle::NoBarrier_Load(&memory_tracing_enabled_), 171 subtle::NoBarrier_Load(&memory_tracing_enabled_),
234 mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread()) 172 mdp_iter->task_runner && mdp_iter->task_runner->BelongsToCurrentThread())
235 << "The MemoryDumpProvider attempted to unregister itself in a racy way. " 173 << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
236 << " Please file a crbug."; 174 << " Please file a crbug.";
petrcermak 2015/07/03 11:04:15 nit: Double space here (not your patch but I thoug
Primiano Tucci (use gerrit) 2015/07/03 15:05:43 Done.
237 175
238 // Remove from the enabled providers list. This is to deal with the case that 176 // Remove from the enabled providers list. This is to deal with the case that
239 // UnregisterDumpProvider is called while the trace is enabled. 177 // UnregisterDumpProvider is called while the trace is enabled.
petrcermak 2015/07/03 11:04:16 nit: It seems to me that this comment is outdated.
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Correct, there is only one list now. Thanks :)
240 dump_providers_.erase(it); 178 dump_providers_.erase(mdp_iter);
179 did_unregister_dump_provider_ = true;
241 } 180 }
242 181
243 void MemoryDumpManager::RequestGlobalDump( 182 void MemoryDumpManager::RequestGlobalDump(
244 MemoryDumpType dump_type, 183 MemoryDumpType dump_type,
245 const MemoryDumpCallback& callback) { 184 const MemoryDumpCallback& callback) {
246 // Bail out immediately if tracing is not enabled at all. 185 // Bail out immediately if tracing is not enabled at all.
247 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) 186 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
248 return; 187 return;
249 188
250 const uint64 guid = 189 const uint64 guid =
(...skipping 14 matching lines...) Expand all
265 delegate->RequestGlobalMemoryDump(args, callback); 204 delegate->RequestGlobalMemoryDump(args, callback);
266 } else if (!callback.is_null()) { 205 } else if (!callback.is_null()) {
267 callback.Run(guid, false /* success */); 206 callback.Run(guid, false /* success */);
268 } 207 }
269 } 208 }
270 209
271 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) { 210 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
272 RequestGlobalDump(dump_type, MemoryDumpCallback()); 211 RequestGlobalDump(dump_type, MemoryDumpCallback());
273 } 212 }
274 213
275 // Creates a memory dump for the current process and appends it to the trace.
276 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, 214 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
277 const MemoryDumpCallback& callback) { 215 const MemoryDumpCallback& callback) {
278 scoped_refptr<ProcessMemoryDumpHolder> pmd_holder( 216 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
279 new ProcessMemoryDumpHolder(args, session_state_, callback));
280 ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
281 bool did_any_provider_dump = false;
282 bool did_post_any_async_task = false;
283
284 // Initalizes the ThreadLocalEventBuffer for the syncrhonous dump providers
285 // that will be invoked in this thread without other posts. The initialization
286 // for the asynchronous providers, instead, is handled in OnTraceLogEnabled().
287 InitializeThreadLocalEventBufferIfSupported();
288
289 // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
290 // The MDM guarantees linearity (at most one MDP is active within one
291 // process) and thread-safety (MDM enforces the right locking when entering /
292 // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
293 // design
294 // and not let the MDPs worry about locking.
295 // As regards thread affinity, depending on the MDP configuration (see
296 // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
297 // - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
298 // - Posted on MDP.task_runner(), when MDP.task_runner() is set.
299 { 217 {
300 AutoLock lock(lock_); 218 AutoLock lock(lock_);
301 for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) { 219 did_unregister_dump_provider_ = false;
302 MemoryDumpProvider* mdp = it->first; 220 pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
303 MemoryDumpProviderInfo* mdp_info = &it->second; 221 args, dump_providers_.begin(), session_state_, callback));
222 }
223
224 // Start the thread hop. |dump_providers_| are kept sorted by thread, so
225 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
226 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
227 ContinueAsyncProcessDump(pmd_async_state.Pass());
228 }
229
230 // At most one ContinueAsyncProcessDump() can be active at any time for a given
231 // PMD, regardless of status of the |lock_|. |lock_| here is used purely to
petrcermak 2015/07/03 11:04:16 nit: s/here is used/is used here/
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
232 // ensure consistency w.r.t. (un)registrations of |dump_providers_|.
233 // The linearization of dump providers' OnMemoryDump invocations is achieved by
234 // means of subsequent PostTask(s).
235 //
236 // 1) Prologue:
237 // - Check if the dump provider is disabled, if so skip the dump.
238 // - Check if we are on the right thread. If not hop and continue there.
239 // 2) Invoke the dump provider's OnMemoryDump() (% skip).
petrcermak 2015/07/03 11:04:16 nit: I'd say "unless skipped" instead of "% skip"
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
240 // 3) Epilogue:
241 // - unregister the dump provider if failed too many times consecutively.
petrcermak 2015/07/03 11:04:16 nit: "if IT failed"
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
242 // - Advance the |next_dump_provider| iterator to the next dump provider.
243 // - If this was the last hop add to the trace and finalize (invoke callback).
petrcermak 2015/07/03 11:04:16 nit2: I think you should say *what* is added to th
petrcermak 2015/07/03 11:04:16 nit1: there should be a comma after "If this was t
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
244
245 void MemoryDumpManager::ContinueAsyncProcessDump(
246 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
247 // Initalizes the ThreadLocalEventBuffer, to guarantee that the TRACE_EVENTs
petrcermak 2015/07/03 11:04:15 nit: No need for a comma here.
Primiano Tucci (use gerrit) 2015/07/03 15:05:45 Done.
248 // in the PostTask below don't end up registering their own dump providers
249 // (for discounting trace memory overhead) while holding the |lock_|.
250 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
251
252 // DO NOT put any LOG() statement in the locked sections, as in some contexts
253 // (GPU process) LOG() ends up performing PostTask/IPCs.
254 MemoryDumpProvider* mdp;
255 bool skip_dump = false;
256 enum { NONE, THREAD_GONE, DUMPER_FAILED } log_warning = NONE;
petrcermak 2015/07/03 11:04:15 I think that this definition should be moved to li
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 actually don't need it anymore at all. Just need o
257 {
258 AutoLock lock(lock_);
259 // In the unlikely event that a dump provider was unregister while dumping
petrcermak 2015/07/03 11:04:15 s/unregister/unregistered/
petrcermak 2015/07/03 11:04:16 nit: There should be a comma before "abort the dum
Primiano Tucci (use gerrit) 2015/07/03 15:05:45 Done.
260 // abort the dump, as that would make the |next_dump_provider| invalid.
261 // Registration of a new MDP, instead, is safe as per std::set<> contract.
petrcermak 2015/07/03 11:04:16 nit: I think that "on the other hand" would work b
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
262 if (did_unregister_dump_provider_) {
263 return AbortDumpLocked(pmd_async_state->callback,
264 pmd_async_state->task_runner,
265 pmd_async_state->req_args.dump_guid);
266 }
267
268 auto* mdp_info = &*pmd_async_state->next_dump_provider;
269 mdp = mdp_info->dump_provider;
270 if (mdp_info->disabled) {
271 skip_dump = true;
272 } else if (mdp == g_mmaps_dump_provider &&
273 pmd_async_state->req_args.dump_type !=
274 MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS) {
304 // Mmaps dumping is very heavyweight and cannot be performed at the same 275 // Mmaps dumping is very heavyweight and cannot be performed at the same
305 // rate of other dumps. TODO(primiano): this is a hack and should be 276 // rate of other dumps. TODO(primiano): this is a hack and should be
306 // cleaned up as part of crbug.com/499731. 277 // cleaned up as part of crbug.com/499731.
307 if (mdp == g_mmaps_dump_provider && 278 skip_dump = true;
308 args.dump_type != MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS) { 279 } else if (mdp_info->task_runner &&
309 continue; 280 !mdp_info->task_runner->BelongsToCurrentThread()) {
310 } 281 // It's time to hop on another thread.
petrcermak 2015/07/03 11:04:16 nit: s/on/onto/
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
311 if (mdp_info->disabled) 282
312 continue; 283 // Copy the callback + arguments just for the unlikley case in which
313 if (mdp_info->task_runner) { 284 // PostTask fails. In such case the Bind helper will destroy the
314 // The OnMemoryDump() call must be posted. 285 // pmd_async_state and we must keep a copy of the fields to notify the
315 bool did_post_async_task = mdp_info->task_runner->PostTask( 286 // abort.
316 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, 287 MemoryDumpCallback callback = pmd_async_state->callback;
317 Unretained(this), Unretained(mdp), pmd_holder)); 288 scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
318 // The thread underlying the TaskRunner might have gone away. 289 pmd_async_state->task_runner;
319 if (did_post_async_task) { 290 const uint64 dump_guid = pmd_async_state->req_args.dump_guid;
320 ++pmd_holder->num_pending_async_requests; 291
321 did_post_any_async_task = true; 292 const bool did_post_task = mdp_info->task_runner->PostTask(
322 } 293 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
petrcermak 2015/07/03 11:04:16 Just a thought: Could you store the Bind in a loca
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Discussed this offline. Can't. THe problem is that
323 } else { 294 Unretained(this), Passed(&pmd_async_state)));
324 // Invoke the dump provider synchronously. 295 if (did_post_task)
325 did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd); 296 return;
297
298 // The thread is gone. At this point the best thing we can do is disabling
petrcermak 2015/07/03 11:04:16 nit: you say "is disablING ... and abort ...". It
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
299 // the dump provider and abort this dump.
300 mdp_info->disabled = true;
301 return AbortDumpLocked(callback, callback_task_runner, dump_guid);
302 }
303 } // AutoLock(lock_)
304
305 // Invoke the dump provider without holding the |lock_|.
306 bool finalize = false;
307 bool dump_successful = false;
308 if (!skip_dump)
309 dump_successful = mdp->OnMemoryDump(&pmd_async_state->process_memory_dump);
310
311 {
312 AutoLock lock(lock_);
313 if (did_unregister_dump_provider_) {
314 return AbortDumpLocked(pmd_async_state->callback,
315 pmd_async_state->task_runner,
316 pmd_async_state->req_args.dump_guid);
317 }
318 auto* mdp_info = &*pmd_async_state->next_dump_provider;
319 if (dump_successful) {
320 mdp_info->consecutive_failures = 0;
321 } else if (!skip_dump) {
322 ++mdp_info->consecutive_failures;
323 if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
324 mdp_info->disabled = true;
325 log_warning = DUMPER_FAILED;
326 } 326 }
327 } 327 }
328 } // AutoLock 328 ++pmd_async_state->next_dump_provider;
329 finalize = pmd_async_state->next_dump_provider == dump_providers_.end();
330 }
329 331
330 // If at least one synchronous provider did dump and there are no pending 332 if (log_warning == THREAD_GONE) {
331 // asynchronous requests, add the dump to the trace and invoke the callback 333 LOG(WARNING) << "A memory dump provider specified a thread affinity but "
332 // straight away (FinalizeDumpAndAddToTrace() takes care of the callback). 334 "its thread is gone";
petrcermak 2015/07/03 11:04:16 nit: missing full stop at the end of the message.
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 removed the entire warning.
333 if (did_any_provider_dump && !did_post_any_async_task) 335 } else if (log_warning == DUMPER_FAILED) {
334 FinalizeDumpAndAddToTrace(pmd_holder); 336 LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
petrcermak 2015/07/03 11:04:15 nit: "The memory dumper" -> "A memory dump provide
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Done.
337 "(crbug.com/461788), disabling it for current process. "
338 "Try restarting chrome with the --no-sandbox switch.";
339 }
340
341 if (finalize) {
342 FinalizeDumpAndAddToTrace(pmd_async_state.Pass());
petrcermak 2015/07/03 11:04:16 I think you could do "return FinalizeDumpAndAddToT
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Indeed. Thanks!
343 return;
344 }
345
346 ContinueAsyncProcessDump(pmd_async_state.Pass());
335 } 347 }
336 348
337 // Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe 349 // static
338 // logic which disables the dumper when failing (crbug.com/461788). 350 void MemoryDumpManager::FinalizeDumpAndAddToTrace(
339 bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp, 351 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
340 ProcessMemoryDump* pmd) { 352 if (!pmd_async_state->task_runner->BelongsToCurrentThread()) {
341 lock_.AssertAcquired(); 353 scoped_refptr<SingleThreadTaskRunner> task_runner =
342 bool dump_successful = mdp->OnMemoryDump(pmd); 354 pmd_async_state->task_runner;
343 MemoryDumpProviderInfo* mdp_info = &dump_providers_.find(mdp)->second; 355 task_runner->PostTask(
344 if (dump_successful) { 356 FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
345 mdp_info->consecutive_failures = 0; 357 Passed(&pmd_async_state)));
346 } else { 358 return;
347 // Disable the MDP if it fails kMaxConsecutiveFailuresCount times
348 // consecutively.
349 mdp_info->consecutive_failures++;
350 if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
351 mdp_info->disabled = true;
352 LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
353 "(crbug.com/461788), disabling it for current process. Try "
354 "restarting chrome with the --no-sandbox switch.";
355 }
356 } 359 }
357 return dump_successful; 360
361 scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
362 pmd_async_state->process_memory_dump.AsValueInto(
363 static_cast<TracedValue*>(event_value.get()));
364 const char* const event_name =
365 MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
366
367 TRACE_EVENT_API_ADD_TRACE_EVENT(
368 TRACE_EVENT_PHASE_MEMORY_DUMP,
369 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
370 pmd_async_state->req_args.dump_guid, kTraceEventNumArgs,
371 kTraceEventArgNames, kTraceEventArgTypes, nullptr /* arg_values */,
372 &event_value, TRACE_EVENT_FLAG_HAS_ID);
373
374 if (!pmd_async_state->callback.is_null()) {
375 pmd_async_state->callback.Run(pmd_async_state->req_args.dump_guid, true);
petrcermak 2015/07/03 11:04:15 nit: Could you please add "/* success */" after "t
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 NOOOOOOOOOOOOOO an extra new line. Pfff ok. Done
376 pmd_async_state->callback.Reset();
377 }
358 } 378 }
359 379
360 // This is posted to arbitrary threads as a continuation of CreateProcessDump(), 380 // static
361 // when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to 381 void MemoryDumpManager::AbortDumpLocked(
362 // happen on a different thread. 382 MemoryDumpCallback callback,
363 void MemoryDumpManager::ContinueAsyncProcessDump( 383 scoped_refptr<SingleThreadTaskRunner> task_runner,
364 MemoryDumpProvider* mdp, 384 uint64 dump_guid) {
365 scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) { 385 if (callback.is_null())
366 bool should_finalize_dump = false; 386 return; // There is nothing to NACK.
367 {
368 // The lock here is to guarantee that different asynchronous dumps on
369 // different threads are still serialized, so that the MemoryDumpProvider
370 // has a consistent view of the |pmd| argument passed.
371 AutoLock lock(lock_);
372 ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
373 387
374 // Check if the MemoryDumpProvider is still there. It might have been 388 // Post the callback even if we are already on the right thread to avoid
375 // destroyed and unregistered while hopping threads. 389 // invoking the callback while holing the lock_.
petrcermak 2015/07/03 11:04:15 s/holing/holding/
Primiano Tucci (use gerrit) 2015/07/03 15:05:44 Holy lock! Done
376 if (dump_providers_.count(mdp)) 390 task_runner->PostTask(FROM_HERE,
377 InvokeDumpProviderLocked(mdp, pmd); 391 Bind(callback, dump_guid, false /* success */));
378
379 // Finalize the dump appending it to the trace if this was the last
380 // asynchronous request pending.
381 --pmd_holder->num_pending_async_requests;
382 if (pmd_holder->num_pending_async_requests == 0)
383 should_finalize_dump = true;
384 } // AutoLock(lock_)
385
386 if (should_finalize_dump)
387 FinalizeDumpAndAddToTrace(pmd_holder);
388 } 392 }
389 393
390 void MemoryDumpManager::OnTraceLogEnabled() { 394 void MemoryDumpManager::OnTraceLogEnabled() {
391 // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter 395 // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
392 // to figure out (and cache) which dumpers should be enabled or not. 396 // to figure out (and cache) which dumpers should be enabled or not.
393 // For the moment piggy back everything on the generic "memory" category. 397 // For the moment piggy back everything on the generic "memory" category.
394 bool enabled; 398 bool enabled;
395 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); 399 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
396 400
397 // Initialize the TraceLog for the current thread. This is to avoid that the 401 // Initialize the TraceLog for the current thread. This is to avoid that the
398 // TraceLog memory dump provider is registered lazily in the PostTask() below 402 // TraceLog memory dump provider is registered lazily in the PostTask() below
399 // while the |lock_| is taken; 403 // while the |lock_| is taken;
400 InitializeThreadLocalEventBufferIfSupported(); 404 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
401 405
402 AutoLock lock(lock_); 406 AutoLock lock(lock_);
403 407
404 // There is no point starting the tracing without a delegate. 408 // There is no point starting the tracing without a delegate.
405 if (!enabled || !delegate_) { 409 if (!enabled || !delegate_) {
406 // Disable all the providers. 410 // Disable all the providers.
407 for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) 411 for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
408 it->second.disabled = true; 412 it->disabled = true;
409 return; 413 return;
410 } 414 }
411 415
412 session_state_ = new MemoryDumpSessionState(); 416 session_state_ = new MemoryDumpSessionState();
413 for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) { 417 for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
414 MemoryDumpProviderInfo& mdp_info = it->second; 418 it->disabled = false;
415 mdp_info.disabled = false; 419 it->consecutive_failures = 0;
416 mdp_info.consecutive_failures = 0;
417 if (mdp_info.task_runner) {
418 // The thread local event buffer must be initialized at this point as it
419 // registers its own dump provider (for tracing overhead acounting).
420 // The registration cannot happen lazily during the first TRACE_EVENT*
421 // as it might end up registering the ThreadLocalEventBuffer while
422 // in onMemoryDump(), which will deadlock.
423 mdp_info.task_runner->PostTask(
424 FROM_HERE, Bind(&InitializeThreadLocalEventBufferIfSupported));
425 }
426 } 420 }
427 421
428 subtle::NoBarrier_Store(&memory_tracing_enabled_, 1); 422 subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
429 423
430 if (delegate_->IsCoordinatorProcess()) { 424 if (delegate_->IsCoordinatorProcess()) {
431 g_periodic_dumps_count = 0; 425 g_periodic_dumps_count = 0;
432 periodic_dump_timer_.Start(FROM_HERE, 426 periodic_dump_timer_.Start(FROM_HERE,
433 TimeDelta::FromMilliseconds(kDumpIntervalMs), 427 TimeDelta::FromMilliseconds(kDumpIntervalMs),
434 base::Bind(&RequestPeriodicGlobalDump)); 428 base::Bind(&RequestPeriodicGlobalDump));
435 } 429 }
436 } 430 }
437 431
438 void MemoryDumpManager::OnTraceLogDisabled() { 432 void MemoryDumpManager::OnTraceLogDisabled() {
439 AutoLock lock(lock_); 433 AutoLock lock(lock_);
440 periodic_dump_timer_.Stop(); 434 periodic_dump_timer_.Stop();
441 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); 435 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
442 session_state_ = nullptr; 436 session_state_ = nullptr;
443 } 437 }
444 438
445 // static 439 // static
446 uint64 MemoryDumpManager::ChildProcessIdToTracingProcessId( 440 uint64 MemoryDumpManager::ChildProcessIdToTracingProcessId(
447 int child_process_id) { 441 int child_process_id) {
448 return static_cast<uint64>( 442 return static_cast<uint64>(
449 Hash(reinterpret_cast<const char*>(&child_process_id), 443 Hash(reinterpret_cast<const char*>(&child_process_id),
450 sizeof(child_process_id))) + 444 sizeof(child_process_id))) +
451 1; 445 1;
452 } 446 }
453 447
454 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo( 448 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
449 MemoryDumpProvider* dump_provider,
455 const scoped_refptr<SingleThreadTaskRunner>& task_runner) 450 const scoped_refptr<SingleThreadTaskRunner>& task_runner)
456 : task_runner(task_runner), consecutive_failures(0), disabled(false) { 451 : dump_provider(dump_provider),
452 task_runner(task_runner),
453 consecutive_failures(0),
454 disabled(false) {
457 } 455 }
456
458 MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() { 457 MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
459 } 458 }
460 459
460 bool MemoryDumpManager::MemoryDumpProviderInfo::operator<(
461 const MemoryDumpProviderInfo& other) const {
462 if (task_runner == other.task_runner)
463 return dump_provider < other.dump_provider;
464 return task_runner < other.task_runner;
465 }
466
467 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
468 MemoryDumpRequestArgs req_args,
469 MemoryDumpProviderInfoSet::iterator next_dump_provider,
470 const scoped_refptr<MemoryDumpSessionState>& session_state,
471 MemoryDumpCallback callback)
472 : process_memory_dump(session_state),
473 req_args(req_args),
474 next_dump_provider(next_dump_provider),
475 callback(callback),
476 task_runner(MessageLoop::current()->task_runner()) {
477 }
478
479 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
480 }
481
461 } // namespace trace_event 482 } // namespace trace_event
462 } // namespace base 483 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698