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" |
| 11 #include "build/build_config.h" | 11 #include "build/build_config.h" |
| 12 | 12 |
| 13 namespace base { | 13 namespace base { |
| 14 namespace trace_event { | 14 namespace trace_event { |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 // Threshold on increase in memory from last dump beyond which a new dump must | 17 // Threshold on increase in memory from last dump beyond which a new dump must |
| 18 // be triggered. | 18 // be triggered. |
| 19 int64_t kDefaultMemoryIncreaseThreshold = 50 * 1024 * 1024; // 50MiB | 19 int64_t kDefaultMemoryIncreaseThreshold = 50 * 1024 * 1024; // 50MiB |
| 20 const uint32_t kMemoryTotalsPollingInterval = 25; | 20 const uint32_t kMemoryTotalsPollingInterval = 25; |
| 21 uint32_t g_polling_interval_ms_for_testing = 0; | 21 uint32_t g_polling_interval_ms_for_testing = 0; |
| 22 } // namespace | 22 } // namespace |
| 23 | 23 |
| 24 MemoryDumpScheduler::MemoryDumpScheduler( | 24 // static |
| 25 MemoryDumpScheduler* MemoryDumpScheduler::GetInstance() { | |
| 26 return Singleton<MemoryDumpScheduler, | |
| 27 LeakySingletonTraits<MemoryDumpScheduler>>::get(); | |
| 28 } | |
| 29 | |
| 30 MemoryDumpScheduler::MemoryDumpScheduler() : mdm_(nullptr), is_setup_(false) {} | |
| 31 MemoryDumpScheduler::~MemoryDumpScheduler() {} | |
| 32 | |
| 33 void MemoryDumpScheduler::Setup( | |
| 25 MemoryDumpManager* mdm, | 34 MemoryDumpManager* mdm, |
| 26 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) | 35 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) { |
| 27 : mdm_(mdm), polling_state_(polling_task_runner) {} | 36 mdm_ = mdm; |
| 28 | 37 polling_task_runner_ = polling_task_runner; |
| 29 MemoryDumpScheduler::~MemoryDumpScheduler() {} | 38 periodic_state_.reset(new PeriodicTriggerState); |
| 39 polling_state_.reset(new PollingTriggerState); | |
| 40 is_setup_ = true; | |
| 41 } | |
| 30 | 42 |
| 31 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type, | 43 void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type, |
| 32 MemoryDumpLevelOfDetail level_of_detail, | 44 MemoryDumpLevelOfDetail level_of_detail, |
| 33 uint32_t min_time_between_dumps_ms) { | 45 uint32_t min_time_between_dumps_ms) { |
| 46 DCHECK(is_setup_); | |
| 34 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { | 47 if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) { |
| 35 DCHECK(!periodic_state_.is_configured); | 48 DCHECK(!periodic_state_->is_configured); |
| 36 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state); | 49 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_->current_state); |
| 37 DCHECK_NE(0u, min_time_between_dumps_ms); | 50 DCHECK_NE(0u, min_time_between_dumps_ms); |
| 38 | 51 |
| 39 polling_state_.level_of_detail = level_of_detail; | 52 polling_state_->level_of_detail = level_of_detail; |
| 40 polling_state_.min_polls_between_dumps = | 53 polling_state_->min_polls_between_dumps = |
| 41 (min_time_between_dumps_ms + polling_state_.polling_interval_ms - 1) / | 54 (min_time_between_dumps_ms + polling_state_->polling_interval_ms - 1) / |
| 42 polling_state_.polling_interval_ms; | 55 polling_state_->polling_interval_ms; |
| 43 polling_state_.current_state = PollingTriggerState::CONFIGURED; | 56 polling_state_->current_state = PollingTriggerState::CONFIGURED; |
| 44 } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) { | 57 } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) { |
| 45 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state); | 58 DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_->current_state); |
| 46 periodic_state_.is_configured = true; | 59 periodic_state_->is_configured = true; |
| 47 DCHECK_NE(0u, min_time_between_dumps_ms); | 60 DCHECK_NE(0u, min_time_between_dumps_ms); |
| 48 switch (level_of_detail) { | 61 switch (level_of_detail) { |
| 49 case MemoryDumpLevelOfDetail::BACKGROUND: | 62 case MemoryDumpLevelOfDetail::BACKGROUND: |
| 50 break; | 63 break; |
| 51 case MemoryDumpLevelOfDetail::LIGHT: | 64 case MemoryDumpLevelOfDetail::LIGHT: |
| 52 DCHECK_EQ(0u, periodic_state_.light_dump_period_ms); | 65 DCHECK_EQ(0u, periodic_state_->light_dump_period_ms); |
| 53 periodic_state_.light_dump_period_ms = min_time_between_dumps_ms; | 66 periodic_state_->light_dump_period_ms = min_time_between_dumps_ms; |
| 54 break; | 67 break; |
| 55 case MemoryDumpLevelOfDetail::DETAILED: | 68 case MemoryDumpLevelOfDetail::DETAILED: |
| 56 DCHECK_EQ(0u, periodic_state_.heavy_dump_period_ms); | 69 DCHECK_EQ(0u, periodic_state_->heavy_dump_period_ms); |
| 57 periodic_state_.heavy_dump_period_ms = min_time_between_dumps_ms; | 70 periodic_state_->heavy_dump_period_ms = min_time_between_dumps_ms; |
| 58 break; | 71 break; |
| 59 } | 72 } |
| 60 | 73 |
| 61 periodic_state_.min_timer_period_ms = std::min( | 74 periodic_state_->min_timer_period_ms = std::min( |
| 62 periodic_state_.min_timer_period_ms, min_time_between_dumps_ms); | 75 periodic_state_->min_timer_period_ms, min_time_between_dumps_ms); |
| 63 DCHECK_EQ(0u, periodic_state_.light_dump_period_ms % | 76 DCHECK_EQ(0u, periodic_state_->light_dump_period_ms % |
| 64 periodic_state_.min_timer_period_ms); | 77 periodic_state_->min_timer_period_ms); |
| 65 DCHECK_EQ(0u, periodic_state_.heavy_dump_period_ms % | 78 DCHECK_EQ(0u, periodic_state_->heavy_dump_period_ms % |
| 66 periodic_state_.min_timer_period_ms); | 79 periodic_state_->min_timer_period_ms); |
| 67 } | 80 } |
| 68 } | 81 } |
| 69 | 82 |
| 70 void MemoryDumpScheduler::NotifyPeriodicTriggerSupported() { | 83 void MemoryDumpScheduler::EnablePeriodicTriggerIfNeeded() { |
| 71 if (!periodic_state_.is_configured || periodic_state_.timer.IsRunning()) | 84 DCHECK(is_setup_); |
| 85 if (!periodic_state_->is_configured || periodic_state_->timer.IsRunning()) | |
| 72 return; | 86 return; |
| 73 periodic_state_.light_dumps_rate = periodic_state_.light_dump_period_ms / | 87 periodic_state_->light_dumps_rate = periodic_state_->light_dump_period_ms / |
| 74 periodic_state_.min_timer_period_ms; | 88 periodic_state_->min_timer_period_ms; |
| 75 periodic_state_.heavy_dumps_rate = periodic_state_.heavy_dump_period_ms / | 89 periodic_state_->heavy_dumps_rate = periodic_state_->heavy_dump_period_ms / |
| 76 periodic_state_.min_timer_period_ms; | 90 periodic_state_->min_timer_period_ms; |
| 77 | 91 |
| 78 periodic_state_.dump_count = 0; | 92 periodic_state_->dump_count = 0; |
| 79 periodic_state_.timer.Start( | 93 periodic_state_->timer.Start( |
| 80 FROM_HERE, | 94 FROM_HERE, |
| 81 TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms), | 95 TimeDelta::FromMilliseconds(periodic_state_->min_timer_period_ms), |
| 82 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this))); | 96 Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this))); |
| 83 } | 97 } |
| 84 | 98 |
| 85 void MemoryDumpScheduler::NotifyPollingSupported() { | 99 void MemoryDumpScheduler::EnablePollingIfNeeded() { |
| 86 if (polling_state_.current_state != PollingTriggerState::CONFIGURED) | 100 DCHECK(is_setup_); |
| 101 if (polling_state_->current_state != PollingTriggerState::CONFIGURED) | |
| 87 return; | 102 return; |
| 88 | 103 |
| 89 polling_state_.current_state = PollingTriggerState::ENABLED; | 104 polling_state_->current_state = PollingTriggerState::ENABLED; |
| 90 polling_state_.ResetTotals(); | 105 polling_state_->ResetTotals(); |
| 91 | 106 |
| 92 polling_state_.polling_task_runner->PostTask( | 107 polling_task_runner_->PostTask( |
| 93 FROM_HERE, | 108 FROM_HERE, |
| 94 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this))); | 109 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this))); |
| 95 } | 110 } |
| 96 | 111 |
| 97 void MemoryDumpScheduler::NotifyDumpTriggered() { | 112 void MemoryDumpScheduler::NotifyDumpTriggered() { |
| 98 if (polling_state_.polling_task_runner && | 113 if (polling_task_runner_ && |
| 99 polling_state_.polling_task_runner->RunsTasksOnCurrentThread()) { | 114 polling_task_runner_->RunsTasksOnCurrentThread()) { |
| 100 polling_state_.polling_task_runner->PostTask( | 115 polling_task_runner_->PostTask( |
| 101 FROM_HERE, | 116 FROM_HERE, |
| 102 Bind(&MemoryDumpScheduler::NotifyDumpTriggered, Unretained(this))); | 117 Bind(&MemoryDumpScheduler::NotifyDumpTriggered, Unretained(this))); |
| 103 return; | 118 return; |
| 104 } | 119 } |
| 105 if (polling_state_.current_state != PollingTriggerState::ENABLED) | 120 |
| 121 if (!polling_state_ || | |
| 122 polling_state_->current_state != PollingTriggerState::ENABLED) | |
| 106 return; | 123 return; |
| 107 | 124 |
| 108 polling_state_.ResetTotals(); | 125 polling_state_->ResetTotals(); |
| 109 } | 126 } |
| 110 | 127 |
| 111 void MemoryDumpScheduler::DisableAllTriggers() { | 128 void MemoryDumpScheduler::DisableAllTriggers() { |
| 112 if (periodic_state_.timer.IsRunning()) | 129 if (periodic_state_) { |
| 113 periodic_state_.timer.Stop(); | 130 if (periodic_state_->timer.IsRunning()) |
| 114 DisablePolling(); | 131 periodic_state_->timer.Stop(); |
| 132 periodic_state_.reset(); | |
| 133 } | |
| 134 | |
| 135 if (polling_task_runner_) { | |
| 136 DCHECK(polling_state_); | |
| 137 polling_task_runner_->PostTask( | |
| 138 FROM_HERE, Bind(&MemoryDumpScheduler::DisablePollingOnPollingThread, | |
| 139 Unretained(this))); | |
| 140 polling_task_runner_ = nullptr; | |
|
Primiano Tucci (use gerrit)
2017/03/16 19:01:36
.reset() might be slightly more readable, as it be
ssid
2017/03/22 01:32:58
scoped_refptr doesn't have a "reset()" method. The
| |
| 141 } | |
| 142 is_setup_ = false; | |
| 115 } | 143 } |
| 116 | 144 |
| 117 void MemoryDumpScheduler::DisablePolling() { | 145 void MemoryDumpScheduler::DisablePollingOnPollingThread() { |
| 118 if (polling_state_.polling_task_runner->RunsTasksOnCurrentThread()) { | 146 polling_state_->current_state = PollingTriggerState::DISABLED; |
| 119 if (polling_state_.polling_task_runner->PostTask( | 147 polling_state_.reset(); |
| 120 FROM_HERE, | |
| 121 Bind(&MemoryDumpScheduler::DisablePolling, Unretained(this)))) | |
| 122 return; | |
| 123 } | |
| 124 polling_state_.current_state = PollingTriggerState::DISABLED; | |
| 125 polling_state_.polling_task_runner = nullptr; | |
| 126 } | 148 } |
| 127 | 149 |
| 128 // static | 150 // static |
| 129 void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) { | 151 void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) { |
| 130 g_polling_interval_ms_for_testing = interval; | 152 g_polling_interval_ms_for_testing = interval; |
| 131 } | 153 } |
| 132 | 154 |
| 133 bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() { | 155 bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() { |
| 134 return periodic_state_.timer.IsRunning(); | 156 return periodic_state_->timer.IsRunning(); |
| 135 } | 157 } |
| 136 | 158 |
| 137 void MemoryDumpScheduler::RequestPeriodicGlobalDump() { | 159 void MemoryDumpScheduler::RequestPeriodicGlobalDump() { |
| 138 MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND; | 160 MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND; |
| 139 if (periodic_state_.light_dumps_rate > 0 && | 161 if (periodic_state_->light_dumps_rate > 0 && |
| 140 periodic_state_.dump_count % periodic_state_.light_dumps_rate == 0) | 162 periodic_state_->dump_count % periodic_state_->light_dumps_rate == 0) |
| 141 level_of_detail = MemoryDumpLevelOfDetail::LIGHT; | 163 level_of_detail = MemoryDumpLevelOfDetail::LIGHT; |
| 142 if (periodic_state_.heavy_dumps_rate > 0 && | 164 if (periodic_state_->heavy_dumps_rate > 0 && |
| 143 periodic_state_.dump_count % periodic_state_.heavy_dumps_rate == 0) | 165 periodic_state_->dump_count % periodic_state_->heavy_dumps_rate == 0) |
| 144 level_of_detail = MemoryDumpLevelOfDetail::DETAILED; | 166 level_of_detail = MemoryDumpLevelOfDetail::DETAILED; |
| 145 ++periodic_state_.dump_count; | 167 ++periodic_state_->dump_count; |
| 146 | 168 |
| 147 mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail); | 169 mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail); |
| 148 } | 170 } |
| 149 | 171 |
| 150 void MemoryDumpScheduler::PollMemoryOnPollingThread() { | 172 void MemoryDumpScheduler::PollMemoryOnPollingThread() { |
| 151 if (polling_state_.current_state != PollingTriggerState::ENABLED) | 173 if (polling_state_->current_state != PollingTriggerState::ENABLED) |
| 152 return; | 174 return; |
| 153 | 175 |
| 154 uint64_t polled_memory = 0; | 176 uint64_t polled_memory = 0; |
| 155 bool res = mdm_->PollFastMemoryTotal(&polled_memory); | 177 bool res = mdm_->PollFastMemoryTotal(&polled_memory); |
| 156 DCHECK(res); | 178 DCHECK(res); |
| 157 if (polling_state_.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { | 179 if (polling_state_->level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { |
| 158 TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "PolledMemoryMB", | 180 TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "PolledMemoryMB", |
| 159 polled_memory / 1024 / 1024); | 181 polled_memory / 1024 / 1024); |
| 160 } | 182 } |
| 161 | 183 |
| 162 if (ShouldTriggerDump(polled_memory)) { | 184 if (ShouldTriggerDump(polled_memory)) { |
| 163 TRACE_EVENT_INSTANT1(MemoryDumpManager::kTraceCategory, | 185 TRACE_EVENT_INSTANT1(MemoryDumpManager::kTraceCategory, |
| 164 "Peak memory dump Triggered", | 186 "Peak memory dump Triggered", |
| 165 TRACE_EVENT_SCOPE_PROCESS, "total_usage_MB", | 187 TRACE_EVENT_SCOPE_PROCESS, "total_usage_MB", |
| 166 polled_memory / 1024 / 1024); | 188 polled_memory / 1024 / 1024); |
| 167 | 189 |
| 168 mdm_->RequestGlobalDump(MemoryDumpType::PEAK_MEMORY_USAGE, | 190 mdm_->RequestGlobalDump(MemoryDumpType::PEAK_MEMORY_USAGE, |
| 169 polling_state_.level_of_detail); | 191 polling_state_->level_of_detail); |
| 170 } | 192 } |
| 171 | 193 |
| 172 // TODO(ssid): Use RequestSchedulerCallback, crbug.com/607533. | 194 // TODO(ssid): Use RequestSchedulerCallback, crbug.com/607533. |
| 173 ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 195 ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 174 FROM_HERE, | 196 FROM_HERE, |
| 175 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)), | 197 Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)), |
| 176 TimeDelta::FromMilliseconds(polling_state_.polling_interval_ms)); | 198 TimeDelta::FromMilliseconds(polling_state_->polling_interval_ms)); |
| 177 } | 199 } |
| 178 | 200 |
| 179 bool MemoryDumpScheduler::ShouldTriggerDump(uint64_t current_memory_total) { | 201 bool MemoryDumpScheduler::ShouldTriggerDump(uint64_t current_memory_total) { |
| 180 // This function tries to detect peak memory usage as discussed in | 202 // This function tries to detect peak memory usage as discussed in |
| 181 // https://goo.gl/0kOU4A. | 203 // https://goo.gl/0kOU4A. |
| 182 | 204 |
| 183 if (current_memory_total == 0) | 205 if (current_memory_total == 0) |
| 184 return false; | 206 return false; |
| 185 | 207 |
| 186 bool should_dump = false; | 208 bool should_dump = false; |
| 187 ++polling_state_.num_polls_from_last_dump; | 209 ++polling_state_->num_polls_from_last_dump; |
| 188 if (polling_state_.last_dump_memory_total == 0) { | 210 if (polling_state_->last_dump_memory_total == 0) { |
| 189 // If it's first sample then trigger memory dump. | 211 // If it's first sample then trigger memory dump. |
| 190 should_dump = true; | 212 should_dump = true; |
| 191 } else if (polling_state_.min_polls_between_dumps > | 213 } else if (polling_state_->min_polls_between_dumps > |
| 192 polling_state_.num_polls_from_last_dump) { | 214 polling_state_->num_polls_from_last_dump) { |
| 193 return false; | 215 return false; |
| 194 } | 216 } |
| 195 | 217 |
| 196 int64_t increase_from_last_dump = | 218 int64_t increase_from_last_dump = |
| 197 current_memory_total - polling_state_.last_dump_memory_total; | 219 current_memory_total - polling_state_->last_dump_memory_total; |
| 198 should_dump |= | 220 should_dump |= |
| 199 increase_from_last_dump > polling_state_.memory_increase_threshold; | 221 increase_from_last_dump > polling_state_->memory_increase_threshold; |
| 200 should_dump |= IsCurrentSamplePeak(current_memory_total); | 222 should_dump |= IsCurrentSamplePeak(current_memory_total); |
| 201 if (should_dump) | 223 if (should_dump) |
| 202 polling_state_.ResetTotals(); | 224 polling_state_->ResetTotals(); |
| 203 return should_dump; | 225 return should_dump; |
| 204 } | 226 } |
| 205 | 227 |
| 206 bool MemoryDumpScheduler::IsCurrentSamplePeak( | 228 bool MemoryDumpScheduler::IsCurrentSamplePeak( |
| 207 uint64_t current_memory_total_bytes) { | 229 uint64_t current_memory_total_bytes) { |
| 208 uint64_t current_memory_total_kb = current_memory_total_bytes / 1024; | 230 uint64_t current_memory_total_kb = current_memory_total_bytes / 1024; |
| 209 polling_state_.last_memory_totals_kb_index = | 231 polling_state_->last_memory_totals_kb_index = |
| 210 (polling_state_.last_memory_totals_kb_index + 1) % | 232 (polling_state_->last_memory_totals_kb_index + 1) % |
| 211 PollingTriggerState::kMaxNumMemorySamples; | 233 PollingTriggerState::kMaxNumMemorySamples; |
| 212 uint64_t mean = 0; | 234 uint64_t mean = 0; |
| 213 for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) { | 235 for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) { |
| 214 if (polling_state_.last_memory_totals_kb[i] == 0) { | 236 if (polling_state_->last_memory_totals_kb[i] == 0) { |
| 215 // Not enough samples to detect peaks. | 237 // Not enough samples to detect peaks. |
| 216 polling_state_ | 238 polling_state_ |
| 217 .last_memory_totals_kb[polling_state_.last_memory_totals_kb_index] = | 239 ->last_memory_totals_kb[polling_state_->last_memory_totals_kb_index] = |
| 218 current_memory_total_kb; | 240 current_memory_total_kb; |
| 219 return false; | 241 return false; |
| 220 } | 242 } |
| 221 mean += polling_state_.last_memory_totals_kb[i]; | 243 mean += polling_state_->last_memory_totals_kb[i]; |
| 222 } | 244 } |
| 223 mean = mean / PollingTriggerState::kMaxNumMemorySamples; | 245 mean = mean / PollingTriggerState::kMaxNumMemorySamples; |
| 224 uint64_t variance = 0; | 246 uint64_t variance = 0; |
| 225 for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) { | 247 for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) { |
| 226 variance += (polling_state_.last_memory_totals_kb[i] - mean) * | 248 variance += (polling_state_->last_memory_totals_kb[i] - mean) * |
| 227 (polling_state_.last_memory_totals_kb[i] - mean); | 249 (polling_state_->last_memory_totals_kb[i] - mean); |
| 228 } | 250 } |
| 229 variance = variance / PollingTriggerState::kMaxNumMemorySamples; | 251 variance = variance / PollingTriggerState::kMaxNumMemorySamples; |
| 230 | 252 |
| 231 polling_state_ | 253 polling_state_ |
| 232 .last_memory_totals_kb[polling_state_.last_memory_totals_kb_index] = | 254 ->last_memory_totals_kb[polling_state_->last_memory_totals_kb_index] = |
| 233 current_memory_total_kb; | 255 current_memory_total_kb; |
| 234 | 256 |
| 235 // If stddev is less than 0.2% then we consider that the process is inactive. | 257 // If stddev is less than 0.2% then we consider that the process is inactive. |
| 236 bool is_stddev_low = variance < mean / 500 * mean / 500; | 258 bool is_stddev_low = variance < mean / 500 * mean / 500; |
| 237 if (is_stddev_low) | 259 if (is_stddev_low) |
| 238 return false; | 260 return false; |
| 239 | 261 |
| 240 // (mean + 3.69 * stddev) corresponds to a value that is higher than current | 262 // (mean + 3.69 * stddev) corresponds to a value that is higher than current |
| 241 // sample with 99.99% probability. | 263 // sample with 99.99% probability. |
| 242 return (current_memory_total_kb - mean) * (current_memory_total_kb - mean) > | 264 return (current_memory_total_kb - mean) * (current_memory_total_kb - mean) > |
| 243 (3.69 * 3.69 * variance); | 265 (3.69 * 3.69 * variance); |
| 244 } | 266 } |
| 245 | 267 |
| 246 MemoryDumpScheduler::PeriodicTriggerState::PeriodicTriggerState() | 268 MemoryDumpScheduler::PeriodicTriggerState::PeriodicTriggerState() |
| 247 : is_configured(false), | 269 : is_configured(false), |
| 248 dump_count(0), | 270 dump_count(0), |
| 249 min_timer_period_ms(std::numeric_limits<uint32_t>::max()), | 271 min_timer_period_ms(std::numeric_limits<uint32_t>::max()), |
| 250 light_dumps_rate(0), | 272 light_dumps_rate(0), |
| 251 heavy_dumps_rate(0), | 273 heavy_dumps_rate(0), |
| 252 light_dump_period_ms(0), | 274 light_dump_period_ms(0), |
| 253 heavy_dump_period_ms(0) {} | 275 heavy_dump_period_ms(0) {} |
| 254 | 276 |
| 255 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() { | 277 MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() { |
| 256 DCHECK(!timer.IsRunning()); | 278 DCHECK(!timer.IsRunning()); |
| 257 } | 279 } |
| 258 | 280 |
| 259 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState( | 281 MemoryDumpScheduler::PollingTriggerState::PollingTriggerState() |
| 260 scoped_refptr<SingleThreadTaskRunner> polling_task_runner) | |
| 261 : current_state(DISABLED), | 282 : current_state(DISABLED), |
| 262 level_of_detail(MemoryDumpLevelOfDetail::FIRST), | 283 level_of_detail(MemoryDumpLevelOfDetail::FIRST), |
| 263 polling_task_runner(polling_task_runner), | |
| 264 polling_interval_ms(g_polling_interval_ms_for_testing | 284 polling_interval_ms(g_polling_interval_ms_for_testing |
| 265 ? g_polling_interval_ms_for_testing | 285 ? g_polling_interval_ms_for_testing |
| 266 : kMemoryTotalsPollingInterval), | 286 : kMemoryTotalsPollingInterval), |
| 267 min_polls_between_dumps(0), | 287 min_polls_between_dumps(0), |
| 268 num_polls_from_last_dump(-1), | 288 num_polls_from_last_dump(-1), |
| 269 last_dump_memory_total(0), | 289 last_dump_memory_total(0), |
| 270 memory_increase_threshold(0), | 290 memory_increase_threshold(0), |
| 271 last_memory_totals_kb_index(0) {} | 291 last_memory_totals_kb_index(0) {} |
| 272 | 292 |
| 273 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() { | 293 MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() {} |
| 274 DCHECK(!polling_task_runner); | |
| 275 } | |
| 276 | 294 |
| 277 void MemoryDumpScheduler::PollingTriggerState::ResetTotals() { | 295 void MemoryDumpScheduler::PollingTriggerState::ResetTotals() { |
| 278 if (!memory_increase_threshold) { | 296 if (!memory_increase_threshold) { |
| 279 memory_increase_threshold = kDefaultMemoryIncreaseThreshold; | 297 memory_increase_threshold = kDefaultMemoryIncreaseThreshold; |
| 280 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ | 298 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ |
| 281 defined(OS_ANDROID) | 299 defined(OS_ANDROID) |
| 282 // Set threshold to 1% of total system memory. | 300 // Set threshold to 1% of total system memory. |
| 283 SystemMemoryInfoKB meminfo; | 301 SystemMemoryInfoKB meminfo; |
| 284 bool res = GetSystemMemoryInfo(&meminfo); | 302 bool res = GetSystemMemoryInfo(&meminfo); |
| 285 if (res) | 303 if (res) |
| 286 memory_increase_threshold = (meminfo.total / 100) * 1024; | 304 memory_increase_threshold = (meminfo.total / 100) * 1024; |
| 287 #endif | 305 #endif |
| 288 } | 306 } |
| 289 | 307 |
| 290 // Update the |last_dump_memory_total|'s value from the totals if it's not | 308 // Update the |last_dump_memory_total|'s value from the totals if it's not |
| 291 // first poll. | 309 // first poll. |
| 292 if (num_polls_from_last_dump >= 0 && | 310 if (num_polls_from_last_dump >= 0 && |
| 293 last_memory_totals_kb[last_memory_totals_kb_index]) { | 311 last_memory_totals_kb[last_memory_totals_kb_index]) { |
| 294 last_dump_memory_total = | 312 last_dump_memory_total = |
| 295 last_memory_totals_kb[last_memory_totals_kb_index] * 1024; | 313 last_memory_totals_kb[last_memory_totals_kb_index] * 1024; |
| 296 } | 314 } |
| 297 num_polls_from_last_dump = 0; | 315 num_polls_from_last_dump = 0; |
| 298 for (uint32_t i = 0; i < kMaxNumMemorySamples; ++i) | 316 for (uint32_t i = 0; i < kMaxNumMemorySamples; ++i) |
| 299 last_memory_totals_kb[i] = 0; | 317 last_memory_totals_kb[i] = 0; |
| 300 last_memory_totals_kb_index = 0; | 318 last_memory_totals_kb_index = 0; |
| 301 } | 319 } |
| 302 | 320 |
| 303 } // namespace trace_event | 321 } // namespace trace_event |
| 304 } // namespace base | 322 } // namespace base |
| OLD | NEW |