Upload upstream chromium 73.0.3683.0
[platform/framework/web/chromium-efl.git] / components / metrics / call_stack_profile_builder.cc
1 // Copyright 2018 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_builder.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10
11 #include "base/files/file_path.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/metrics/metrics_hashes.h"
15 #include "base/no_destructor.h"
16 #include "base/stl_util.h"
17 #include "components/metrics/call_stack_profile_encoding.h"
18
19 namespace metrics {
20
21 namespace {
22
23 // Only used by child processes.
24 base::LazyInstance<ChildCallStackProfileCollector>::Leaky
25     g_child_call_stack_profile_collector = LAZY_INSTANCE_INITIALIZER;
26
27 base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>&
28 GetBrowserProcessReceiverCallbackInstance() {
29   static base::NoDestructor<
30       base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>>
31       instance;
32   return *instance;
33 }
34
35 // Convert |filename| to its MD5 hash.
36 uint64_t HashModuleFilename(const base::FilePath& filename) {
37   const base::FilePath::StringType basename = filename.BaseName().value();
38   // Copy the bytes in basename into a string buffer.
39   size_t basename_length_in_bytes =
40       basename.size() * sizeof(base::FilePath::CharType);
41   std::string name_bytes(basename_length_in_bytes, '\0');
42   memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
43   return base::HashMetricName(name_bytes);
44 }
45
46 }  // namespace
47
48 CallStackProfileBuilder::CallStackProfileBuilder(
49     const CallStackProfileParams& profile_params,
50     const WorkIdRecorder* work_id_recorder,
51     base::OnceClosure completed_callback)
52     : work_id_recorder_(work_id_recorder),
53       profile_start_time_(base::TimeTicks::Now()) {
54   completed_callback_ = std::move(completed_callback);
55   sampled_profile_.set_process(
56       ToExecutionContextProcess(profile_params.process));
57   sampled_profile_.set_thread(ToExecutionContextThread(profile_params.thread));
58   sampled_profile_.set_trigger_event(
59       ToSampledProfileTriggerEvent(profile_params.trigger));
60 }
61
62 CallStackProfileBuilder::~CallStackProfileBuilder() = default;
63
64 // This function is invoked on the profiler thread while the target thread is
65 // suspended so must not take any locks, including indirectly through use of
66 // heap allocation, LOG, CHECK, or DCHECK.
67 void CallStackProfileBuilder::RecordMetadata() {
68   if (!work_id_recorder_)
69     return;
70   unsigned int work_id = work_id_recorder_->RecordWorkId();
71   // A work id of 0 indicates that the message loop has not yet started.
72   if (work_id == 0)
73     return;
74   is_continued_work_ = (last_work_id_ == work_id);
75   last_work_id_ = work_id;
76 }
77
78 void CallStackProfileBuilder::OnSampleCompleted(
79     std::vector<base::StackSamplingProfiler::Frame> frames) {
80   // Write CallStackProfile::Stack protobuf message.
81   CallStackProfile::Stack stack;
82
83   for (const auto& frame : frames) {
84     // keep the frame information even if its module is invalid so we have
85     // visibility into how often this issue is happening on the server.
86     CallStackProfile::Location* location = stack.add_frame();
87     if (!frame.module.is_valid)
88       continue;
89
90     // Dedup modules.
91     const base::ModuleCache::Module& module = frame.module;
92     auto module_loc = module_index_.find(module.base_address);
93     if (module_loc == module_index_.end()) {
94       modules_.push_back(module);
95       size_t index = modules_.size() - 1;
96       module_loc = module_index_.emplace(module.base_address, index).first;
97     }
98
99     // Write CallStackProfile::Location protobuf message.
100     ptrdiff_t module_offset =
101         reinterpret_cast<const char*>(frame.instruction_pointer) -
102         reinterpret_cast<const char*>(module.base_address);
103     DCHECK_GE(module_offset, 0);
104     location->set_address(static_cast<uint64_t>(module_offset));
105     location->set_module_id_index(module_loc->second);
106   }
107
108   CallStackProfile* call_stack_profile =
109       sampled_profile_.mutable_call_stack_profile();
110
111   // Dedup Stacks.
112   auto stack_loc = stack_index_.find(&stack);
113   if (stack_loc == stack_index_.end()) {
114     *call_stack_profile->add_stack() = std::move(stack);
115     int stack_index = call_stack_profile->stack_size() - 1;
116     // It is safe to store the Stack pointer because the repeated message
117     // representation ensures pointer stability.
118     stack_loc = stack_index_
119                     .emplace(call_stack_profile->mutable_stack(stack_index),
120                              stack_index)
121                     .first;
122   }
123
124   // Write CallStackProfile::StackSample protobuf message.
125   CallStackProfile::StackSample* stack_sample_proto =
126       call_stack_profile->add_stack_sample();
127   stack_sample_proto->set_stack_index(stack_loc->second);
128   if (is_continued_work_)
129     stack_sample_proto->set_continued_work(is_continued_work_);
130 }
131
132 void CallStackProfileBuilder::OnProfileCompleted(
133     base::TimeDelta profile_duration,
134     base::TimeDelta sampling_period) {
135   // Build the SampledProfile protobuf message.
136   CallStackProfile* call_stack_profile =
137       sampled_profile_.mutable_call_stack_profile();
138   call_stack_profile->set_profile_duration_ms(
139       profile_duration.InMilliseconds());
140   call_stack_profile->set_sampling_period_ms(sampling_period.InMilliseconds());
141
142   // Write CallStackProfile::ModuleIdentifier protobuf message.
143   for (const auto& module : modules_) {
144     CallStackProfile::ModuleIdentifier* module_id =
145         call_stack_profile->add_module_id();
146     module_id->set_build_id(module.id);
147     module_id->set_name_md5_prefix(HashModuleFilename(module.filename));
148   }
149
150   PassProfilesToMetricsProvider(std::move(sampled_profile_));
151
152   // Run the completed callback if there is one.
153   if (!completed_callback_.is_null())
154     std::move(completed_callback_).Run();
155
156   // Clear the caches.
157   stack_index_.clear();
158   module_index_.clear();
159   modules_.clear();
160 }
161
162 // static
163 void CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
164     const base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>&
165         callback) {
166   GetBrowserProcessReceiverCallbackInstance() = callback;
167 }
168
169 // static
170 void CallStackProfileBuilder::SetParentProfileCollectorForChildProcess(
171     metrics::mojom::CallStackProfileCollectorPtr browser_interface) {
172   g_child_call_stack_profile_collector.Get().SetParentProfileCollector(
173       std::move(browser_interface));
174 }
175
176 void CallStackProfileBuilder::PassProfilesToMetricsProvider(
177     SampledProfile sampled_profile) {
178   if (sampled_profile.process() == BROWSER_PROCESS) {
179     GetBrowserProcessReceiverCallbackInstance().Run(profile_start_time_,
180                                                     std::move(sampled_profile));
181   } else {
182     g_child_call_stack_profile_collector.Get()
183         .ChildCallStackProfileCollector::Collect(profile_start_time_,
184                                                  std::move(sampled_profile));
185   }
186 }
187
188 bool CallStackProfileBuilder::StackComparer::operator()(
189     const CallStackProfile::Stack* stack1,
190     const CallStackProfile::Stack* stack2) const {
191   return std::lexicographical_compare(
192       stack1->frame().begin(), stack1->frame().end(), stack2->frame().begin(),
193       stack2->frame().end(),
194       [](const CallStackProfile::Location& loc1,
195          const CallStackProfile::Location& loc2) {
196         return std::make_pair(loc1.address(), loc1.module_id_index()) <
197                std::make_pair(loc2.address(), loc2.module_id_index());
198       });
199 }
200
201 }  // namespace metrics