| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "components/metrics/call_stack_profile_metrics_provider.h" | 
|  | 6 | 
|  | 7 #include <cstring> | 
|  | 8 #include <map> | 
|  | 9 #include <utility> | 
|  | 10 | 
|  | 11 #include "base/logging.h" | 
|  | 12 #include "base/macros.h" | 
|  | 13 #include "base/profiler/stack_sampling_profiler.h" | 
|  | 14 #include "components/metrics/metrics_hashes.h" | 
|  | 15 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h" | 
|  | 16 | 
|  | 17 using base::StackSamplingProfiler; | 
|  | 18 | 
|  | 19 namespace metrics { | 
|  | 20 | 
|  | 21 namespace { | 
|  | 22 | 
|  | 23 // The protobuf expects the MD5 checksum prefix of the module name. | 
|  | 24 uint64 HashModuleFilename(const base::FilePath& filename) { | 
|  | 25   const base::FilePath::StringType basename = filename.BaseName().value(); | 
|  | 26   // Copy the bytes in basename into a string buffer. | 
|  | 27   size_t basename_length_in_bytes = | 
|  | 28       basename.size() * sizeof(base::FilePath::CharType); | 
|  | 29   std::string name_bytes(basename_length_in_bytes, '\0'); | 
|  | 30   memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes); | 
|  | 31   return HashMetricName(name_bytes); | 
|  | 32 } | 
|  | 33 | 
|  | 34 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to | 
|  | 35 // compute module instruction pointer offsets. | 
|  | 36 void CopySampleToProto( | 
|  | 37     const StackSamplingProfiler::Sample& sample, | 
|  | 38     const std::vector<StackSamplingProfiler::Module>& modules, | 
|  | 39     CallStackProfile::Sample* proto_sample) { | 
|  | 40   for (const StackSamplingProfiler::Frame& frame : sample) { | 
|  | 41     CallStackProfile::Entry* entry = proto_sample->add_entry(); | 
|  | 42     // A frame may not have a valid module. If so, we can't compute the | 
|  | 43     // instruction pointer offset, and we don't want to send bare pointers, so | 
|  | 44     // leave call_stack_entry empty. | 
|  | 45     if (frame.module_index < 0) | 
|  | 46       continue; | 
|  | 47     int64 module_offset = | 
|  | 48         reinterpret_cast<const char*>(frame.instruction_pointer) - | 
|  | 49         reinterpret_cast<const char*>(modules[frame.module_index].base_address); | 
|  | 50     DCHECK_GE(module_offset, 0); | 
|  | 51     entry->set_address(static_cast<uint64>(module_offset)); | 
|  | 52     entry->set_module_id_index(frame.module_index); | 
|  | 53   } | 
|  | 54 } | 
|  | 55 | 
|  | 56 // Transcode |profile| into |proto_profile|. | 
|  | 57 void CopyProfileToProto( | 
|  | 58     const StackSamplingProfiler::Profile& profile, | 
|  | 59     CallStackProfile* proto_profile) { | 
|  | 60   if (profile.samples.empty()) | 
|  | 61     return; | 
|  | 62 | 
|  | 63   if (profile.preserve_sample_ordering) { | 
|  | 64     // Collapse only consecutive repeated samples together. | 
|  | 65     CallStackProfile::Sample* current_sample_proto = nullptr; | 
|  | 66     for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { | 
|  | 67       if (!current_sample_proto || *it != *(it - 1)) { | 
|  | 68         current_sample_proto = proto_profile->add_sample(); | 
|  | 69         CopySampleToProto(*it, profile.modules, current_sample_proto); | 
|  | 70         current_sample_proto->set_count(1); | 
|  | 71       } else { | 
|  | 72         current_sample_proto->set_count(current_sample_proto->count() + 1); | 
|  | 73       } | 
|  | 74     } | 
|  | 75   } else { | 
|  | 76     // Collapse all repeated samples together. | 
|  | 77     std::map<StackSamplingProfiler::Sample, int> sample_index; | 
|  | 78     for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { | 
|  | 79       auto location = sample_index.find(*it); | 
|  | 80       if (location == sample_index.end()) { | 
|  | 81         CallStackProfile::Sample* sample_proto = proto_profile->add_sample(); | 
|  | 82         CopySampleToProto(*it, profile.modules, sample_proto); | 
|  | 83         sample_proto->set_count(1); | 
|  | 84         sample_index.insert( | 
|  | 85             std::make_pair( | 
|  | 86                 *it, static_cast<int>(proto_profile->sample().size()) - 1)); | 
|  | 87       } else { | 
|  | 88         CallStackProfile::Sample* sample_proto = | 
|  | 89             proto_profile->mutable_sample()->Mutable(location->second); | 
|  | 90         sample_proto->set_count(sample_proto->count() + 1); | 
|  | 91       } | 
|  | 92     } | 
|  | 93   } | 
|  | 94 | 
|  | 95   for (const StackSamplingProfiler::Module& module : profile.modules) { | 
|  | 96     CallStackProfile::ModuleIdentifier* module_id = | 
|  | 97         proto_profile->add_module_id(); | 
|  | 98     module_id->set_build_id(module.id); | 
|  | 99     module_id->set_name_md5_prefix(HashModuleFilename(module.filename)); | 
|  | 100   } | 
|  | 101 | 
|  | 102   proto_profile->set_profile_duration_ms( | 
|  | 103       profile.profile_duration.InMilliseconds()); | 
|  | 104   proto_profile->set_sampling_period_ms( | 
|  | 105       profile.sampling_period.InMilliseconds()); | 
|  | 106 } | 
|  | 107 }  // namespace | 
|  | 108 | 
|  | 109 CallStackProfileMetricsProvider::CallStackProfileMetricsProvider() {} | 
|  | 110 | 
|  | 111 CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {} | 
|  | 112 | 
|  | 113 void CallStackProfileMetricsProvider::ProvideGeneralMetrics( | 
|  | 114     ChromeUserMetricsExtension* uma_proto) { | 
|  | 115   std::vector<StackSamplingProfiler::Profile> profiles; | 
|  | 116   if (!source_profiles_for_test_.empty()) | 
|  | 117     profiles.swap(source_profiles_for_test_); | 
|  | 118   else | 
|  | 119     StackSamplingProfiler::GetPendingProfiles(&profiles); | 
|  | 120 | 
|  | 121   for (const StackSamplingProfiler::Profile& profile : profiles) { | 
|  | 122     CallStackProfile* call_stack_profile = | 
|  | 123         uma_proto->add_sampled_profile()->mutable_call_stack_profile(); | 
|  | 124     CopyProfileToProto(profile, call_stack_profile); | 
|  | 125   } | 
|  | 126 } | 
|  | 127 | 
|  | 128 void CallStackProfileMetricsProvider::SetSourceProfilesForTesting( | 
|  | 129     const std::vector<StackSamplingProfiler::Profile>& profiles) { | 
|  | 130   source_profiles_for_test_ = profiles; | 
|  | 131 } | 
|  | 132 | 
|  | 133 }  // namespace metrics | 
| OLD | NEW | 
|---|