| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/metrics_log.h" | 5 #include "chrome/browser/metrics/metrics_log.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/base64.h" | 11 #include "base/base64.h" |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/cpu.h" | 14 #include "base/cpu.h" |
| 15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/prefs/pref_registry_simple.h" | 16 #include "base/prefs/pref_registry_simple.h" |
| 17 #include "base/prefs/pref_service.h" | 17 #include "base/prefs/pref_service.h" |
| 18 #include "base/profiler/alternate_timer.h" | |
| 19 #include "base/sha1.h" | 18 #include "base/sha1.h" |
| 20 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 21 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 22 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 23 #include "base/sys_info.h" | 22 #include "base/sys_info.h" |
| 24 #include "base/third_party/nspr/prtime.h" | |
| 25 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 26 #include "base/tracked_objects.h" | |
| 27 #include "chrome/browser/browser_process.h" | |
| 28 #include "chrome/common/pref_names.h" | 24 #include "chrome/common/pref_names.h" |
| 29 #include "components/metrics/metrics_provider.h" | 25 #include "components/metrics/metrics_provider.h" |
| 30 #include "components/metrics/metrics_service_client.h" | 26 #include "components/metrics/metrics_service_client.h" |
| 31 #include "components/metrics/proto/profiler_event.pb.h" | |
| 32 #include "components/metrics/proto/system_profile.pb.h" | 27 #include "components/metrics/proto/system_profile.pb.h" |
| 33 #include "components/nacl/common/nacl_process_type.h" | |
| 34 #include "components/variations/active_field_trials.h" | 28 #include "components/variations/active_field_trials.h" |
| 35 #include "content/public/common/content_client.h" | |
| 36 #include "url/gurl.h" | |
| 37 | 29 |
| 38 #if defined(OS_ANDROID) | 30 #if defined(OS_ANDROID) |
| 39 #include "base/android/build_info.h" | 31 #include "base/android/build_info.h" |
| 40 #endif | 32 #endif |
| 41 | 33 |
| 42 #if defined(OS_WIN) | 34 #if defined(OS_WIN) |
| 43 #include "base/win/metro.h" | 35 #include "base/win/metro.h" |
| 44 | 36 |
| 45 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx | 37 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx |
| 46 extern "C" IMAGE_DOS_HEADER __ImageBase; | 38 extern "C" IMAGE_DOS_HEADER __ImageBase; |
| 47 #endif | 39 #endif |
| 48 | 40 |
| 49 using metrics::MetricsLogBase; | 41 using metrics::MetricsLogBase; |
| 50 using metrics::ProfilerEventProto; | 42 using metrics::ProfilerEventProto; |
| 51 using metrics::SystemProfileProto; | 43 using metrics::SystemProfileProto; |
| 52 using tracked_objects::ProcessDataSnapshot; | |
| 53 typedef variations::ActiveGroupId ActiveGroupId; | 44 typedef variations::ActiveGroupId ActiveGroupId; |
| 54 | 45 |
| 55 namespace { | 46 namespace { |
| 56 | 47 |
| 57 // Returns the date at which the current metrics client ID was created as | 48 // Returns the date at which the current metrics client ID was created as |
| 58 // a string containing seconds since the epoch, or "0" if none was found. | 49 // a string containing seconds since the epoch, or "0" if none was found. |
| 59 std::string GetMetricsEnabledDate(PrefService* pref) { | 50 std::string GetMetricsEnabledDate(PrefService* pref) { |
| 60 if (!pref) { | 51 if (!pref) { |
| 61 NOTREACHED(); | 52 NOTREACHED(); |
| 62 return "0"; | 53 return "0"; |
| 63 } | 54 } |
| 64 | 55 |
| 65 return pref->GetString(prefs::kMetricsReportingEnabledTimestamp); | 56 return pref->GetString(prefs::kMetricsReportingEnabledTimestamp); |
| 66 } | 57 } |
| 67 | 58 |
| 68 ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType( | |
| 69 int process_type) { | |
| 70 switch (process_type) { | |
| 71 case content::PROCESS_TYPE_BROWSER: | |
| 72 return ProfilerEventProto::TrackedObject::BROWSER; | |
| 73 case content::PROCESS_TYPE_RENDERER: | |
| 74 return ProfilerEventProto::TrackedObject::RENDERER; | |
| 75 case content::PROCESS_TYPE_PLUGIN: | |
| 76 return ProfilerEventProto::TrackedObject::PLUGIN; | |
| 77 case content::PROCESS_TYPE_WORKER: | |
| 78 return ProfilerEventProto::TrackedObject::WORKER; | |
| 79 case content::PROCESS_TYPE_UTILITY: | |
| 80 return ProfilerEventProto::TrackedObject::UTILITY; | |
| 81 case content::PROCESS_TYPE_ZYGOTE: | |
| 82 return ProfilerEventProto::TrackedObject::ZYGOTE; | |
| 83 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
| 84 return ProfilerEventProto::TrackedObject::SANDBOX_HELPER; | |
| 85 case content::PROCESS_TYPE_GPU: | |
| 86 return ProfilerEventProto::TrackedObject::GPU; | |
| 87 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
| 88 return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN; | |
| 89 case content::PROCESS_TYPE_PPAPI_BROKER: | |
| 90 return ProfilerEventProto::TrackedObject::PPAPI_BROKER; | |
| 91 case PROCESS_TYPE_NACL_LOADER: | |
| 92 return ProfilerEventProto::TrackedObject::NACL_LOADER; | |
| 93 case PROCESS_TYPE_NACL_BROKER: | |
| 94 return ProfilerEventProto::TrackedObject::NACL_BROKER; | |
| 95 default: | |
| 96 NOTREACHED(); | |
| 97 return ProfilerEventProto::TrackedObject::UNKNOWN; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 // Computes a SHA-1 hash of |data| and returns it as a hex string. | 59 // Computes a SHA-1 hash of |data| and returns it as a hex string. |
| 102 std::string ComputeSHA1(const std::string& data) { | 60 std::string ComputeSHA1(const std::string& data) { |
| 103 const std::string sha1 = base::SHA1HashString(data); | 61 const std::string sha1 = base::SHA1HashString(data); |
| 104 return base::HexEncode(sha1.data(), sha1.size()); | 62 return base::HexEncode(sha1.data(), sha1.size()); |
| 105 } | 63 } |
| 106 | 64 |
| 107 void WriteFieldTrials(const std::vector<ActiveGroupId>& field_trial_ids, | 65 void WriteFieldTrials(const std::vector<ActiveGroupId>& field_trial_ids, |
| 108 SystemProfileProto* system_profile) { | 66 SystemProfileProto* system_profile) { |
| 109 for (std::vector<ActiveGroupId>::const_iterator it = | 67 for (std::vector<ActiveGroupId>::const_iterator it = |
| 110 field_trial_ids.begin(); it != field_trial_ids.end(); ++it) { | 68 field_trial_ids.begin(); it != field_trial_ids.end(); ++it) { |
| 111 SystemProfileProto::FieldTrial* field_trial = | 69 SystemProfileProto::FieldTrial* field_trial = |
| 112 system_profile->add_field_trial(); | 70 system_profile->add_field_trial(); |
| 113 field_trial->set_name_id(it->name); | 71 field_trial->set_name_id(it->name); |
| 114 field_trial->set_group_id(it->group); | 72 field_trial->set_group_id(it->group); |
| 115 } | 73 } |
| 116 } | 74 } |
| 117 | 75 |
| 118 // Maps a thread name by replacing trailing sequence of digits with "*". | |
| 119 // Examples: | |
| 120 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*" | |
| 121 // 2. "Chrome_IOThread" => "Chrome_IOThread" | |
| 122 std::string MapThreadName(const std::string& thread_name) { | |
| 123 size_t i = thread_name.length(); | |
| 124 | |
| 125 while (i > 0 && isdigit(thread_name[i - 1])) { | |
| 126 --i; | |
| 127 } | |
| 128 | |
| 129 if (i == thread_name.length()) | |
| 130 return thread_name; | |
| 131 | |
| 132 return thread_name.substr(0, i) + '*'; | |
| 133 } | |
| 134 | |
| 135 // Normalizes a source filename (which is platform- and build-method-dependent) | |
| 136 // by extracting the last component of the full file name. | |
| 137 // Example: "c:\b\build\slave\win\build\src\chrome\app\chrome_main.cc" => | |
| 138 // "chrome_main.cc". | |
| 139 std::string NormalizeFileName(const std::string& file_name) { | |
| 140 const size_t offset = file_name.find_last_of("\\/"); | |
| 141 return offset != std::string::npos ? file_name.substr(offset + 1) : file_name; | |
| 142 } | |
| 143 | |
| 144 void WriteProfilerData(const ProcessDataSnapshot& profiler_data, | |
| 145 int process_type, | |
| 146 ProfilerEventProto* performance_profile) { | |
| 147 for (std::vector<tracked_objects::TaskSnapshot>::const_iterator it = | |
| 148 profiler_data.tasks.begin(); | |
| 149 it != profiler_data.tasks.end(); ++it) { | |
| 150 const tracked_objects::DeathDataSnapshot& death_data = it->death_data; | |
| 151 ProfilerEventProto::TrackedObject* tracked_object = | |
| 152 performance_profile->add_tracked_object(); | |
| 153 tracked_object->set_birth_thread_name_hash( | |
| 154 MetricsLogBase::Hash(MapThreadName(it->birth.thread_name))); | |
| 155 tracked_object->set_exec_thread_name_hash( | |
| 156 MetricsLogBase::Hash(MapThreadName(it->death_thread_name))); | |
| 157 tracked_object->set_source_file_name_hash( | |
| 158 MetricsLogBase::Hash(NormalizeFileName(it->birth.location.file_name))); | |
| 159 tracked_object->set_source_function_name_hash( | |
| 160 MetricsLogBase::Hash(it->birth.location.function_name)); | |
| 161 tracked_object->set_source_line_number(it->birth.location.line_number); | |
| 162 tracked_object->set_exec_count(death_data.count); | |
| 163 tracked_object->set_exec_time_total(death_data.run_duration_sum); | |
| 164 tracked_object->set_exec_time_sampled(death_data.run_duration_sample); | |
| 165 tracked_object->set_queue_time_total(death_data.queue_duration_sum); | |
| 166 tracked_object->set_queue_time_sampled(death_data.queue_duration_sample); | |
| 167 tracked_object->set_process_type(AsProtobufProcessType(process_type)); | |
| 168 tracked_object->set_process_id(profiler_data.process_id); | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 // Round a timestamp measured in seconds since epoch to one with a granularity | 76 // Round a timestamp measured in seconds since epoch to one with a granularity |
| 173 // of an hour. This can be used before uploaded potentially sensitive | 77 // of an hour. This can be used before uploaded potentially sensitive |
| 174 // timestamps. | 78 // timestamps. |
| 175 int64 RoundSecondsToHour(int64 time_in_seconds) { | 79 int64 RoundSecondsToHour(int64 time_in_seconds) { |
| 176 return 3600 * (time_in_seconds / 3600); | 80 return 3600 * (time_in_seconds / 3600); |
| 177 } | 81 } |
| 178 | 82 |
| 179 } // namespace | 83 } // namespace |
| 180 | 84 |
| 181 MetricsLog::MetricsLog(const std::string& client_id, | 85 MetricsLog::MetricsLog(const std::string& client_id, |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 local_state->ClearPref(prefs::kStabilitySavedSystemProfile); | 305 local_state->ClearPref(prefs::kStabilitySavedSystemProfile); |
| 402 local_state->ClearPref(prefs::kStabilitySavedSystemProfileHash); | 306 local_state->ClearPref(prefs::kStabilitySavedSystemProfileHash); |
| 403 | 307 |
| 404 SystemProfileProto* system_profile = uma_proto()->mutable_system_profile(); | 308 SystemProfileProto* system_profile = uma_proto()->mutable_system_profile(); |
| 405 std::string serialied_system_profile; | 309 std::string serialied_system_profile; |
| 406 return base::Base64Decode(base64_system_profile, &serialied_system_profile) && | 310 return base::Base64Decode(base64_system_profile, &serialied_system_profile) && |
| 407 ComputeSHA1(serialied_system_profile) == system_profile_hash && | 311 ComputeSHA1(serialied_system_profile) == system_profile_hash && |
| 408 system_profile->ParseFromString(serialied_system_profile); | 312 system_profile->ParseFromString(serialied_system_profile); |
| 409 } | 313 } |
| 410 | 314 |
| 411 void MetricsLog::RecordProfilerData( | |
| 412 const tracked_objects::ProcessDataSnapshot& process_data, | |
| 413 int process_type) { | |
| 414 DCHECK(!locked()); | |
| 415 | |
| 416 if (tracked_objects::GetTimeSourceType() != | |
| 417 tracked_objects::TIME_SOURCE_TYPE_WALL_TIME) { | |
| 418 // We currently only support the default time source, wall clock time. | |
| 419 return; | |
| 420 } | |
| 421 | |
| 422 ProfilerEventProto* profile; | |
| 423 if (!uma_proto()->profiler_event_size()) { | |
| 424 // For the first process's data, add a new field to the protocol buffer. | |
| 425 profile = uma_proto()->add_profiler_event(); | |
| 426 profile->set_profile_type(ProfilerEventProto::STARTUP_PROFILE); | |
| 427 profile->set_time_source(ProfilerEventProto::WALL_CLOCK_TIME); | |
| 428 } else { | |
| 429 // For the remaining calls, re-use the existing field. | |
| 430 profile = uma_proto()->mutable_profiler_event(0); | |
| 431 } | |
| 432 | |
| 433 WriteProfilerData(process_data, process_type, profile); | |
| 434 } | |
| OLD | NEW |