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

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

Issue 2836933002: memory-infra: Never kill memory-infra background thread (Closed)
Patch Set: Created 3 years, 8 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 <inttypes.h> 7 #include <inttypes.h>
8 #include <stdio.h> 8 #include <stdio.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 MemoryDumpProvider* provider) { 482 MemoryDumpProvider* provider) {
483 AutoLock lock(lock_); 483 AutoLock lock(lock_);
484 484
485 for (const auto& info : dump_providers_) { 485 for (const auto& info : dump_providers_) {
486 if (info->dump_provider == provider) 486 if (info->dump_provider == provider)
487 return true; 487 return true;
488 } 488 }
489 return false; 489 return false;
490 } 490 }
491 491
492 scoped_refptr<base::SingleThreadTaskRunner> MemoryDumpManager::GetTaskRunner() {
493 lock_.AssertAcquired();
494
495 if (dump_thread_)
496 return dump_thread_->task_runner();
497
498 // Spin-up the thread used to invoke unbound dump providers.
499 std::unique_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
500 if (!dump_thread->Start()) {
Primiano Tucci (use gerrit) 2017/04/24 15:30:58 I'd just violently CHECK(started) here. Trying to
hjd 2017/04/24 16:27:59 Done.
501 LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
502 NOTREACHED();
503 }
504
505 dump_thread_ = std::move(dump_thread);
506
507 return dump_thread_->task_runner();
508 }
509
492 void MemoryDumpManager::CreateProcessDump( 510 void MemoryDumpManager::CreateProcessDump(
493 const MemoryDumpRequestArgs& args, 511 const MemoryDumpRequestArgs& args,
494 const ProcessMemoryDumpCallback& callback) { 512 const ProcessMemoryDumpCallback& callback) {
495 char guid_str[20]; 513 char guid_str[20];
496 sprintf(guid_str, "0x%" PRIx64, args.dump_guid); 514 sprintf(guid_str, "0x%" PRIx64, args.dump_guid);
497 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kTraceCategory, "ProcessMemoryDump", 515 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kTraceCategory, "ProcessMemoryDump",
498 TRACE_ID_LOCAL(args.dump_guid), "dump_guid", 516 TRACE_ID_LOCAL(args.dump_guid), "dump_guid",
499 TRACE_STR_COPY(guid_str)); 517 TRACE_STR_COPY(guid_str));
500 518
501 // If argument filter is enabled then only background mode dumps should be 519 // If argument filter is enabled then only background mode dumps should be
502 // allowed. In case the trace config passed for background tracing session 520 // allowed. In case the trace config passed for background tracing session
503 // missed the allowed modes argument, it crashes here instead of creating 521 // missed the allowed modes argument, it crashes here instead of creating
504 // unexpected dumps. 522 // unexpected dumps.
505 if (TraceLog::GetInstance() 523 if (TraceLog::GetInstance()
506 ->GetCurrentTraceConfig() 524 ->GetCurrentTraceConfig()
507 .IsArgumentFilterEnabled()) { 525 .IsArgumentFilterEnabled()) {
508 CHECK_EQ(MemoryDumpLevelOfDetail::BACKGROUND, args.level_of_detail); 526 CHECK_EQ(MemoryDumpLevelOfDetail::BACKGROUND, args.level_of_detail);
509 } 527 }
510 528
511 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; 529 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
512 { 530 {
513 AutoLock lock(lock_); 531 AutoLock lock(lock_);
514 532
515 // |dump_thread_| can be nullptr is tracing was disabled before reaching
516 // here. SetupNextMemoryDump() is robust enough to tolerate it and will
517 // NACK the dump.
518 pmd_async_state.reset(new ProcessMemoryDumpAsyncState( 533 pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
519 args, dump_providers_, session_state_, callback, 534 args, dump_providers_, session_state_, callback, GetTaskRunner()));
520 dump_thread_ ? dump_thread_->task_runner() : nullptr));
521 535
522 // Safety check to prevent reaching here without calling RequestGlobalDump, 536 // Safety check to prevent reaching here without calling RequestGlobalDump,
523 // with disallowed modes. If |session_state_| is null then tracing is 537 // with disallowed modes. If |session_state_| is null then tracing is
524 // disabled. 538 // disabled.
525 CHECK(!session_state_ || 539 CHECK(!session_state_ ||
526 session_state_->IsDumpModeAllowed(args.level_of_detail)); 540 session_state_->IsDumpModeAllowed(args.level_of_detail));
527 541
528 // If enabled, holds back the peak detector resetting its estimation window. 542 // If enabled, holds back the peak detector resetting its estimation window.
529 MemoryPeakDetector::GetInstance()->Throttle(); 543 MemoryPeakDetector::GetInstance()->Throttle();
530 } 544 }
(...skipping 13 matching lines...) Expand all
544 // |lock_| is used in these functions purely to ensure consistency w.r.t. 558 // |lock_| is used in these functions purely to ensure consistency w.r.t.
545 // (un)registrations of |dump_providers_|. 559 // (un)registrations of |dump_providers_|.
546 void MemoryDumpManager::SetupNextMemoryDump( 560 void MemoryDumpManager::SetupNextMemoryDump(
547 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) { 561 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
548 HEAP_PROFILER_SCOPED_IGNORE; 562 HEAP_PROFILER_SCOPED_IGNORE;
549 // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs 563 // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
550 // in the PostTask below don't end up registering their own dump providers 564 // in the PostTask below don't end up registering their own dump providers
551 // (for discounting trace memory overhead) while holding the |lock_|. 565 // (for discounting trace memory overhead) while holding the |lock_|.
552 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported(); 566 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
553 567
554 // |dump_thread_| might be destroyed before getting this point. 568 // MDM might have been disabled before getting to this point.
555 // It means that tracing was disabled right before starting this dump. 569 // Anyway either MDM is disabled or this was the last hop, create a trace
556 // Anyway either tracing is stopped or this was the last hop, create a trace
557 // event, add it to the trace and finalize process dump invoking the callback. 570 // event, add it to the trace and finalize process dump invoking the callback.
558 if (!pmd_async_state->dump_thread_task_runner.get()) { 571 if (!subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
Primiano Tucci (use gerrit) 2017/04/24 15:30:58 I think this extra check is superfluous. The callb
hjd 2017/04/24 16:27:59 Removing this causes a test (MemoryDumpManagerTest
ssid 2017/04/25 03:21:47 I agree with primiano. We could get to a state whe
559 if (pmd_async_state->pending_dump_providers.empty()) { 572 if (pmd_async_state->pending_dump_providers.empty()) {
560 VLOG(1) << kLogPrefix << " failed because dump thread was destroyed" 573 VLOG(1) << kLogPrefix << " failed because MemoryDumpManager was disabled"
561 << " before finalizing the dump"; 574 << " before finalizing the dump";
562 } else { 575 } else {
563 VLOG(1) << kLogPrefix << " failed because dump thread was destroyed" 576 VLOG(1) << kLogPrefix << " failed because MemoryDumpManager was disabled"
564 << " before dumping " 577 << " before dumping "
565 << pmd_async_state->pending_dump_providers.back().get()->name; 578 << pmd_async_state->pending_dump_providers.back().get()->name;
566 } 579 }
567 pmd_async_state->dump_successful = false; 580 pmd_async_state->dump_successful = false;
568 pmd_async_state->pending_dump_providers.clear(); 581 pmd_async_state->pending_dump_providers.clear();
569 } 582 }
583
570 if (pmd_async_state->pending_dump_providers.empty()) 584 if (pmd_async_state->pending_dump_providers.empty())
571 return FinalizeDumpAndAddToTrace(std::move(pmd_async_state)); 585 return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
572 586
573 // Read MemoryDumpProviderInfo thread safety considerations in 587 // Read MemoryDumpProviderInfo thread safety considerations in
574 // memory_dump_manager.h when accessing |mdpinfo| fields. 588 // memory_dump_manager.h when accessing |mdpinfo| fields.
575 MemoryDumpProviderInfo* mdpinfo = 589 MemoryDumpProviderInfo* mdpinfo =
576 pmd_async_state->pending_dump_providers.back().get(); 590 pmd_async_state->pending_dump_providers.back().get();
577 591
578 // If we are in background tracing, we should invoke only the whitelisted 592 // If we are in background tracing, we should invoke only the whitelisted
579 // providers. Ignore other providers and continue. 593 // providers. Ignore other providers and continue.
580 if (pmd_async_state->req_args.level_of_detail == 594 if (pmd_async_state->req_args.level_of_detail ==
581 MemoryDumpLevelOfDetail::BACKGROUND && 595 MemoryDumpLevelOfDetail::BACKGROUND &&
582 !mdpinfo->whitelisted_for_background_mode) { 596 !mdpinfo->whitelisted_for_background_mode) {
583 pmd_async_state->pending_dump_providers.pop_back(); 597 pmd_async_state->pending_dump_providers.pop_back();
584 return SetupNextMemoryDump(std::move(pmd_async_state)); 598 return SetupNextMemoryDump(std::move(pmd_async_state));
585 } 599 }
586 600
587 // If the dump provider did not specify a task runner affinity, dump on 601 // If the dump provider did not specify a task runner affinity, dump on
588 // |dump_thread_| which is already checked above for presence. 602 // |dump_thread_|.
589 SequencedTaskRunner* task_runner = mdpinfo->task_runner.get(); 603 SequencedTaskRunner* task_runner = mdpinfo->task_runner.get();
590 if (!task_runner) { 604 if (!task_runner) {
591 DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner); 605 DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
592 task_runner = pmd_async_state->dump_thread_task_runner.get(); 606 task_runner = pmd_async_state->dump_thread_task_runner.get();
593 DCHECK(task_runner); 607 DCHECK(task_runner);
594 } 608 }
595 609
596 if (mdpinfo->options.dumps_on_single_thread_task_runner && 610 if (mdpinfo->options.dumps_on_single_thread_task_runner &&
597 task_runner->RunsTasksOnCurrentThread()) { 611 task_runner->RunsTasksOnCurrentThread()) {
598 // If |dumps_on_single_thread_task_runner| is true then no PostTask is 612 // If |dumps_on_single_thread_task_runner| is true then no PostTask is
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 pmd_async_state->callback.Run(dump_guid, dump_successful, result); 793 pmd_async_state->callback.Run(dump_guid, dump_successful, result);
780 pmd_async_state->callback.Reset(); 794 pmd_async_state->callback.Reset();
781 } 795 }
782 796
783 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", 797 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
784 TRACE_ID_LOCAL(dump_guid)); 798 TRACE_ID_LOCAL(dump_guid));
785 } 799 }
786 800
787 void MemoryDumpManager::Enable( 801 void MemoryDumpManager::Enable(
788 const TraceConfig::MemoryDumpConfig& memory_dump_config) { 802 const TraceConfig::MemoryDumpConfig& memory_dump_config) {
789 // Spin-up the thread used to invoke unbound dump providers.
790 std::unique_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
791 if (!dump_thread->Start()) {
792 LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
793 return;
794 }
795 803
796 scoped_refptr<MemoryDumpSessionState> session_state = 804 scoped_refptr<MemoryDumpSessionState> session_state =
797 new MemoryDumpSessionState; 805 new MemoryDumpSessionState;
798 session_state->SetAllowedDumpModes(memory_dump_config.allowed_dump_modes); 806 session_state->SetAllowedDumpModes(memory_dump_config.allowed_dump_modes);
799 session_state->set_heap_profiler_breakdown_threshold_bytes( 807 session_state->set_heap_profiler_breakdown_threshold_bytes(
800 memory_dump_config.heap_profiler_options.breakdown_threshold_bytes); 808 memory_dump_config.heap_profiler_options.breakdown_threshold_bytes);
801 if (heap_profiling_enabled_) { 809 if (heap_profiling_enabled_) {
802 // If heap profiling is enabled, the stack frame deduplicator and type name 810 // If heap profiling is enabled, the stack frame deduplicator and type name
803 // deduplicator will be in use. Add a metadata events to write the frames 811 // deduplicator will be in use. Add a metadata events to write the frames
804 // and type IDs. 812 // and type IDs.
(...skipping 14 matching lines...) Expand all
819 "typeNames", 827 "typeNames",
820 MakeUnique<SessionStateConvertableProxy<TypeNameDeduplicator>>( 828 MakeUnique<SessionStateConvertableProxy<TypeNameDeduplicator>>(
821 session_state, &MemoryDumpSessionState::type_name_deduplicator)); 829 session_state, &MemoryDumpSessionState::type_name_deduplicator));
822 } 830 }
823 831
824 AutoLock lock(lock_); 832 AutoLock lock(lock_);
825 833
826 DCHECK(delegate_); // At this point we must have a delegate. 834 DCHECK(delegate_); // At this point we must have a delegate.
827 session_state_ = session_state; 835 session_state_ = session_state;
828 836
829 DCHECK(!dump_thread_);
830 dump_thread_ = std::move(dump_thread);
831
832 subtle::NoBarrier_Store(&memory_tracing_enabled_, 1); 837 subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
833 838
834 MemoryDumpScheduler::Config periodic_config; 839 MemoryDumpScheduler::Config periodic_config;
835 bool peak_detector_configured = false; 840 bool peak_detector_configured = false;
836 for (const auto& trigger : memory_dump_config.triggers) { 841 for (const auto& trigger : memory_dump_config.triggers) {
837 if (!session_state_->IsDumpModeAllowed(trigger.level_of_detail)) { 842 if (!session_state_->IsDumpModeAllowed(trigger.level_of_detail)) {
838 NOTREACHED(); 843 NOTREACHED();
839 continue; 844 continue;
840 } 845 }
841 if (trigger.trigger_type == MemoryDumpType::PERIODIC_INTERVAL) { 846 if (trigger.trigger_type == MemoryDumpType::PERIODIC_INTERVAL) {
842 if (periodic_config.triggers.empty()) { 847 if (periodic_config.triggers.empty()) {
843 periodic_config.callback = BindRepeating(&OnPeriodicSchedulerTick); 848 periodic_config.callback = BindRepeating(&OnPeriodicSchedulerTick);
844 } 849 }
845 periodic_config.triggers.push_back( 850 periodic_config.triggers.push_back(
846 {trigger.level_of_detail, trigger.min_time_between_dumps_ms}); 851 {trigger.level_of_detail, trigger.min_time_between_dumps_ms});
847 } else if (trigger.trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { 852 } else if (trigger.trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) {
848 // At most one peak trigger is allowed. 853 // At most one peak trigger is allowed.
849 CHECK(!peak_detector_configured); 854 CHECK(!peak_detector_configured);
850 peak_detector_configured = true; 855 peak_detector_configured = true;
851 MemoryPeakDetector::GetInstance()->Setup( 856 MemoryPeakDetector::GetInstance()->Setup(
852 BindRepeating(&MemoryDumpManager::GetDumpProvidersForPolling, 857 BindRepeating(&MemoryDumpManager::GetDumpProvidersForPolling,
853 Unretained(this)), 858 Unretained(this)),
854 dump_thread_->task_runner(), 859 GetTaskRunner(),
855 BindRepeating(&OnPeakDetected, trigger.level_of_detail)); 860 BindRepeating(&OnPeakDetected, trigger.level_of_detail));
856 861
857 MemoryPeakDetector::Config peak_config; 862 MemoryPeakDetector::Config peak_config;
858 peak_config.polling_interval_ms = 10; 863 peak_config.polling_interval_ms = 10;
859 peak_config.min_time_between_peaks_ms = trigger.min_time_between_dumps_ms; 864 peak_config.min_time_between_peaks_ms = trigger.min_time_between_dumps_ms;
860 peak_config.enable_verbose_poll_tracing = 865 peak_config.enable_verbose_poll_tracing =
861 trigger.level_of_detail == MemoryDumpLevelOfDetail::DETAILED; 866 trigger.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
862 MemoryPeakDetector::GetInstance()->Start(peak_config); 867 MemoryPeakDetector::GetInstance()->Start(peak_config);
863 868
864 // When peak detection is enabled, trigger a dump straight away as it 869 // When peak detection is enabled, trigger a dump straight away as it
865 // gives a good reference point for analyzing the trace. 870 // gives a good reference point for analyzing the trace.
866 if (delegate_->IsCoordinator()) { 871 if (delegate_->IsCoordinator()) {
867 dump_thread_->task_runner()->PostTask( 872 GetTaskRunner()->PostTask(
868 FROM_HERE, BindRepeating(&OnPeakDetected, trigger.level_of_detail)); 873 FROM_HERE, BindRepeating(&OnPeakDetected, trigger.level_of_detail));
869 } 874 }
870 } 875 }
871 } 876 }
872 877
873 // Only coordinator process triggers periodic global memory dumps. 878 // Only coordinator process triggers periodic global memory dumps.
874 if (delegate_->IsCoordinator() && !periodic_config.triggers.empty()) { 879 if (delegate_->IsCoordinator() && !periodic_config.triggers.empty()) {
875 MemoryDumpScheduler::GetInstance()->Start(periodic_config, 880 MemoryDumpScheduler::GetInstance()->Start(periodic_config, GetTaskRunner());
876 dump_thread_->task_runner());
877 } 881 }
878 } 882 }
879 883
880 void MemoryDumpManager::Disable() { 884 void MemoryDumpManager::Disable() {
881 // There might be a memory dump in progress while this happens. Therefore, 885 // There might be a memory dump in progress while this happens. Therefore,
882 // ensure that the MDM state which depends on the tracing enabled / disabled 886 // ensure that the MDM state which depends on the tracing enabled / disabled
883 // state is always accessed by the dumping methods holding the |lock_|. 887 // state is always accessed by the dumping methods holding the |lock_|.
884 if (!subtle::NoBarrier_Load(&memory_tracing_enabled_)) 888 if (!subtle::NoBarrier_Load(&memory_tracing_enabled_))
885 return; 889 return;
886 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); 890 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
887 std::unique_ptr<Thread> dump_thread;
888 { 891 {
889 AutoLock lock(lock_); 892 AutoLock lock(lock_);
890 MemoryDumpScheduler::GetInstance()->Stop(); 893 MemoryDumpScheduler::GetInstance()->Stop();
891 MemoryPeakDetector::GetInstance()->TearDown(); 894 MemoryPeakDetector::GetInstance()->TearDown();
892 dump_thread = std::move(dump_thread_);
893 session_state_ = nullptr; 895 session_state_ = nullptr;
894 } 896 }
895
896 // Thread stops are blocking and must be performed outside of the |lock_|
897 // or will deadlock (e.g., if SetupNextMemoryDump() tries to acquire it).
898 if (dump_thread)
899 dump_thread->Stop();
Primiano Tucci (use gerrit) 2017/04/24 15:30:58 \o/ This, as a side effect, should fix crbug.com/7
hjd 2017/04/24 16:27:59 Done.
ssid 2017/04/25 03:21:47 Yay
900 } 897 }
901 898
902 bool MemoryDumpManager::IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode) { 899 bool MemoryDumpManager::IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode) {
903 AutoLock lock(lock_); 900 AutoLock lock(lock_);
904 if (!session_state_) 901 if (!session_state_)
905 return false; 902 return false;
906 return session_state_->IsDumpModeAllowed(dump_mode); 903 return session_state_->IsDumpModeAllowed(dump_mode);
907 } 904 }
908 905
909 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( 906 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
(...skipping 22 matching lines...) Expand all
932 if (iter == process_dumps.end()) { 929 if (iter == process_dumps.end()) {
933 std::unique_ptr<ProcessMemoryDump> new_pmd( 930 std::unique_ptr<ProcessMemoryDump> new_pmd(
934 new ProcessMemoryDump(session_state, dump_args)); 931 new ProcessMemoryDump(session_state, dump_args));
935 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; 932 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
936 } 933 }
937 return iter->second.get(); 934 return iter->second.get();
938 } 935 }
939 936
940 } // namespace trace_event 937 } // namespace trace_event
941 } // namespace base 938 } // namespace base
OLDNEW
« base/trace_event/memory_dump_manager.h ('K') | « base/trace_event/memory_dump_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698