| OLD | NEW |
| 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 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/atomic_sequence_num.h" | 10 #include "base/atomic_sequence_num.h" |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 } | 332 } |
| 333 | 333 |
| 334 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, | 334 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, |
| 335 const MemoryDumpCallback& callback) { | 335 const MemoryDumpCallback& callback) { |
| 336 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump", | 336 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump", |
| 337 TRACE_ID_MANGLE(args.dump_guid)); | 337 TRACE_ID_MANGLE(args.dump_guid)); |
| 338 | 338 |
| 339 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; | 339 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; |
| 340 { | 340 { |
| 341 AutoLock lock(lock_); | 341 AutoLock lock(lock_); |
| 342 pmd_async_state.reset( | 342 // |dump_thread_| can be nullptr is tracing was disabled before reaching |
| 343 new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_, | 343 // here. ContinueAsyncProcessDump is robust enough to tolerate it and will |
| 344 callback, dump_thread_->task_runner())); | 344 // NACK the dump. |
| 345 pmd_async_state.reset(new ProcessMemoryDumpAsyncState( |
| 346 args, dump_providers_, session_state_, callback, |
| 347 dump_thread_ ? dump_thread_->task_runner() : nullptr)); |
| 345 } | 348 } |
| 346 | 349 |
| 347 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", | 350 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", |
| 348 TRACE_ID_MANGLE(args.dump_guid), | 351 TRACE_ID_MANGLE(args.dump_guid), |
| 349 TRACE_EVENT_FLAG_FLOW_OUT); | 352 TRACE_EVENT_FLAG_FLOW_OUT); |
| 350 | 353 |
| 351 // Start the thread hop. |dump_providers_| are kept sorted by thread, so | 354 // Start the thread hop. |dump_providers_| are kept sorted by thread, so |
| 352 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread | 355 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread |
| 353 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). | 356 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). |
| 354 ContinueAsyncProcessDump(pmd_async_state.release()); | 357 ContinueAsyncProcessDump(pmd_async_state.release()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 | 400 |
| 398 // If the dump provider did not specify a thread affinity, dump on | 401 // If the dump provider did not specify a thread affinity, dump on |
| 399 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this | 402 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this |
| 400 // point (if tracing was disabled in the meanwhile). In such case the | 403 // point (if tracing was disabled in the meanwhile). In such case the |
| 401 // PostTask() below will fail, but |task_runner| should always be non-null. | 404 // PostTask() below will fail, but |task_runner| should always be non-null. |
| 402 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); | 405 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); |
| 403 if (!task_runner) | 406 if (!task_runner) |
| 404 task_runner = pmd_async_state->dump_thread_task_runner.get(); | 407 task_runner = pmd_async_state->dump_thread_task_runner.get(); |
| 405 | 408 |
| 406 bool post_task_failed = false; | 409 bool post_task_failed = false; |
| 407 if (!task_runner->BelongsToCurrentThread()) { | 410 if (!task_runner) { |
| 411 // If tracing was disabled before reaching CreateProcessDump() |task_runner| |
| 412 // will be null, as the dump_thread_ would have been already torn down. |
| 413 post_task_failed = true; |
| 414 pmd_async_state->dump_successful = false; |
| 415 } else if (!task_runner->BelongsToCurrentThread()) { |
| 408 // It's time to hop onto another thread. | 416 // It's time to hop onto another thread. |
| 409 post_task_failed = !task_runner->PostTask( | 417 post_task_failed = !task_runner->PostTask( |
| 410 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, | 418 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, |
| 411 Unretained(this), Unretained(pmd_async_state.get()))); | 419 Unretained(this), Unretained(pmd_async_state.get()))); |
| 412 if (!post_task_failed) { | 420 if (!post_task_failed) { |
| 413 // Ownership is tranferred to the next ContinueAsyncProcessDump(). | 421 // Ownership is tranferred to the next ContinueAsyncProcessDump(). |
| 414 ignore_result(pmd_async_state.release()); | 422 ignore_result(pmd_async_state.release()); |
| 415 return; | 423 return; |
| 416 } | 424 } |
| 417 } | 425 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 434 " Try --no-sandbox."; | 442 " Try --no-sandbox."; |
| 435 } else if (post_task_failed && mdpinfo->task_runner) { | 443 } else if (post_task_failed && mdpinfo->task_runner) { |
| 436 // Don't disable unbound dump providers. The utility thread is normally | 444 // Don't disable unbound dump providers. The utility thread is normally |
| 437 // shutdown when disabling the trace and getting here in this case is | 445 // shutdown when disabling the trace and getting here in this case is |
| 438 // expected. | 446 // expected. |
| 439 mdpinfo->disabled = true; | 447 mdpinfo->disabled = true; |
| 440 disabled_reason = "The thread it was meant to dump onto is gone."; | 448 disabled_reason = "The thread it was meant to dump onto is gone."; |
| 441 } | 449 } |
| 442 } | 450 } |
| 443 should_dump = !mdpinfo->disabled && !post_task_failed; | 451 should_dump = !mdpinfo->disabled && !post_task_failed; |
| 444 } | 452 } // AutoLock lock(lock_); |
| 445 | 453 |
| 446 if (disabled_reason) { | 454 if (disabled_reason) { |
| 447 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " | 455 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " |
| 448 << disabled_reason; | 456 << disabled_reason; |
| 449 } | 457 } |
| 450 | 458 |
| 451 if (should_dump) { | 459 if (should_dump) { |
| 452 // Invoke the dump provider. | 460 // Invoke the dump provider. |
| 453 TRACE_EVENT_WITH_FLOW1(kTraceCategory, | 461 TRACE_EVENT_WITH_FLOW1(kTraceCategory, |
| 454 "MemoryDumpManager::ContinueAsyncProcessDump", | 462 "MemoryDumpManager::ContinueAsyncProcessDump", |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 MemoryDumpTypeToString(pmd_async_state->req_args.dump_type); | 511 MemoryDumpTypeToString(pmd_async_state->req_args.dump_type); |
| 504 | 512 |
| 505 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID( | 513 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID( |
| 506 TRACE_EVENT_PHASE_MEMORY_DUMP, | 514 TRACE_EVENT_PHASE_MEMORY_DUMP, |
| 507 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, | 515 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, |
| 508 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames, | 516 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames, |
| 509 kTraceEventArgTypes, nullptr /* arg_values */, &event_value, | 517 kTraceEventArgTypes, nullptr /* arg_values */, &event_value, |
| 510 TRACE_EVENT_FLAG_HAS_ID); | 518 TRACE_EVENT_FLAG_HAS_ID); |
| 511 } | 519 } |
| 512 | 520 |
| 521 bool tracing_still_enabled; |
| 522 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &tracing_still_enabled); |
| 523 if (!tracing_still_enabled) |
| 524 pmd_async_state->dump_successful = false; |
| 525 |
| 513 if (!pmd_async_state->callback.is_null()) { | 526 if (!pmd_async_state->callback.is_null()) { |
| 514 pmd_async_state->callback.Run(dump_guid, true /* success */); | 527 pmd_async_state->callback.Run(dump_guid, pmd_async_state->dump_successful); |
| 515 pmd_async_state->callback.Reset(); | 528 pmd_async_state->callback.Reset(); |
| 516 } | 529 } |
| 517 | 530 |
| 518 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", | 531 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", |
| 519 TRACE_ID_MANGLE(dump_guid)); | 532 TRACE_ID_MANGLE(dump_guid)); |
| 520 } | 533 } |
| 521 | 534 |
| 522 void MemoryDumpManager::OnTraceLogEnabled() { | 535 void MemoryDumpManager::OnTraceLogEnabled() { |
| 523 bool enabled; | 536 bool enabled; |
| 524 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); | 537 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 } | 611 } |
| 599 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms); | 612 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms); |
| 600 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms; | 613 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms; |
| 601 | 614 |
| 602 periodic_dump_timer_.Start(FROM_HERE, | 615 periodic_dump_timer_.Start(FROM_HERE, |
| 603 TimeDelta::FromMilliseconds(min_timer_period_ms), | 616 TimeDelta::FromMilliseconds(min_timer_period_ms), |
| 604 base::Bind(&RequestPeriodicGlobalDump)); | 617 base::Bind(&RequestPeriodicGlobalDump)); |
| 605 } | 618 } |
| 606 | 619 |
| 607 void MemoryDumpManager::OnTraceLogDisabled() { | 620 void MemoryDumpManager::OnTraceLogDisabled() { |
| 621 // There might be a memory dump in progress while this happens. Therefore, |
| 622 // ensure that the MDM state which depends on the tracing enabled / disabled |
| 623 // state is always accessed by the dumping methods holding the |lock_|. |
| 608 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); | 624 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); |
| 609 scoped_ptr<Thread> dump_thread; | 625 scoped_ptr<Thread> dump_thread; |
| 610 { | 626 { |
| 611 AutoLock lock(lock_); | 627 AutoLock lock(lock_); |
| 612 dump_thread = std::move(dump_thread_); | 628 dump_thread = std::move(dump_thread_); |
| 613 session_state_ = nullptr; | 629 session_state_ = nullptr; |
| 614 } | 630 } |
| 615 | 631 |
| 616 // Thread stops are blocking and must be performed outside of the |lock_| | 632 // Thread stops are blocking and must be performed outside of the |lock_| |
| 617 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). | 633 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 | 668 |
| 653 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( | 669 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( |
| 654 MemoryDumpRequestArgs req_args, | 670 MemoryDumpRequestArgs req_args, |
| 655 const MemoryDumpProviderInfo::OrderedSet& dump_providers, | 671 const MemoryDumpProviderInfo::OrderedSet& dump_providers, |
| 656 const scoped_refptr<MemoryDumpSessionState>& session_state, | 672 const scoped_refptr<MemoryDumpSessionState>& session_state, |
| 657 MemoryDumpCallback callback, | 673 MemoryDumpCallback callback, |
| 658 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) | 674 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) |
| 659 : req_args(req_args), | 675 : req_args(req_args), |
| 660 session_state(session_state), | 676 session_state(session_state), |
| 661 callback(callback), | 677 callback(callback), |
| 678 dump_successful(true), |
| 662 callback_task_runner(MessageLoop::current()->task_runner()), | 679 callback_task_runner(MessageLoop::current()->task_runner()), |
| 663 dump_thread_task_runner(dump_thread_task_runner) { | 680 dump_thread_task_runner(dump_thread_task_runner) { |
| 664 pending_dump_providers.reserve(dump_providers.size()); | 681 pending_dump_providers.reserve(dump_providers.size()); |
| 665 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend()); | 682 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend()); |
| 666 } | 683 } |
| 667 | 684 |
| 668 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { | 685 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { |
| 669 } | 686 } |
| 670 | 687 |
| 671 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState:: | 688 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState:: |
| 672 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) { | 689 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) { |
| 673 auto iter = process_dumps.find(pid); | 690 auto iter = process_dumps.find(pid); |
| 674 if (iter == process_dumps.end()) { | 691 if (iter == process_dumps.end()) { |
| 675 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); | 692 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); |
| 676 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; | 693 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; |
| 677 } | 694 } |
| 678 return iter->second.get(); | 695 return iter->second.get(); |
| 679 } | 696 } |
| 680 | 697 |
| 681 } // namespace trace_event | 698 } // namespace trace_event |
| 682 } // namespace base | 699 } // namespace base |
| OLD | NEW |