OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "chrome/browser/metrics/leak_detector/leak_detector_controller.h" | 5 #include "chrome/browser/metrics/leak_detector/leak_detector_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/rand_util.h" |
10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
11 #include "components/metrics/leak_detector/gnu_build_id_reader.h" | 12 #include "components/metrics/leak_detector/gnu_build_id_reader.h" |
12 #include "components/variations/variations_associated_data.h" | 13 #include "components/variations/variations_associated_data.h" |
13 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
14 | 15 |
15 namespace metrics { | 16 namespace metrics { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // Reads parameters for the field trial variation. Any parameters not present in | 20 using ParamsMap = std::map<std::string, std::string>; |
20 // the variation info or that cannot be parsed will be filled in with default | 21 |
21 // values. Returns a MemoryLeakReportProto with the parameter fields filled in. | 22 // Returns a mapping of param names to param values, obtained from the |
22 MemoryLeakReportProto::Params GetVariationParameters() { | 23 // variations system. Both names and values are strings. |
| 24 ParamsMap GetRawVariationParams() { |
| 25 const char kFieldTrialName[] = "RuntimeMemoryLeakDetector"; |
| 26 ParamsMap result; |
| 27 variations::GetVariationParams(kFieldTrialName, &result); |
| 28 return result; |
| 29 } |
| 30 |
| 31 // Reads the raw variation parameters and parses them to obtain values for the |
| 32 // parameters used by the memory leak detector itself. Any parameters not |
| 33 // present in the variation info or that cannot be parsed will be filled in with |
| 34 // default values. Returns a MemoryLeakReportProto with the parameter fields |
| 35 // filled in. |
| 36 MemoryLeakReportProto::Params GetLeakDetectorParams() { |
23 // Variation parameter names. | 37 // Variation parameter names. |
24 const char kFieldTrialName[] = "RuntimeMemoryLeakDetector"; | |
25 const char kSamplingRateParam[] = "sampling_rate"; | 38 const char kSamplingRateParam[] = "sampling_rate"; |
26 const char kMaxStackDepthParam[] = "max_stack_depth"; | 39 const char kMaxStackDepthParam[] = "max_stack_depth"; |
27 const char kAnalysisIntervalKbParam[] = "analysis_interval_kb"; | 40 const char kAnalysisIntervalKbParam[] = "analysis_interval_kb"; |
28 const char kSizeSuspicionThresholdParam[] = "size_suspicion_threshold"; | 41 const char kSizeSuspicionThresholdParam[] = "size_suspicion_threshold"; |
29 const char kCallStackSuspicionThresholdParam[] = | 42 const char kCallStackSuspicionThresholdParam[] = |
30 "call_stack_suspicion_threshold"; | 43 "call_stack_suspicion_threshold"; |
31 | 44 |
32 // Default parameter values. | 45 // Default parameter values. |
33 double kDefaultSamplingRate = 1.0f / 256; | 46 double kDefaultSamplingRate = 1.0f / 256; |
34 size_t kDefaultMaxStackDepth = 4; | 47 size_t kDefaultMaxStackDepth = 4; |
35 uint64_t kDefaultAnalysisIntervalKb = 32768; | 48 uint64_t kDefaultAnalysisIntervalKb = 32768; |
36 uint32_t kDefaultSizeSuspicionThreshold = 4; | 49 uint32_t kDefaultSizeSuspicionThreshold = 4; |
37 uint32_t kDefaultCallStackSuspicionThreshold = 4; | 50 uint32_t kDefaultCallStackSuspicionThreshold = 4; |
38 | 51 |
39 double sampling_rate = 0; | 52 double sampling_rate = 0; |
40 size_t max_stack_depth = 0; | 53 size_t max_stack_depth = 0; |
41 uint64_t analysis_interval_kb = 0; | 54 uint64_t analysis_interval_kb = 0; |
42 uint32_t size_suspicion_threshold = 0; | 55 uint32_t size_suspicion_threshold = 0; |
43 uint32_t call_stack_suspicion_threshold = 0; | 56 uint32_t call_stack_suspicion_threshold = 0; |
44 | 57 |
45 // Get a mapping of param names to param values. | 58 const ParamsMap params = GetRawVariationParams(); |
46 std::map<std::string, std::string> params; | |
47 variations::GetVariationParams(kFieldTrialName, ¶ms); | |
48 | 59 |
49 // Even if the variation param data does not exist and |params| ends up empty, | 60 // Even if the variation param data does not exist and |params| ends up empty, |
50 // the below code will assign default values. | 61 // the below code will assign default values. |
51 auto iter = params.find(kSamplingRateParam); | 62 auto iter = params.find(kSamplingRateParam); |
52 if (iter == params.end() || | 63 if (iter == params.end() || |
53 !base::StringToDouble(iter->second, &sampling_rate)) { | 64 !base::StringToDouble(iter->second, &sampling_rate)) { |
54 sampling_rate = kDefaultSamplingRate; | 65 sampling_rate = kDefaultSamplingRate; |
55 } | 66 } |
56 | 67 |
57 iter = params.find(kMaxStackDepthParam); | 68 iter = params.find(kMaxStackDepthParam); |
(...skipping 22 matching lines...) Expand all Loading... |
80 | 91 |
81 MemoryLeakReportProto_Params result; | 92 MemoryLeakReportProto_Params result; |
82 result.set_sampling_rate(sampling_rate); | 93 result.set_sampling_rate(sampling_rate); |
83 result.set_max_stack_depth(max_stack_depth); | 94 result.set_max_stack_depth(max_stack_depth); |
84 result.set_analysis_interval_bytes(analysis_interval_kb * 1024); | 95 result.set_analysis_interval_bytes(analysis_interval_kb * 1024); |
85 result.set_size_suspicion_threshold(size_suspicion_threshold); | 96 result.set_size_suspicion_threshold(size_suspicion_threshold); |
86 result.set_call_stack_suspicion_threshold(call_stack_suspicion_threshold); | 97 result.set_call_stack_suspicion_threshold(call_stack_suspicion_threshold); |
87 return result; | 98 return result; |
88 } | 99 } |
89 | 100 |
| 101 // Parses the parameters related to randomly enabling leak detector on different |
| 102 // processes, from the raw parameter strings provided by the variations. |
| 103 // Args: |
| 104 // - browser_probability: probability that the leak detector will be enabled on |
| 105 // browser process (spawned once per session). |
| 106 // - renderer_probability: probability that the leak detector will be enabled on |
| 107 // renderer process (spawned many times per session). |
| 108 // - max_renderer_processes_enabled: The maximum number of renderer processes on |
| 109 // which the leak detector can be enabled |
| 110 // simultaneously. |
| 111 // |
| 112 // Probabilities are in the range [0, 1]. Anything higher or lower will not be |
| 113 // clamped but it will not affect the outcome, since these probabilities are |
| 114 // compared against the value of base::RandDouble() (aka the "dice roll"), which |
| 115 // will be within this range. |
| 116 void GetLeakDetectorEnableParams(double* browser_probability, |
| 117 double* renderer_probability, |
| 118 int* max_renderer_processes_enabled) { |
| 119 const char kBrowserEnableProbabilityParam[] = |
| 120 "browser_process_enable_probability"; |
| 121 const char kRendererEnableProbabilityParam[] = |
| 122 "renderer_process_enable_probability"; |
| 123 const char kMaxRendererProcessesEnabledParam[] = |
| 124 "max_renderer_processes_enabled"; |
| 125 const double kDefaultProbability = 0.0; |
| 126 const int kDefaultNumProcessesEnabled = 0; |
| 127 |
| 128 const ParamsMap params = GetRawVariationParams(); |
| 129 auto iter = params.find(kBrowserEnableProbabilityParam); |
| 130 if (iter == params.end() || |
| 131 !base::StringToDouble(iter->second, browser_probability)) { |
| 132 *browser_probability = kDefaultProbability; |
| 133 } |
| 134 iter = params.find(kRendererEnableProbabilityParam); |
| 135 if (iter == params.end() || |
| 136 !base::StringToDouble(iter->second, renderer_probability)) { |
| 137 *renderer_probability = kDefaultProbability; |
| 138 } |
| 139 iter = params.find(kMaxRendererProcessesEnabledParam); |
| 140 if (iter == params.end() || |
| 141 !base::StringToInt(iter->second, max_renderer_processes_enabled)) { |
| 142 *max_renderer_processes_enabled = kDefaultNumProcessesEnabled; |
| 143 } |
| 144 } |
| 145 |
90 } // namespace | 146 } // namespace |
91 | 147 |
92 LeakDetectorController::LeakDetectorController() | 148 LeakDetectorController::LeakDetectorController() |
93 : params_(GetVariationParameters()) { | 149 : params_(GetLeakDetectorParams()), |
| 150 browser_process_enable_probability_(0), |
| 151 renderer_process_enable_probability_(0), |
| 152 max_renderer_processes_with_leak_detector_enabled_(0), |
| 153 num_renderer_processes_with_leak_detector_enabled_(0) { |
94 // Read the build ID once and store it. | 154 // Read the build ID once and store it. |
95 leak_detector::gnu_build_id_reader::ReadBuildID(&build_id_); | 155 leak_detector::gnu_build_id_reader::ReadBuildID(&build_id_); |
96 | 156 |
97 LeakDetector* detector = LeakDetector::GetInstance(); | 157 GetLeakDetectorEnableParams( |
98 detector->AddObserver(this); | 158 &browser_process_enable_probability_, |
| 159 &renderer_process_enable_probability_, |
| 160 &max_renderer_processes_with_leak_detector_enabled_); |
99 | 161 |
100 // Leak detector parameters are stored in |params_|. | 162 // Register the LeakDetectorController with the remote controller, so this |
101 detector->Init(params_, content::BrowserThread::GetTaskRunnerForThread( | 163 // class can send/receive data to/from remote processes. |
102 content::BrowserThread::UI)); | 164 LeakDetectorRemoteController::SetLocalControllerInstance(this); |
| 165 |
| 166 // Conditionally launch browser process based on probability. |
| 167 if (base::RandDouble() < browser_process_enable_probability_) { |
| 168 LeakDetector* detector = LeakDetector::GetInstance(); |
| 169 detector->AddObserver(this); |
| 170 |
| 171 // Leak detector parameters are stored in |params_|. |
| 172 detector->Init(params_, content::BrowserThread::GetTaskRunnerForThread( |
| 173 content::BrowserThread::UI)); |
| 174 } |
103 } | 175 } |
104 | 176 |
105 LeakDetectorController::~LeakDetectorController() { | 177 LeakDetectorController::~LeakDetectorController() { |
106 DCHECK(thread_checker_.CalledOnValidThread()); | 178 DCHECK(thread_checker_.CalledOnValidThread()); |
107 LeakDetector::GetInstance()->RemoveObserver(this); | 179 LeakDetector::GetInstance()->RemoveObserver(this); |
108 } | 180 } |
109 | 181 |
110 void LeakDetectorController::GetLeakReports( | 182 void LeakDetectorController::GetLeakReports( |
111 std::vector<MemoryLeakReportProto>* reports) { | 183 std::vector<MemoryLeakReportProto>* reports) { |
112 DCHECK(thread_checker_.CalledOnValidThread()); | 184 DCHECK(thread_checker_.CalledOnValidThread()); |
113 reports->swap(stored_reports_); | 185 reports->swap(stored_reports_); |
114 stored_reports_.clear(); | 186 stored_reports_.clear(); |
115 } | 187 } |
116 | 188 |
117 void LeakDetectorController::OnLeaksFound( | 189 void LeakDetectorController::OnLeaksFound( |
118 const std::vector<MemoryLeakReportProto>& reports) { | 190 const std::vector<MemoryLeakReportProto>& reports) { |
119 StoreLeakReports(reports, MemoryLeakReportProto::BROWSER_PROCESS); | 191 StoreLeakReports(reports, MemoryLeakReportProto::BROWSER_PROCESS); |
120 } | 192 } |
121 | 193 |
122 MemoryLeakReportProto_Params LeakDetectorController::GetParams() const { | 194 MemoryLeakReportProto_Params |
123 return params_; | 195 LeakDetectorController::GetParamsAndRecordRequest() { |
| 196 if (ShouldRandomlyEnableLeakDetectorOnRendererProcess()) { |
| 197 ++num_renderer_processes_with_leak_detector_enabled_; |
| 198 return params_; |
| 199 } |
| 200 // If the leak detector is not to be enabled on the remote process, send an |
| 201 // empty MemoryLeakReportProto_Params protobuf. The remote process will not |
| 202 // initialize the leak detector since |sampling_rate| is 0. |
| 203 return MemoryLeakReportProto_Params(); |
124 } | 204 } |
125 | 205 |
126 void LeakDetectorController::SendLeakReports( | 206 void LeakDetectorController::SendLeakReports( |
127 const std::vector<MemoryLeakReportProto>& reports) { | 207 const std::vector<MemoryLeakReportProto>& reports) { |
128 StoreLeakReports(reports, MemoryLeakReportProto::RENDERER_PROCESS); | 208 StoreLeakReports(reports, MemoryLeakReportProto::RENDERER_PROCESS); |
129 } | 209 } |
130 | 210 |
131 void LeakDetectorController::OnRemoteProcessShutdown() { | 211 void LeakDetectorController::OnRemoteProcessShutdown() { |
132 // TODO(sque): Handle remote process shutdown. | 212 DCHECK_GT(num_renderer_processes_with_leak_detector_enabled_, 0); |
| 213 --num_renderer_processes_with_leak_detector_enabled_; |
| 214 } |
| 215 |
| 216 bool LeakDetectorController::ShouldRandomlyEnableLeakDetectorOnRendererProcess() |
| 217 const { |
| 218 return base::RandDouble() < renderer_process_enable_probability_ && |
| 219 num_renderer_processes_with_leak_detector_enabled_ < |
| 220 max_renderer_processes_with_leak_detector_enabled_; |
133 } | 221 } |
134 | 222 |
135 void LeakDetectorController::StoreLeakReports( | 223 void LeakDetectorController::StoreLeakReports( |
136 const std::vector<MemoryLeakReportProto>& reports, | 224 const std::vector<MemoryLeakReportProto>& reports, |
137 MemoryLeakReportProto::ProcessType process_type) { | 225 MemoryLeakReportProto::ProcessType process_type) { |
138 DCHECK(thread_checker_.CalledOnValidThread()); | 226 DCHECK(thread_checker_.CalledOnValidThread()); |
139 | 227 |
140 for (const auto& report : reports) { | 228 for (const auto& report : reports) { |
141 // Store the report and insert stored parameters. | 229 // Store the report and insert stored parameters. |
142 stored_reports_.push_back(report); | 230 stored_reports_.push_back(report); |
143 stored_reports_.back().mutable_params()->CopyFrom(params_); | 231 stored_reports_.back().mutable_params()->CopyFrom(params_); |
144 stored_reports_.back().set_source_process(process_type); | 232 stored_reports_.back().set_source_process(process_type); |
145 stored_reports_.back().mutable_build_id()->assign(build_id_.begin(), | 233 stored_reports_.back().mutable_build_id()->assign(build_id_.begin(), |
146 build_id_.end()); | 234 build_id_.end()); |
147 } | 235 } |
148 } | 236 } |
149 | 237 |
150 } // namespace metrics | 238 } // namespace metrics |
OLD | NEW |