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

Side by Side Diff: components/metrics/call_stack_profile_metrics_provider.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: abandon generator for on-the-fly Profiles creation Created 4 years 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "components/metrics/call_stack_profile_metrics_provider.h" 5 #include "components/metrics/call_stack_profile_metrics_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 15 matching lines...) Expand all
26 #include "base/threading/thread_task_runner_handle.h" 26 #include "base/threading/thread_task_runner_handle.h"
27 #include "base/time/time.h" 27 #include "base/time/time.h"
28 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h" 28 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
29 29
30 using base::StackSamplingProfiler; 30 using base::StackSamplingProfiler;
31 31
32 namespace metrics { 32 namespace metrics {
33 33
34 namespace { 34 namespace {
35 35
36 // Provide a mapping from the C++ "enum" definition of various process phases
37 // to the equivalent protobuf "enum" definition. This table-lookup conversion
38 // allows for the implementation to evolve and still be compatible with the
39 // protobuf -- even if there are ever more than 32 defined proto values, though
40 // never more than 32 could be in-use in a given C++ version of the code.
41 const ProcessPhase
42 kProtoPhases[CallStackProfileMetricsProvider::PHASES_MAX_VALUE] = {
43 ProcessPhase::MAIN_LOOP_START,
44 ProcessPhase::MAIN_NAVIGATION_START,
45 ProcessPhase::MAIN_NAVIGATION_FINISHED,
46 ProcessPhase::FIRST_NONEMPTY_PAINT,
47
48 ProcessPhase::SHUTDOWN_START,
49 };
50
36 // ProfilesState -------------------------------------------------------------- 51 // ProfilesState --------------------------------------------------------------
37 52
38 // A set of profiles and the CallStackProfileMetricsProvider state associated 53 // A set of profiles and the CallStackProfileMetricsProvider state associated
39 // with them. 54 // with them.
40 struct ProfilesState { 55 struct ProfilesState {
41 ProfilesState(const CallStackProfileParams& params, 56 ProfilesState(const CallStackProfileParams& params,
42 base::StackSamplingProfiler::CallStackProfiles profiles, 57 base::StackSamplingProfiler::CallStackProfiles profiles,
43 base::TimeTicks start_timestamp); 58 base::TimeTicks start_timestamp);
44 ProfilesState(ProfilesState&&); 59 ProfilesState(ProfilesState&&);
45 ProfilesState& operator=(ProfilesState&&); 60 ProfilesState& operator=(ProfilesState&&);
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes); 231 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
217 return base::HashMetricName(name_bytes); 232 return base::HashMetricName(name_bytes);
218 } 233 }
219 234
220 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to 235 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to
221 // compute module instruction pointer offsets. 236 // compute module instruction pointer offsets.
222 void CopySampleToProto( 237 void CopySampleToProto(
223 const StackSamplingProfiler::Sample& sample, 238 const StackSamplingProfiler::Sample& sample,
224 const std::vector<StackSamplingProfiler::Module>& modules, 239 const std::vector<StackSamplingProfiler::Module>& modules,
225 CallStackProfile::Sample* proto_sample) { 240 CallStackProfile::Sample* proto_sample) {
226 for (const StackSamplingProfiler::Frame& frame : sample) { 241 for (const StackSamplingProfiler::Frame& frame : sample.frames) {
227 CallStackProfile::Entry* entry = proto_sample->add_entry(); 242 CallStackProfile::Entry* entry = proto_sample->add_entry();
228 // A frame may not have a valid module. If so, we can't compute the 243 // A frame may not have a valid module. If so, we can't compute the
229 // instruction pointer offset, and we don't want to send bare pointers, so 244 // instruction pointer offset, and we don't want to send bare pointers, so
230 // leave call_stack_entry empty. 245 // leave call_stack_entry empty.
231 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) 246 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex)
232 continue; 247 continue;
233 int64_t module_offset = 248 int64_t module_offset =
234 reinterpret_cast<const char*>(frame.instruction_pointer) - 249 reinterpret_cast<const char*>(frame.instruction_pointer) -
235 reinterpret_cast<const char*>(modules[frame.module_index].base_address); 250 reinterpret_cast<const char*>(modules[frame.module_index].base_address);
236 DCHECK_GE(module_offset, 0); 251 DCHECK_GE(module_offset, 0);
237 entry->set_address(static_cast<uint64_t>(module_offset)); 252 entry->set_address(static_cast<uint64_t>(module_offset));
238 entry->set_module_id_index(frame.module_index); 253 entry->set_module_id_index(frame.module_index);
239 } 254 }
240 } 255 }
241 256
257 // Transcode Sample annotations into protobuf fields. The C++ code uses a bit-
258 // field with each bit corresponding to an entry in an enumeration while the
259 // protobuf uses a repeated field of individual values. Conversion tables
260 // allow for arbitrary mapping, though no more than 32 in any given version
261 // of the code.
262 void CopyAnnotationsToProto(uint32_t new_phases,
263 CallStackProfile::Sample* sample_proto) {
264 for (size_t bit = 0; new_phases != 0 && bit < sizeof(new_phases) * 8; ++bit) {
265 const uint32_t flag = 1U << bit;
266 if (new_phases & flag) {
267 if (bit >= arraysize(kProtoPhases)) {
268 NOTREACHED();
269 continue;
270 }
271 sample_proto->add_process_phase(kProtoPhases[bit]);
272 new_phases ^= flag; // Bit is set so XOR will clear it.
273 }
274 }
275 }
276
242 // Transcode |profile| into |proto_profile|. 277 // Transcode |profile| into |proto_profile|.
243 void CopyProfileToProto( 278 void CopyProfileToProto(
244 const StackSamplingProfiler::CallStackProfile& profile, 279 const StackSamplingProfiler::CallStackProfile& profile,
245 CallStackProfileParams::SampleOrderingSpec ordering_spec, 280 CallStackProfileParams::SampleOrderingSpec ordering_spec,
246 CallStackProfile* proto_profile) { 281 CallStackProfile* proto_profile) {
247 if (profile.samples.empty()) 282 if (profile.samples.empty())
248 return; 283 return;
249 284
250 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) { 285 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) {
251 // Collapse only consecutive repeated samples together. 286 // Collapse only consecutive repeated samples together.
252 CallStackProfile::Sample* current_sample_proto = nullptr; 287 CallStackProfile::Sample* current_sample_proto = nullptr;
288 uint32_t phases = 0;
253 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 289 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
290 // Check if the sample is different than the previous one. Samples match
291 // if the frame and all annotations are the same.
254 if (!current_sample_proto || *it != *(it - 1)) { 292 if (!current_sample_proto || *it != *(it - 1)) {
255 current_sample_proto = proto_profile->add_sample(); 293 current_sample_proto = proto_profile->add_sample();
256 CopySampleToProto(*it, profile.modules, current_sample_proto); 294 CopySampleToProto(*it, profile.modules, current_sample_proto);
257 current_sample_proto->set_count(1); 295 current_sample_proto->set_count(1);
296 CopyAnnotationsToProto(it->process_phases & ~phases,
297 current_sample_proto);
298 phases = it->process_phases;
258 } else { 299 } else {
259 current_sample_proto->set_count(current_sample_proto->count() + 1); 300 current_sample_proto->set_count(current_sample_proto->count() + 1);
260 } 301 }
261 } 302 }
262 } else { 303 } else {
263 // Collapse all repeated samples together. 304 // Collapse all repeated samples together.
264 std::map<StackSamplingProfiler::Sample, int> sample_index; 305 std::map<StackSamplingProfiler::Sample, int> sample_index;
306 uint32_t phases = 0;
265 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 307 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
308 // Check for a sample already seen. Samples match if the frame and all
309 // annotations are the same.
266 auto location = sample_index.find(*it); 310 auto location = sample_index.find(*it);
267 if (location == sample_index.end()) { 311 if (location == sample_index.end()) {
268 CallStackProfile::Sample* sample_proto = proto_profile->add_sample(); 312 CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
269 CopySampleToProto(*it, profile.modules, sample_proto); 313 CopySampleToProto(*it, profile.modules, sample_proto);
270 sample_proto->set_count(1); 314 sample_proto->set_count(1);
315 CopyAnnotationsToProto(it->process_phases & ~phases, sample_proto);
271 sample_index.insert( 316 sample_index.insert(
272 std::make_pair( 317 std::make_pair(
273 *it, static_cast<int>(proto_profile->sample().size()) - 1)); 318 *it, static_cast<int>(proto_profile->sample().size()) - 1));
319 phases = it->process_phases;
274 } else { 320 } else {
275 CallStackProfile::Sample* sample_proto = 321 CallStackProfile::Sample* sample_proto =
276 proto_profile->mutable_sample()->Mutable(location->second); 322 proto_profile->mutable_sample()->Mutable(location->second);
277 sample_proto->set_count(sample_proto->count() + 1); 323 sample_proto->set_count(sample_proto->count() + 1);
278 } 324 }
279 } 325 }
280 } 326 }
281 327
282 for (const StackSamplingProfiler::Module& module : profile.modules) { 328 for (const StackSamplingProfiler::Module& module : profile.modules) {
283 CallStackProfile::ModuleIdentifier* module_id = 329 CallStackProfile::ModuleIdentifier* module_id =
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 489
444 // static 490 // static
445 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() { 491 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() {
446 const std::string group_name = base::FieldTrialList::FindFullName( 492 const std::string group_name = base::FieldTrialList::FindFullName(
447 CallStackProfileMetricsProvider::kFieldTrialName); 493 CallStackProfileMetricsProvider::kFieldTrialName);
448 return group_name == 494 return group_name ==
449 CallStackProfileMetricsProvider::kReportProfilesGroupName; 495 CallStackProfileMetricsProvider::kReportProfilesGroupName;
450 } 496 }
451 497
452 } // namespace metrics 498 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698