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

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

Issue 2737153002: [memory-infra] Implement peak detection logic (Closed)
Patch Set: fixes. Created 3 years, 9 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 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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_scheduler.h" 5 #include "base/trace_event/memory_dump_scheduler.h"
6 6
7 #include <math.h>
8
9 #include "base/process/process_metrics.h"
7 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
8 #include "base/threading/thread_task_runner_handle.h" 11 #include "base/threading/thread_task_runner_handle.h"
9 #include "base/trace_event/memory_dump_manager.h" 12 #include "base/trace_event/memory_dump_manager.h"
10 #include "build/build_config.h" 13 #include "build/build_config.h"
11 14
12 namespace base { 15 namespace base {
13 namespace trace_event { 16 namespace trace_event {
14 17
15 namespace { 18 namespace {
16 // Threshold on increase in memory from last dump beyond which a new dump must 19 // Threshold on increase in memory from last dump beyond which a new dump must
17 // be triggered. 20 // be triggered.
18 int64_t kMemoryIncreaseThreshold = 50 * 1024 * 1024; // 50MiB 21 int64_t kDefaultMemoryIncreaseThreshold = 50 * 1024 * 1024; // 50MiB
19 const uint32_t kMemoryTotalsPollingInterval = 25; 22 const uint32_t kMemoryTotalsPollingInterval = 25;
20 uint32_t g_polling_interval_ms_for_testing = 0; 23 uint32_t g_polling_interval_ms_for_testing = 0;
24 const unsigned kNumTotalsTrackedForPeakDetection = 50;
25
21 } // namespace 26 } // namespace
22 27
23 MemoryDumpScheduler::MemoryDumpScheduler( 28 MemoryDumpScheduler::MemoryDumpScheduler(
24 MemoryDumpManager* mdm, 29 MemoryDumpManager* mdm,
25 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) 30 scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
26 : mdm_(mdm), polling_state_(polling_task_runner) {} 31 : mdm_(mdm), polling_state_(polling_task_runner) {
32 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
Primiano Tucci (use gerrit) 2017/03/09 18:31:27 isn't easier to say which one you don't want? Is t
ssid 2017/03/09 19:32:44 GetSystemMemoryInfo is defined under this same mac
33 defined(OS_ANDROID)
34 // Set threshold to 1% of total system memory.
35 SystemMemoryInfoKB meminfo;
36 bool res = GetSystemMemoryInfo(&meminfo);
37 if (res)
38 polling_state_.memory_increase_threshold = (meminfo.total / 100) * 1024;
39 #endif
40 }
27 41
28 MemoryDumpScheduler::~MemoryDumpScheduler() {} 42 MemoryDumpScheduler::~MemoryDumpScheduler() {}
29 43
30 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type, 44 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type,
31 MemoryDumpLevelOfDetail level_of_detail, 45 MemoryDumpLevelOfDetail level_of_detail,
32 uint32_t min_time_between_dumps_ms) { 46 uint32_t min_time_between_dumps_ms) {
33 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { 47 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) {
34 DCHECK(!periodic_state_.is_configured); 48 DCHECK(!periodic_state_.is_configured);
35 DCHECK(!polling_state_.is_configured); 49 DCHECK(!polling_state_.is_configured);
36 DCHECK_NE(0u, min_time_between_dumps_ms); 50 DCHECK_NE(0u, min_time_between_dumps_ms);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 periodic_state_.timer.Start( 92 periodic_state_.timer.Start(
79 FROM_HERE, 93 FROM_HERE,
80 TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms), 94 TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms),
81 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this))); 95 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this)));
82 } 96 }
83 97
84 void MemoryDumpScheduler::NotifyPollingSupported() { 98 void MemoryDumpScheduler::NotifyPollingSupported() {
85 if (!polling_state_.is_configured || polling_state_.is_polling_enabled) 99 if (!polling_state_.is_configured || polling_state_.is_polling_enabled)
86 return; 100 return;
87 polling_state_.is_polling_enabled = true; 101 polling_state_.is_polling_enabled = true;
102 polling_state_.last_n_memory_totals.clear();
88 polling_state_.num_polls_from_last_dump = 0; 103 polling_state_.num_polls_from_last_dump = 0;
89 polling_state_.last_dump_memory_total = 0; 104 polling_state_.last_dump_memory_total = 0;
90 polling_state_.polling_task_runner->PostTask( 105 polling_state_.polling_task_runner->PostTask(
91 FROM_HERE, 106 FROM_HERE,
92 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this))); 107 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)));
93 } 108 }
94 109
95 void MemoryDumpScheduler::DisableAllTriggers() { 110 void MemoryDumpScheduler::DisableAllTriggers() {
96 if (periodic_state_.timer.IsRunning()) 111 if (periodic_state_.timer.IsRunning())
97 periodic_state_.timer.Stop(); 112 periodic_state_.timer.Stop();
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (polling_state_.last_dump_memory_total == 0) { 188 if (polling_state_.last_dump_memory_total == 0) {
174 // If it's first sample then trigger memory dump. 189 // If it's first sample then trigger memory dump.
175 should_dump = true; 190 should_dump = true;
176 } else if (polling_state_.min_polls_between_dumps > 191 } else if (polling_state_.min_polls_between_dumps >
177 polling_state_.num_polls_from_last_dump) { 192 polling_state_.num_polls_from_last_dump) {
178 return false; 193 return false;
179 } 194 }
180 195
181 int64_t increase_from_last_dump = 196 int64_t increase_from_last_dump =
182 current_memory_total - polling_state_.last_dump_memory_total; 197 current_memory_total - polling_state_.last_dump_memory_total;
183 should_dump |= increase_from_last_dump > kMemoryIncreaseThreshold; 198 should_dump |=
199 increase_from_last_dump > polling_state_.memory_increase_threshold;
200 should_dump |= IsCurrentSamplePeak(current_memory_total);
184 if (should_dump) { 201 if (should_dump) {
185 polling_state_.last_dump_memory_total = current_memory_total; 202 polling_state_.last_dump_memory_total = current_memory_total;
186 polling_state_.num_polls_from_last_dump = 0; 203 polling_state_.num_polls_from_last_dump = 0;
204 polling_state_.last_n_memory_totals.clear();
187 } 205 }
188 return should_dump; 206 return should_dump;
189 } 207 }
190 208
209 bool MemoryDumpScheduler::IsCurrentSamplePeak(uint64_t current_memory_total) {
210 if (polling_state_.last_n_memory_totals.size() <
211 kNumTotalsTrackedForPeakDetection) {
212 polling_state_.last_n_memory_totals.push_back(current_memory_total);
213 return false;
214 } else if (polling_state_.last_n_memory_totals.size() >
215 kNumTotalsTrackedForPeakDetection) {
216 polling_state_.last_n_memory_totals.pop_front();
217 }
218
219 double mean = 0;
Primiano Tucci (use gerrit) 2017/03/09 18:31:27 never like too much to use floating point arith if
ssid 2017/03/09 19:32:44 Done. I liked double because i didn't have to worr
Primiano Tucci (use gerrit) 2017/03/10 10:19:32 ah are definitely right. I didn't realize that you
ssid 2017/03/10 19:56:10 Weel now that i accounted for the overflow, it sho
220 for (uint64_t sample : polling_state_.last_n_memory_totals)
221 mean += sample;
222 mean = mean / kNumTotalsTrackedForPeakDetection;
Primiano Tucci (use gerrit) 2017/03/09 18:31:27 hmm this is not true until you get the initial kNu
ssid 2017/03/09 19:32:44 If I don't have N samples then the func returns fa
Primiano Tucci (use gerrit) 2017/03/10 10:19:32 ah righ. ack
223 double stddev = 0;
224 for (uint64_t sample : polling_state_.last_n_memory_totals)
225 stddev += (sample - mean) * (sample - mean);
226 stddev = sqrt(stddev / kNumTotalsTrackedForPeakDetection);
Primiano Tucci (use gerrit) 2017/03/09 18:31:27 same here, would be great if instead of the actual
ssid 2017/03/09 19:32:44 Done.
227
228 polling_state_.last_n_memory_totals.push_back(current_memory_total);
229
230 // if stddev is less than 0.2% then we consider that the process is inactive.
231 bool is_stddev_low = stddev < mean / 500;
232 if (is_stddev_low)
233 return false;
234 // 3.69 corresponds to a value that is higher than current sample with 99.99%
235 // probability.
236 return current_memory_total > (mean + 3.69 * stddev);
237 }
238
191 MemoryDumpScheduler::PeriodicTriggerState::PeriodicTriggerState() 239 MemoryDumpScheduler::PeriodicTriggerState::PeriodicTriggerState()
192 : is_configured(false), 240 : is_configured(false),
193 dump_count(0), 241 dump_count(0),
194 min_timer_period_ms(std::numeric_limits<uint32_t>::max()), 242 min_timer_period_ms(std::numeric_limits<uint32_t>::max()),
195 light_dumps_rate(0), 243 light_dumps_rate(0),
196 heavy_dumps_rate(0), 244 heavy_dumps_rate(0),
197 light_dump_period_ms(0), 245 light_dump_period_ms(0),
198 heavy_dump_period_ms(0) {} 246 heavy_dump_period_ms(0) {}
199 247
200 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() { 248 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() {
201 DCHECK(!timer.IsRunning()); 249 DCHECK(!timer.IsRunning());
202 } 250 }
203 251
204 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState( 252 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState(
205 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) 253 scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
206 : is_configured(false), 254 : is_configured(false),
207 is_polling_enabled(false), 255 is_polling_enabled(false),
208 level_of_detail(MemoryDumpLevelOfDetail::FIRST), 256 level_of_detail(MemoryDumpLevelOfDetail::FIRST),
209 polling_task_runner(polling_task_runner), 257 polling_task_runner(polling_task_runner),
210 polling_interval_ms(g_polling_interval_ms_for_testing 258 polling_interval_ms(g_polling_interval_ms_for_testing
211 ? g_polling_interval_ms_for_testing 259 ? g_polling_interval_ms_for_testing
212 : kMemoryTotalsPollingInterval), 260 : kMemoryTotalsPollingInterval),
213 min_polls_between_dumps(0), 261 min_polls_between_dumps(0),
214 num_polls_from_last_dump(0), 262 num_polls_from_last_dump(0),
215 last_dump_memory_total(0) {} 263 last_dump_memory_total(0),
264 memory_increase_threshold(kDefaultMemoryIncreaseThreshold) {}
216 265
217 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() { 266 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() {
218 DCHECK(!polling_task_runner); 267 DCHECK(!polling_task_runner);
219 } 268 }
220 269
221 } // namespace trace_event 270 } // namespace trace_event
222 } // namespace base 271 } // namespace base
OLDNEW
« base/trace_event/memory_dump_scheduler.h ('K') | « base/trace_event/memory_dump_scheduler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698