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

Unified Diff: base/trace_event/memory_dump_trigger.cc

Issue 2582453002: [tracing] Implement polling in MemoryDumpManager (Closed)
Patch Set: Created 4 years 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 side-by-side diff with in-line comments
Download patch
Index: base/trace_event/memory_dump_trigger.cc
diff --git a/base/trace_event/memory_dump_trigger.cc b/base/trace_event/memory_dump_trigger.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fcd41111e7062bf89b8815422a04f97e6e582b85
--- /dev/null
+++ b/base/trace_event/memory_dump_trigger.cc
@@ -0,0 +1,217 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_trigger.h"
+
+#include "base/command_line.h"
+#include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+// For triggering periodic dumps:
+uint32_t g_periodic_dumps_count;
Primiano Tucci (use gerrit) 2017/01/18 16:16:06 why these are globals and not instance fields? Don
ssid 2017/01/20 23:07:27 I changed all of these to instance field of specif
+uint32_t g_light_dump_rate;
+uint32_t g_heavy_dump_rate;
+
+// For triggering peak dumps:
+const uint32_t kMemoryTotalsPollingInterval = 25;
+uint32_t g_polling_interval_for_testing = 0;
+
+// Threshold on increase in memory from last dump beyond which a new dump must
+// be triggered.
+int64_t g_memory_increase_threshold = 50 * 1024 * 1024; // 50MiB
+uint64_t g_last_dump_memory_total = 0;
+
+MemoryDumpLevelOfDetail g_peak_dumps_mode;
+int g_min_polls_between_dumps = 0;
+int g_num_polls_from_last_dump = 0;
+
+bool ShouldTriggerDump(uint64_t current_memory_total) {
+ if (current_memory_total == 0)
+ return false;
+
+ bool should_dump = false;
+ ++g_num_polls_from_last_dump;
+ if (g_last_dump_memory_total == 0) {
+ // If it's first sample then trigger memory dump.
+ should_dump |= true;
+ } else if (g_min_polls_between_dumps > g_num_polls_from_last_dump) {
+ return false;
+ }
+
+ int64_t increase_from_last_dump =
+ current_memory_total - g_last_dump_memory_total;
+ should_dump |= increase_from_last_dump > g_memory_increase_threshold;
+ if (should_dump) {
+ g_last_dump_memory_total = current_memory_total;
+ g_num_polls_from_last_dump = 0;
+ TRACE_EVENT_INSTANT1(MemoryDumpManager::kTraceCategory,
+ "Peak memory dump Triggered",
+ TRACE_EVENT_SCOPE_PROCESS, "total_usage_MB",
+ current_memory_total / 1024 / 1024);
+ }
+ return should_dump;
+}
+
+} // namespace
+
+MemoryDumpTrigger::MemoryDumpTrigger(MemoryDumpManager* mdm,
+ bool is_coordinator)
+ : mdm_(mdm), is_coordinator_(is_coordinator), polling_enabled_(0) {
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+ defined(OS_ANDROID)
+ // Set threshold to 1% of total system memory.
+ SystemMemoryInfoKB meminfo;
+ bool res = GetSystemMemoryInfo(&meminfo);
+ if (res)
+ g_memory_increase_threshold = (meminfo.total / 100) * 1024;
+#endif
+}
+
+MemoryDumpTrigger::~MemoryDumpTrigger() {
+ DCHECK(!polling_task_runner_);
+ Disable();
+}
+
+void MemoryDumpTrigger::SetupPeakTriggers(
+ const TriggerList& trigger_list,
+ scoped_refptr<SingleThreadTaskRunner> polling_task_runner) {
+ if (subtle::NoBarrier_Load(&polling_enabled_))
+ return;
+ if (trigger_list.size() != 1 ||
+ trigger_list.begin()->trigger_type != MemoryDumpType::PEAK_MEMORY_USAGE) {
+ return;
+ }
+
+ DCHECK(polling_task_runner);
+ const auto& peak_trigger = *trigger_list.begin();
+ DCHECK_NE(0u, peak_trigger.min_time_between_dumps_ms);
+
+ g_peak_dumps_mode = peak_trigger.level_of_detail;
+ uint32_t polling_interval = g_polling_interval_for_testing
+ ? g_polling_interval_for_testing
+ : kMemoryTotalsPollingInterval;
+ g_min_polls_between_dumps =
+ (peak_trigger.min_time_between_dumps_ms + polling_interval - 1) /
+ polling_interval;
+ g_num_polls_from_last_dump = 0;
+ g_last_dump_memory_total = 0;
+ subtle::NoBarrier_Store(&polling_enabled_, 1);
+ DCHECK(!polling_task_runner_);
+ polling_task_runner_ = polling_task_runner;
+ polling_task_runner->PostTask(
+ FROM_HERE,
+ Bind(&MemoryDumpTrigger::PollMemoryOnPollingThread, Unretained(this)));
+ return;
+}
+
+void MemoryDumpTrigger::SetupPeriodicTriggers(const TriggerList& trigger_list) {
+ if (trigger_list.empty() || !is_coordinator_)
+ return;
+
+ // At the moment the periodic support is limited to at most one periodic
+ // trigger per dump mode. All intervals should be an integer multiple of the
+ // smallest interval specified.
+ g_periodic_dumps_count = 0;
+ uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+ uint32_t light_dump_period_ms = 0;
+ uint32_t heavy_dump_period_ms = 0;
+ DCHECK_LE(trigger_list.size(), 3u);
+ auto* mdm = mdm_;
+ for (const TraceConfig::MemoryDumpConfig::Trigger& config : trigger_list) {
+ if (config.trigger_type != MemoryDumpType::PERIODIC_INTERVAL)
+ continue;
+ DCHECK_NE(0u, config.min_time_between_dumps_ms);
+ switch (config.level_of_detail) {
+ case MemoryDumpLevelOfDetail::BACKGROUND:
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::BACKGROUND));
+ break;
+ case MemoryDumpLevelOfDetail::LIGHT:
+ DCHECK_EQ(0u, light_dump_period_ms);
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::LIGHT));
+ light_dump_period_ms = config.min_time_between_dumps_ms;
+ break;
+ case MemoryDumpLevelOfDetail::DETAILED:
+ DCHECK_EQ(0u, heavy_dump_period_ms);
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::DETAILED));
+ heavy_dump_period_ms = config.min_time_between_dumps_ms;
+ break;
+ }
+ min_timer_period_ms =
+ std::min(min_timer_period_ms, config.min_time_between_dumps_ms);
+ }
+
+ DCHECK_EQ(0u, light_dump_period_ms % min_timer_period_ms);
+ g_light_dump_rate = light_dump_period_ms / min_timer_period_ms;
+ DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
+ g_heavy_dump_rate = heavy_dump_period_ms / min_timer_period_ms;
+
+ timer_.Start(
+ FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms),
+ Bind(&MemoryDumpTrigger::RequestPeriodicGlobalDump, Unretained(this)));
+}
+
+void MemoryDumpTrigger::Disable() {
+ if (timer_.IsRunning())
+ timer_.Stop();
+ subtle::NoBarrier_Store(&polling_enabled_, 0);
+ polling_task_runner_ = nullptr;
+}
+
+bool MemoryDumpTrigger::IsPeriodicDumpTimerRunning() const {
+ return timer_.IsRunning();
+}
+
+// static
+void MemoryDumpTrigger::SetPollingIntervalForTesting(uint32_t interval) {
+ g_polling_interval_for_testing = interval;
+}
+
+void MemoryDumpTrigger::RequestPeriodicGlobalDump() {
+ MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
+ if (g_light_dump_rate > 0 && g_periodic_dumps_count % g_light_dump_rate == 0)
+ level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
+ if (g_heavy_dump_rate > 0 && g_periodic_dumps_count % g_heavy_dump_rate == 0)
+ level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
+ ++g_periodic_dumps_count;
+
+ mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
+}
+
+void MemoryDumpTrigger::PollMemoryOnPollingThread() {
+ if (!subtle::NoBarrier_Load(&polling_enabled_)) {
+ polling_task_runner_ = nullptr;
+ return;
+ }
+
+ uint64_t metric = 0;
+ bool res = mdm_->PollFastMemoryTotal(&metric);
+ DCHECK(res);
+ if (g_peak_dumps_mode == MemoryDumpLevelOfDetail::DETAILED) {
+ TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "MemoryMetricMB",
+ metric / 1024 / 1024);
+ }
+
+ if (ShouldTriggerDump(metric)) {
+ mdm_->RequestGlobalDump(MemoryDumpType::PEAK_MEMORY_USAGE,
+ g_peak_dumps_mode);
+ }
+
+ // TODO(ssid): Use RequestSchedulerCallback, crbug.com/607533.
+ uint32_t polling_interval = g_polling_interval_for_testing
+ ? g_polling_interval_for_testing
+ : kMemoryTotalsPollingInterval;
+ polling_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ Bind(&MemoryDumpTrigger::PollMemoryOnPollingThread, Unretained(this)),
+ TimeDelta::FromMilliseconds(polling_interval));
+}
+
+} // namespace trace_event
+} // namespace base
« base/trace_event/memory_dump_trigger.h ('K') | « base/trace_event/memory_dump_trigger.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698