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

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

Issue 2582453002: [tracing] Implement polling in MemoryDumpManager (Closed)
Patch Set: Nit. Created 3 years, 10 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/trace_event/memory_dump_scheduler.h"
6
7 #include "base/process/process_metrics.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/threading/thread_task_runner_handle.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "build/build_config.h"
12
13 namespace base {
14 namespace trace_event {
15
16 namespace {
17 const uint32_t kMemoryTotalsPollingInterval = 25;
18 uint32_t g_polling_interval_for_testing = 0;
19 } // namespace
20
21 MemoryDumpScheduler::MemoryDumpScheduler(
22 MemoryDumpManager* mdm,
23 scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
24 : periodic_dump_scheduler_(mdm),
25 peak_dump_scheduler_(mdm, polling_task_runner) {}
26
27 MemoryDumpScheduler::~MemoryDumpScheduler() {}
28
29 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type,
30 MemoryDumpLevelOfDetail level_of_detail,
31 uint32_t min_time_between_dumps_ms) {
32 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) {
33 DCHECK(!periodic_dump_scheduler_.is_setup());
34 peak_dump_scheduler_.AddTrigger(level_of_detail, min_time_between_dumps_ms);
35 } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) {
36 DCHECK(!peak_dump_scheduler_.is_setup());
37 periodic_dump_scheduler_.AddTrigger(level_of_detail,
38 min_time_between_dumps_ms);
39 }
40 }
41
42 void MemoryDumpScheduler::NotifyPeriodicTriggerSupported() {
43 periodic_dump_scheduler_.NotifySupported();
44 }
45
46 void MemoryDumpScheduler::NotifyPollingSupported() {
47 peak_dump_scheduler_.NotifySupported();
48 }
49
50 void MemoryDumpScheduler::DisableAllTriggers() {
51 periodic_dump_scheduler_.Disable();
52 peak_dump_scheduler_.Disable();
53 }
54
55 // static
56 void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) {
57 g_polling_interval_for_testing = interval;
58 }
59
60 bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() {
61 return periodic_dump_scheduler_.IsTimerRunning();
62 }
63
64 MemoryDumpScheduler::PeriodicDumpScheduler::PeriodicDumpScheduler(
65 MemoryDumpManager* mdm)
66 : mdm_(mdm),
67 is_setup_(false),
68 dump_count_(0),
69 min_timer_period_ms_(std::numeric_limits<uint32_t>::max()),
70 light_dumps_rate_(0),
71 heavy_dumps_rate_(0),
72 light_dump_period_ms(0),
73 heavy_dump_period_ms(0) {}
74
75 MemoryDumpScheduler::PeriodicDumpScheduler::~PeriodicDumpScheduler() {
76 DCHECK(!IsTimerRunning());
77 }
78
79 void MemoryDumpScheduler::PeriodicDumpScheduler::AddTrigger(
80 MemoryDumpLevelOfDetail level_of_detail,
81 uint32_t min_time_between_dumps_ms) {
82 is_setup_ = true;
83 DCHECK_NE(0u, min_time_between_dumps_ms);
84 switch (level_of_detail) {
85 case MemoryDumpLevelOfDetail::BACKGROUND:
86 break;
87 case MemoryDumpLevelOfDetail::LIGHT:
88 DCHECK_EQ(0u, light_dump_period_ms);
89 light_dump_period_ms = min_time_between_dumps_ms;
90 break;
91 case MemoryDumpLevelOfDetail::DETAILED:
92 DCHECK_EQ(0u, heavy_dump_period_ms);
93 heavy_dump_period_ms = min_time_between_dumps_ms;
94 break;
95 }
96 min_timer_period_ms_ =
97 std::min(min_timer_period_ms_, min_time_between_dumps_ms);
98 }
99
100 void MemoryDumpScheduler::PeriodicDumpScheduler::NotifySupported() {
101 if (!is_setup_)
102 return;
103 DCHECK_EQ(0u, light_dump_period_ms % min_timer_period_ms_);
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 I'd move these checks to AddTrigger, so the stackt
ssid 2017/02/14 02:05:40 Um, we will be doing the check multiple times when
104 light_dumps_rate_ = light_dump_period_ms / min_timer_period_ms_;
105 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms_);
106 heavy_dumps_rate_ = heavy_dump_period_ms / min_timer_period_ms_;
107
108 dump_count_ = 0;
109 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms_),
110 Bind(&MemoryDumpScheduler::PeriodicDumpScheduler::
111 RequestPeriodicGlobalDump,
112 Unretained(this)));
113 }
114
115 void MemoryDumpScheduler::PeriodicDumpScheduler::Disable() {
116 if (timer_.IsRunning())
117 timer_.Stop();
118 }
119
120 void MemoryDumpScheduler::PeriodicDumpScheduler::RequestPeriodicGlobalDump() {
121 MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
122 if (light_dumps_rate_ > 0 && dump_count_ % light_dumps_rate_ == 0)
123 level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
124 if (heavy_dumps_rate_ > 0 && dump_count_ % heavy_dumps_rate_ == 0)
125 level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
126 ++dump_count_;
127
128 mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
129 }
130
131 MemoryDumpScheduler::PeakDumpScheduler::PeakDumpScheduler(
132 MemoryDumpManager* mdm,
133 scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
134 : mdm_(mdm),
135 is_setup_(0),
136 dump_mode_(MemoryDumpLevelOfDetail::FIRST),
137 polling_task_runner_(polling_task_runner),
138 polling_interval_(g_polling_interval_for_testing
139 ? g_polling_interval_for_testing
140 : kMemoryTotalsPollingInterval),
141 min_polls_between_dumps_(0),
142 num_polls_from_last_dump_(0),
143 last_dump_memory_total_(0) {
144 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
145 defined(OS_ANDROID)
146 // Set threshold to 1% of total system memory.
147 SystemMemoryInfoKB meminfo;
148 bool res = GetSystemMemoryInfo(&meminfo);
149 if (res)
150 memory_increase_threshold_ = (meminfo.total / 100) * 1024;
151 #else
152 memory_increase_threshold_ = 50 * 1024 * 1024; // 50MiB
153 #endif
154 }
155
156 MemoryDumpScheduler::PeakDumpScheduler::~PeakDumpScheduler() {
157 DCHECK(!polling_task_runner_) << "Polling was not disabled safely";
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 remove the string comment, the code in the dcheck
ssid 2017/02/14 02:05:40 Done.
158 }
159
160 void MemoryDumpScheduler::PeakDumpScheduler::AddTrigger(
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 shouldn't this method just be called Configure() o
ssid 2017/02/14 02:05:40 Removed this method since this is a struct.
161 MemoryDumpLevelOfDetail level_of_detail,
162 uint32_t min_time_between_dumps_ms) {
163 DCHECK(!is_setup_);
164 DCHECK_NE(0u, min_time_between_dumps_ms);
165
166 dump_mode_ = level_of_detail;
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 just call the variable level_of_detail_ ? never be
ssid 2017/02/14 02:05:40 Done.
167 min_polls_between_dumps_ =
168 (min_time_between_dumps_ms + polling_interval_ - 1) / polling_interval_;
169 is_setup_ = true;
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 s/is_setup_/is_initialized_/ (or is_configured_)
ssid 2017/02/14 02:05:40 Done.
170 }
171
172 void MemoryDumpScheduler::PeakDumpScheduler::NotifySupported() {
173 if (!is_setup_)
174 return;
175 num_polls_from_last_dump_ = 0;
Primiano Tucci (use gerrit) 2017/02/03 20:08:20 can you add some logic (either a check or a return
ssid 2017/02/14 02:05:40 Done.
176 last_dump_memory_total_ = 0;
177 polling_task_runner_->PostTask(
178 FROM_HERE,
179 Bind(&MemoryDumpScheduler::PeakDumpScheduler::PollMemoryOnPollingThread,
180 Unretained(this)));
181 }
182
183 void MemoryDumpScheduler::PeakDumpScheduler::Disable() {
184 if (ThreadTaskRunnerHandle::Get() != polling_task_runner_) {
185 if (polling_task_runner_->PostTask(
186 FROM_HERE, Bind(&MemoryDumpScheduler::PeakDumpScheduler::Disable,
187 Unretained(this))))
188 return;
189 }
190 is_setup_ = false;
191 polling_task_runner_ = nullptr;
192 }
193
194 void MemoryDumpScheduler::PeakDumpScheduler::PollMemoryOnPollingThread() {
195 if (!is_setup_)
196 return;
197
198 uint64_t metric = 0;
199 bool res = mdm_->PollFastMemoryTotal(&metric);
200 DCHECK(res);
201 if (dump_mode_ == MemoryDumpLevelOfDetail::DETAILED) {
202 TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "MemoryMetricMB",
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 MemoryMetricMB -> PolledMemoryMB ?
ssid 2017/02/14 02:05:40 Done.
203 metric / 1024 / 1024);
204 }
205
206 if (ShouldTriggerDump(metric))
207 mdm_->RequestGlobalDump(MemoryDumpType::PEAK_MEMORY_USAGE, dump_mode_);
208
209 // TODO(ssid): Use RequestSchedulerCallback, crbug.com/607533.
210 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
211 FROM_HERE,
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 out of curiosity why reposting instead of using Ti
ssid 2017/02/14 02:05:40 I did not use timer here because in future we plan
212 Bind(&MemoryDumpScheduler::PeakDumpScheduler::PollMemoryOnPollingThread,
213 Unretained(this)),
214 TimeDelta::FromMilliseconds(polling_interval_));
215 }
216
217 bool MemoryDumpScheduler::PeakDumpScheduler::ShouldTriggerDump(
218 uint64_t current_memory_total) {
219 if (current_memory_total == 0)
220 return false;
221
222 bool should_dump = false;
223 ++num_polls_from_last_dump_;
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 can you make all this in early-out style, without
ssid 2017/02/14 02:05:40 The code would look like: if (polling_state_.las
224 if (last_dump_memory_total_ == 0) {
225 // If it's first sample then trigger memory dump.
226 should_dump |= true;
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 well, really no need for the |= here :) just = tru
ssid 2017/02/14 02:05:40 Done.
227 } else if (min_polls_between_dumps_ > num_polls_from_last_dump_) {
228 return false;
229 }
230
231 int64_t increase_from_last_dump =
232 current_memory_total - last_dump_memory_total_;
233 should_dump |= increase_from_last_dump > memory_increase_threshold_;
234 if (should_dump) {
235 last_dump_memory_total_ = current_memory_total;
236 num_polls_from_last_dump_ = 0;
237 TRACE_EVENT_INSTANT1(MemoryDumpManager::kTraceCategory,
238 "Peak memory dump Triggered",
Primiano Tucci (use gerrit) 2017/02/03 20:08:19 I'd move this above in Poll...OnThread, so this is
ssid 2017/02/14 02:05:40 Done.
239 TRACE_EVENT_SCOPE_PROCESS, "total_usage_MB",
240 current_memory_total / 1024 / 1024);
241 }
242 return should_dump;
243 }
244
245 } // namespace trace_event
246 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698