1 // Copyright 2014 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.
5 #include "components/metrics/profiler/profiler_metrics_provider.h"
11 #include "base/stl_util.h"
12 #include "base/tracked_objects.h"
13 #include "components/metrics/metrics_log.h"
14 #include "components/nacl/common/nacl_process_type.h"
19 ProfilerEventProto::TrackedObject::ProcessType
AsProtobufProcessType(
21 switch (process_type
) {
22 case content::PROCESS_TYPE_BROWSER
:
23 return ProfilerEventProto::TrackedObject::BROWSER
;
24 case content::PROCESS_TYPE_RENDERER
:
25 return ProfilerEventProto::TrackedObject::RENDERER
;
26 case content::PROCESS_TYPE_PLUGIN
:
27 return ProfilerEventProto::TrackedObject::PLUGIN
;
28 case content::PROCESS_TYPE_UTILITY
:
29 return ProfilerEventProto::TrackedObject::UTILITY
;
30 case content::PROCESS_TYPE_ZYGOTE
:
31 return ProfilerEventProto::TrackedObject::ZYGOTE
;
32 case content::PROCESS_TYPE_SANDBOX_HELPER
:
33 return ProfilerEventProto::TrackedObject::SANDBOX_HELPER
;
34 case content::PROCESS_TYPE_GPU
:
35 return ProfilerEventProto::TrackedObject::GPU
;
36 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
37 return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN
;
38 case content::PROCESS_TYPE_PPAPI_BROKER
:
39 return ProfilerEventProto::TrackedObject::PPAPI_BROKER
;
40 case PROCESS_TYPE_NACL_LOADER
:
41 return ProfilerEventProto::TrackedObject::NACL_LOADER
;
42 case PROCESS_TYPE_NACL_BROKER
:
43 return ProfilerEventProto::TrackedObject::NACL_BROKER
;
46 return ProfilerEventProto::TrackedObject::UNKNOWN
;
50 // Maps a thread name by replacing trailing sequence of digits with "*".
52 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*"
53 // 2. "Chrome_IOThread" => "Chrome_IOThread"
54 std::string
MapThreadName(const std::string
& thread_name
) {
55 size_t i
= thread_name
.length();
57 while (i
> 0 && isdigit(thread_name
[i
- 1])) {
61 if (i
== thread_name
.length())
64 return thread_name
.substr(0, i
) + '*';
67 // Normalizes a source filename (which is platform- and build-method-dependent)
68 // by extracting the last component of the full file name.
69 // Example: "c:\b\build\slave\win\build\src\chrome\app\chrome_main.cc" =>
71 std::string
NormalizeFileName(const std::string
& file_name
) {
72 const size_t offset
= file_name
.find_last_of("\\/");
73 return offset
!= std::string::npos
? file_name
.substr(offset
+ 1) : file_name
;
76 void WriteProfilerData(
77 const tracked_objects::ProcessDataPhaseSnapshot
& process_data_phase
,
78 base::ProcessId process_id
,
79 content::ProcessType process_type
,
80 ProfilerEventProto
* performance_profile
) {
81 for (const auto& task
: process_data_phase
.tasks
) {
82 const tracked_objects::DeathDataSnapshot
& death_data
= task
.death_data
;
83 ProfilerEventProto::TrackedObject
* tracked_object
=
84 performance_profile
->add_tracked_object();
85 tracked_object
->set_birth_thread_name_hash(
86 MetricsLog::Hash(MapThreadName(task
.birth
.thread_name
)));
87 tracked_object
->set_exec_thread_name_hash(
88 MetricsLog::Hash(MapThreadName(task
.death_thread_name
)));
89 tracked_object
->set_source_file_name_hash(
90 MetricsLog::Hash(NormalizeFileName(task
.birth
.location
.file_name
)));
91 tracked_object
->set_source_function_name_hash(
92 MetricsLog::Hash(task
.birth
.location
.function_name
));
93 tracked_object
->set_source_line_number(task
.birth
.location
.line_number
);
94 tracked_object
->set_exec_count(death_data
.count
);
95 tracked_object
->set_exec_time_total(death_data
.run_duration_sum
);
96 tracked_object
->set_exec_time_sampled(death_data
.run_duration_sample
);
97 tracked_object
->set_queue_time_total(death_data
.queue_duration_sum
);
98 tracked_object
->set_queue_time_sampled(death_data
.queue_duration_sample
);
99 tracked_object
->set_process_type(AsProtobufProcessType(process_type
));
100 tracked_object
->set_process_id(process_id
);
106 ProfilerMetricsProvider::ProfilerMetricsProvider() {
109 ProfilerMetricsProvider::ProfilerMetricsProvider(
110 const base::Callback
<bool(void)>& cellular_callback
)
111 : cellular_callback_(cellular_callback
) {
114 ProfilerMetricsProvider::~ProfilerMetricsProvider() {
117 void ProfilerMetricsProvider::ProvideGeneralMetrics(
118 ChromeUserMetricsExtension
* uma_proto
) {
119 DCHECK_EQ(tracked_objects::TIME_SOURCE_TYPE_WALL_TIME
,
120 tracked_objects::GetTimeSourceType());
122 DCHECK_EQ(0, uma_proto
->profiler_event_size());
124 for (auto& event
: profiler_events_cache_
) {
125 uma_proto
->add_profiler_event()->Swap(&event
.second
);
128 profiler_events_cache_
.clear();
131 void ProfilerMetricsProvider::RecordProfilerData(
132 const tracked_objects::ProcessDataPhaseSnapshot
& process_data_phase
,
133 base::ProcessId process_id
,
134 content::ProcessType process_type
,
136 base::TimeDelta phase_start
,
137 base::TimeDelta phase_finish
,
138 const ProfilerEvents
& past_events
) {
139 // Omit profiler data on connections where it's likely to cost the user money
140 // for us to upload it.
141 if (IsCellularLogicEnabled())
144 if (tracked_objects::GetTimeSourceType() !=
145 tracked_objects::TIME_SOURCE_TYPE_WALL_TIME
) {
146 // We currently only support the default time source, wall clock time.
150 const bool new_phase
= !ContainsKey(profiler_events_cache_
, profiling_phase
);
151 ProfilerEventProto
* profiler_event
= &profiler_events_cache_
[profiling_phase
];
154 profiler_event
->set_profile_version(
155 ProfilerEventProto::VERSION_SPLIT_PROFILE
);
156 profiler_event
->set_time_source(ProfilerEventProto::WALL_CLOCK_TIME
);
157 profiler_event
->set_profiling_start_ms(phase_start
.InMilliseconds());
158 profiler_event
->set_profiling_finish_ms(phase_finish
.InMilliseconds());
159 for (const auto& event
: past_events
) {
160 profiler_event
->add_past_session_event(event
);
164 WriteProfilerData(process_data_phase
, process_id
, process_type
,
168 bool ProfilerMetricsProvider::IsCellularLogicEnabled() {
169 if (cellular_callback_
.is_null())
172 return cellular_callback_
.Run();
175 } // namespace metrics