Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/process/process_metrics.h" | 7 #include "base/process/process_metrics.h" |
| 8 #include "base/single_thread_task_runner.h" | 8 #include "base/single_thread_task_runner.h" |
| 9 #include "base/threading/thread_task_runner_handle.h" | 9 #include "base/threading/thread_task_runner_handle.h" |
| 10 #include "base/trace_event/memory_dump_manager.h" | 10 #include "base/trace_event/memory_dump_manager.h" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 #endif | 35 #endif |
| 36 } | 36 } |
| 37 | 37 |
| 38 MemoryDumpScheduler::~MemoryDumpScheduler() {} | 38 MemoryDumpScheduler::~MemoryDumpScheduler() {} |
| 39 | 39 |
| 40 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type, | 40 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type, |
| 41 MemoryDumpLevelOfDetail level_of_detail, | 41 MemoryDumpLevelOfDetail level_of_detail, |
| 42 uint32_t min_time_between_dumps_ms) { | 42 uint32_t min_time_between_dumps_ms) { |
| 43 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { | 43 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { |
| 44 DCHECK(!periodic_state_.is_configured); | 44 DCHECK(!periodic_state_.is_configured); |
| 45 DCHECK(!polling_state_.is_configured); | 45 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state); |
| 46 DCHECK_NE(0u, min_time_between_dumps_ms); | 46 DCHECK_NE(0u, min_time_between_dumps_ms); |
| 47 | 47 |
| 48 polling_state_.level_of_detail = level_of_detail; | 48 polling_state_.level_of_detail = level_of_detail; |
| 49 polling_state_.min_polls_between_dumps = | 49 polling_state_.min_polls_between_dumps = |
| 50 (min_time_between_dumps_ms + polling_state_.polling_interval_ms - 1) / | 50 (min_time_between_dumps_ms + polling_state_.polling_interval_ms - 1) / |
| 51 polling_state_.polling_interval_ms; | 51 polling_state_.polling_interval_ms; |
| 52 polling_state_.is_configured = true; | 52 polling_state_.current_state = PollingTriggerState::CONFIGURED; |
| 53 } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) { | 53 } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) { |
| 54 DCHECK(!polling_state_.is_configured); | 54 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state); |
| 55 periodic_state_.is_configured = true; | 55 periodic_state_.is_configured = true; |
| 56 DCHECK_NE(0u, min_time_between_dumps_ms); | 56 DCHECK_NE(0u, min_time_between_dumps_ms); |
| 57 switch (level_of_detail) { | 57 switch (level_of_detail) { |
| 58 case MemoryDumpLevelOfDetail::BACKGROUND: | 58 case MemoryDumpLevelOfDetail::BACKGROUND: |
| 59 break; | 59 break; |
| 60 case MemoryDumpLevelOfDetail::LIGHT: | 60 case MemoryDumpLevelOfDetail::LIGHT: |
| 61 DCHECK_EQ(0u, periodic_state_.light_dump_period_ms); | 61 DCHECK_EQ(0u, periodic_state_.light_dump_period_ms); |
| 62 periodic_state_.light_dump_period_ms = min_time_between_dumps_ms; | 62 periodic_state_.light_dump_period_ms = min_time_between_dumps_ms; |
| 63 break; | 63 break; |
| 64 case MemoryDumpLevelOfDetail::DETAILED: | 64 case MemoryDumpLevelOfDetail::DETAILED: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 85 periodic_state_.min_timer_period_ms; | 85 periodic_state_.min_timer_period_ms; |
| 86 | 86 |
| 87 periodic_state_.dump_count = 0; | 87 periodic_state_.dump_count = 0; |
| 88 periodic_state_.timer.Start( | 88 periodic_state_.timer.Start( |
| 89 FROM_HERE, | 89 FROM_HERE, |
| 90 TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms), | 90 TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms), |
| 91 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this))); | 91 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this))); |
| 92 } | 92 } |
| 93 | 93 |
| 94 void MemoryDumpScheduler::NotifyPollingSupported() { | 94 void MemoryDumpScheduler::NotifyPollingSupported() { |
| 95 if (!polling_state_.is_configured || polling_state_.is_polling_enabled) | 95 if (polling_state_.current_state != PollingTriggerState::CONFIGURED) |
| 96 return; | 96 return; |
| 97 polling_state_.is_polling_enabled = true; | 97 polling_state_.current_state = PollingTriggerState::ENABLED; |
| 98 for (uint32_t i = 0; | 98 |
| 99 i < PollingTriggerState::kNumTotalsTrackedForPeakDetection; ++i) { | 99 polling_state_.ResetTotals(); |
| 100 polling_state_.last_memory_totals_kb[i] = 0; | |
| 101 } | |
| 102 polling_state_.last_memory_totals_kb_index = 0; | |
| 103 polling_state_.num_polls_from_last_dump = 0; | |
| 104 polling_state_.last_dump_memory_total = 0; | |
| 105 polling_state_.polling_task_runner->PostTask( | 100 polling_state_.polling_task_runner->PostTask( |
| 106 FROM_HERE, | 101 FROM_HERE, |
| 107 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this))); | 102 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this))); |
| 108 } | 103 } |
| 109 | 104 |
| 105 void MemoryDumpScheduler::NotifyDumpTriggered() { | |
| 106 if (polling_state_.polling_task_runner && | |
| 107 ThreadTaskRunnerHandle::Get() != polling_state_.polling_task_runner) { | |
|
Primiano Tucci (use gerrit)
2017/03/10 10:35:39
do you really want to compare the TaskRunnerHandle
ssid
2017/03/10 23:51:10
Yes my bad. Fixed it.
| |
| 108 polling_state_.polling_task_runner->PostTask( | |
| 109 FROM_HERE, | |
| 110 Bind(&MemoryDumpScheduler::NotifyDumpTriggered, Unretained(this))); | |
|
Primiano Tucci (use gerrit)
2017/03/10 10:35:39
Also I just realized that these Unretained aren't
ssid
2017/03/10 14:57:37
The reason why the unretained should be safe here
| |
| 111 return; | |
| 112 } | |
| 113 if (polling_state_.current_state != PollingTriggerState::ENABLED) | |
| 114 return; | |
| 115 | |
| 116 polling_state_.ResetTotals(); | |
| 117 } | |
| 118 | |
| 110 void MemoryDumpScheduler::DisableAllTriggers() { | 119 void MemoryDumpScheduler::DisableAllTriggers() { |
| 111 if (periodic_state_.timer.IsRunning()) | 120 if (periodic_state_.timer.IsRunning()) |
| 112 periodic_state_.timer.Stop(); | 121 periodic_state_.timer.Stop(); |
| 113 DisablePolling(); | 122 DisablePolling(); |
| 114 } | 123 } |
| 115 | 124 |
| 116 void MemoryDumpScheduler::DisablePolling() { | 125 void MemoryDumpScheduler::DisablePolling() { |
| 117 if (ThreadTaskRunnerHandle::Get() != polling_state_.polling_task_runner) { | 126 if (ThreadTaskRunnerHandle::Get() != polling_state_.polling_task_runner) { |
| 118 if (polling_state_.polling_task_runner->PostTask( | 127 if (polling_state_.polling_task_runner->PostTask( |
| 119 FROM_HERE, | 128 FROM_HERE, |
| 120 Bind(&MemoryDumpScheduler::DisablePolling, Unretained(this)))) | 129 Bind(&MemoryDumpScheduler::DisablePolling, Unretained(this)))) |
| 121 return; | 130 return; |
| 122 } | 131 } |
| 123 polling_state_.is_polling_enabled = false; | 132 polling_state_.current_state = PollingTriggerState::DISABLED; |
| 124 polling_state_.is_configured = false; | |
| 125 polling_state_.polling_task_runner = nullptr; | 133 polling_state_.polling_task_runner = nullptr; |
| 126 } | 134 } |
| 127 | 135 |
| 128 // static | 136 // static |
| 129 void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) { | 137 void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) { |
| 130 g_polling_interval_ms_for_testing = interval; | 138 g_polling_interval_ms_for_testing = interval; |
| 131 } | 139 } |
| 132 | 140 |
| 133 bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() { | 141 bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() { |
| 134 return periodic_state_.timer.IsRunning(); | 142 return periodic_state_.timer.IsRunning(); |
| 135 } | 143 } |
| 136 | 144 |
| 137 void MemoryDumpScheduler::RequestPeriodicGlobalDump() { | 145 void MemoryDumpScheduler::RequestPeriodicGlobalDump() { |
| 138 MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND; | 146 MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND; |
| 139 if (periodic_state_.light_dumps_rate > 0 && | 147 if (periodic_state_.light_dumps_rate > 0 && |
| 140 periodic_state_.dump_count % periodic_state_.light_dumps_rate == 0) | 148 periodic_state_.dump_count % periodic_state_.light_dumps_rate == 0) |
| 141 level_of_detail = MemoryDumpLevelOfDetail::LIGHT; | 149 level_of_detail = MemoryDumpLevelOfDetail::LIGHT; |
| 142 if (periodic_state_.heavy_dumps_rate > 0 && | 150 if (periodic_state_.heavy_dumps_rate > 0 && |
| 143 periodic_state_.dump_count % periodic_state_.heavy_dumps_rate == 0) | 151 periodic_state_.dump_count % periodic_state_.heavy_dumps_rate == 0) |
| 144 level_of_detail = MemoryDumpLevelOfDetail::DETAILED; | 152 level_of_detail = MemoryDumpLevelOfDetail::DETAILED; |
| 145 ++periodic_state_.dump_count; | 153 ++periodic_state_.dump_count; |
| 146 | 154 |
| 147 mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail); | 155 mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail); |
| 148 } | 156 } |
| 149 | 157 |
| 150 void MemoryDumpScheduler::PollMemoryOnPollingThread() { | 158 void MemoryDumpScheduler::PollMemoryOnPollingThread() { |
| 151 if (!polling_state_.is_configured) | 159 if (polling_state_.current_state != PollingTriggerState::ENABLED) |
| 152 return; | 160 return; |
| 153 | 161 |
| 154 uint64_t polled_memory = 0; | 162 uint64_t polled_memory = 0; |
| 155 bool res = mdm_->PollFastMemoryTotal(&polled_memory); | 163 bool res = mdm_->PollFastMemoryTotal(&polled_memory); |
| 156 DCHECK(res); | 164 DCHECK(res); |
| 157 if (polling_state_.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { | 165 if (polling_state_.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { |
| 158 TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "PolledMemoryMB", | 166 TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "PolledMemoryMB", |
| 159 polled_memory / 1024 / 1024); | 167 polled_memory / 1024 / 1024); |
| 160 } | 168 } |
| 161 | 169 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 191 } else if (polling_state_.min_polls_between_dumps > | 199 } else if (polling_state_.min_polls_between_dumps > |
| 192 polling_state_.num_polls_from_last_dump) { | 200 polling_state_.num_polls_from_last_dump) { |
| 193 return false; | 201 return false; |
| 194 } | 202 } |
| 195 | 203 |
| 196 int64_t increase_from_last_dump = | 204 int64_t increase_from_last_dump = |
| 197 current_memory_total - polling_state_.last_dump_memory_total; | 205 current_memory_total - polling_state_.last_dump_memory_total; |
| 198 should_dump |= | 206 should_dump |= |
| 199 increase_from_last_dump > polling_state_.memory_increase_threshold; | 207 increase_from_last_dump > polling_state_.memory_increase_threshold; |
| 200 should_dump |= IsCurrentSamplePeak(current_memory_total); | 208 should_dump |= IsCurrentSamplePeak(current_memory_total); |
| 201 if (should_dump) { | 209 if (should_dump) |
| 202 polling_state_.last_dump_memory_total = current_memory_total; | 210 polling_state_.ResetTotals(); |
| 203 polling_state_.num_polls_from_last_dump = 0; | |
| 204 for (uint32_t i = 0; | |
| 205 i < PollingTriggerState::kNumTotalsTrackedForPeakDetection; ++i) { | |
| 206 polling_state_.last_memory_totals_kb[i] = 0; | |
| 207 } | |
| 208 polling_state_.last_memory_totals_kb_index = 0; | |
| 209 } | |
| 210 return should_dump; | 211 return should_dump; |
| 211 } | 212 } |
| 212 | 213 |
| 213 bool MemoryDumpScheduler::IsCurrentSamplePeak( | 214 bool MemoryDumpScheduler::IsCurrentSamplePeak( |
| 214 uint64_t current_memory_total_bytes) { | 215 uint64_t current_memory_total_bytes) { |
| 215 uint64_t current_memory_total_kb = current_memory_total_bytes / 1024; | 216 uint64_t current_memory_total_kb = current_memory_total_bytes / 1024; |
| 216 polling_state_.last_memory_totals_kb_index = | 217 polling_state_.last_memory_totals_kb_index = |
| 217 (polling_state_.last_memory_totals_kb_index + 1) % | 218 (polling_state_.last_memory_totals_kb_index + 1) % |
| 218 PollingTriggerState::kNumTotalsTrackedForPeakDetection; | 219 PollingTriggerState::kNumTotalsTrackedForPeakDetection; |
| 219 uint64_t mean = 0; | 220 uint64_t mean = 0; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 heavy_dumps_rate(0), | 261 heavy_dumps_rate(0), |
| 261 light_dump_period_ms(0), | 262 light_dump_period_ms(0), |
| 262 heavy_dump_period_ms(0) {} | 263 heavy_dump_period_ms(0) {} |
| 263 | 264 |
| 264 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() { | 265 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() { |
| 265 DCHECK(!timer.IsRunning()); | 266 DCHECK(!timer.IsRunning()); |
| 266 } | 267 } |
| 267 | 268 |
| 268 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState( | 269 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState( |
| 269 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) | 270 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) |
| 270 : is_configured(false), | 271 : current_state(DISABLED), |
| 271 is_polling_enabled(false), | |
| 272 level_of_detail(MemoryDumpLevelOfDetail::FIRST), | 272 level_of_detail(MemoryDumpLevelOfDetail::FIRST), |
| 273 polling_task_runner(polling_task_runner), | 273 polling_task_runner(polling_task_runner), |
| 274 polling_interval_ms(g_polling_interval_ms_for_testing | 274 polling_interval_ms(g_polling_interval_ms_for_testing |
| 275 ? g_polling_interval_ms_for_testing | 275 ? g_polling_interval_ms_for_testing |
| 276 : kMemoryTotalsPollingInterval), | 276 : kMemoryTotalsPollingInterval), |
| 277 min_polls_between_dumps(0), | 277 min_polls_between_dumps(0), |
| 278 num_polls_from_last_dump(0), | 278 num_polls_from_last_dump(0), |
| 279 last_dump_memory_total(0), | 279 last_dump_memory_total(0), |
| 280 memory_increase_threshold(kDefaultMemoryIncreaseThreshold), | 280 memory_increase_threshold(kDefaultMemoryIncreaseThreshold), |
| 281 last_memory_totals_kb_index(0) {} | 281 last_memory_totals_kb_index(0) {} |
| 282 | 282 |
| 283 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() { | 283 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() { |
| 284 DCHECK(!polling_task_runner); | 284 DCHECK(!polling_task_runner); |
| 285 } | 285 } |
| 286 | 286 |
| 287 void MemoryDumpScheduler::PollingTriggerState::ResetTotals() { | |
| 288 if (last_memory_totals_kb_index) { | |
| 289 last_dump_memory_total = | |
| 290 last_memory_totals_kb[last_memory_totals_kb_index] * 1024; | |
| 291 } | |
| 292 num_polls_from_last_dump = 0; | |
| 293 for (uint32_t i = 0; i < kNumTotalsTrackedForPeakDetection; ++i) | |
| 294 last_memory_totals_kb[i] = 0; | |
| 295 last_memory_totals_kb_index = 0; | |
| 296 } | |
| 297 | |
| 287 } // namespace trace_event | 298 } // namespace trace_event |
| 288 } // namespace base | 299 } // namespace base |
| OLD | NEW |