Home | History | Annotate | Download | only in metrics
      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.
      4 
      5 #include "chrome/browser/metrics/profiler_metrics_provider.h"
      6 
      7 #include <ctype.h>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/tracked_objects.h"
     12 #include "components/metrics/metrics_log.h"
     13 #include "components/nacl/common/nacl_process_type.h"
     14 #include "content/public/common/process_type.h"
     15 
     16 using metrics::ProfilerEventProto;
     17 using tracked_objects::ProcessDataSnapshot;
     18 
     19 namespace {
     20 
     21 ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType(
     22     int process_type) {
     23   switch (process_type) {
     24     case content::PROCESS_TYPE_BROWSER:
     25       return ProfilerEventProto::TrackedObject::BROWSER;
     26     case content::PROCESS_TYPE_RENDERER:
     27       return ProfilerEventProto::TrackedObject::RENDERER;
     28     case content::PROCESS_TYPE_PLUGIN:
     29       return ProfilerEventProto::TrackedObject::PLUGIN;
     30     case content::PROCESS_TYPE_WORKER:
     31       return ProfilerEventProto::TrackedObject::WORKER;
     32     case content::PROCESS_TYPE_UTILITY:
     33       return ProfilerEventProto::TrackedObject::UTILITY;
     34     case content::PROCESS_TYPE_ZYGOTE:
     35       return ProfilerEventProto::TrackedObject::ZYGOTE;
     36     case content::PROCESS_TYPE_SANDBOX_HELPER:
     37       return ProfilerEventProto::TrackedObject::SANDBOX_HELPER;
     38     case content::PROCESS_TYPE_GPU:
     39       return ProfilerEventProto::TrackedObject::GPU;
     40     case content::PROCESS_TYPE_PPAPI_PLUGIN:
     41       return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
     42     case content::PROCESS_TYPE_PPAPI_BROKER:
     43       return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
     44     case PROCESS_TYPE_NACL_LOADER:
     45       return ProfilerEventProto::TrackedObject::NACL_LOADER;
     46     case PROCESS_TYPE_NACL_BROKER:
     47       return ProfilerEventProto::TrackedObject::NACL_BROKER;
     48     default:
     49       NOTREACHED();
     50       return ProfilerEventProto::TrackedObject::UNKNOWN;
     51   }
     52 }
     53 
     54 // Maps a thread name by replacing trailing sequence of digits with "*".
     55 // Examples:
     56 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*"
     57 // 2. "Chrome_IOThread" => "Chrome_IOThread"
     58 std::string MapThreadName(const std::string& thread_name) {
     59   size_t i = thread_name.length();
     60 
     61   while (i > 0 && isdigit(thread_name[i - 1])) {
     62     --i;
     63   }
     64 
     65   if (i == thread_name.length())
     66     return thread_name;
     67 
     68   return thread_name.substr(0, i) + '*';
     69 }
     70 
     71 // Normalizes a source filename (which is platform- and build-method-dependent)
     72 // by extracting the last component of the full file name.
     73 // Example: "c:\b\build\slave\win\build\src\chrome\app\chrome_main.cc" =>
     74 // "chrome_main.cc".
     75 std::string NormalizeFileName(const std::string& file_name) {
     76   const size_t offset = file_name.find_last_of("\\/");
     77   return offset != std::string::npos ? file_name.substr(offset + 1) : file_name;
     78 }
     79 
     80 void WriteProfilerData(const ProcessDataSnapshot& profiler_data,
     81                        int process_type,
     82                        ProfilerEventProto* performance_profile) {
     83   for (std::vector<tracked_objects::TaskSnapshot>::const_iterator it =
     84            profiler_data.tasks.begin();
     85        it != profiler_data.tasks.end();
     86        ++it) {
     87     const tracked_objects::DeathDataSnapshot& death_data = it->death_data;
     88     ProfilerEventProto::TrackedObject* tracked_object =
     89         performance_profile->add_tracked_object();
     90     tracked_object->set_birth_thread_name_hash(
     91         MetricsLog::Hash(MapThreadName(it->birth.thread_name)));
     92     tracked_object->set_exec_thread_name_hash(
     93         MetricsLog::Hash(MapThreadName(it->death_thread_name)));
     94     tracked_object->set_source_file_name_hash(
     95         MetricsLog::Hash(NormalizeFileName(it->birth.location.file_name)));
     96     tracked_object->set_source_function_name_hash(
     97         MetricsLog::Hash(it->birth.location.function_name));
     98     tracked_object->set_source_line_number(it->birth.location.line_number);
     99     tracked_object->set_exec_count(death_data.count);
    100     tracked_object->set_exec_time_total(death_data.run_duration_sum);
    101     tracked_object->set_exec_time_sampled(death_data.run_duration_sample);
    102     tracked_object->set_queue_time_total(death_data.queue_duration_sum);
    103     tracked_object->set_queue_time_sampled(death_data.queue_duration_sample);
    104     tracked_object->set_process_type(AsProtobufProcessType(process_type));
    105     tracked_object->set_process_id(profiler_data.process_id);
    106   }
    107 }
    108 
    109 }  // namespace
    110 
    111 ProfilerMetricsProvider::ProfilerMetricsProvider() : has_profiler_data_(false) {
    112 }
    113 
    114 ProfilerMetricsProvider::~ProfilerMetricsProvider() {
    115 }
    116 
    117 void ProfilerMetricsProvider::ProvideGeneralMetrics(
    118     metrics::ChromeUserMetricsExtension* uma_proto) {
    119   if (!has_profiler_data_)
    120     return;
    121 
    122   DCHECK_EQ(tracked_objects::TIME_SOURCE_TYPE_WALL_TIME,
    123             tracked_objects::GetTimeSourceType());
    124 
    125   DCHECK_EQ(0, uma_proto->profiler_event_size());
    126   ProfilerEventProto* profile = uma_proto->add_profiler_event();
    127   profile->Swap(&profiler_event_cache_);
    128   has_profiler_data_ = false;
    129 }
    130 
    131 void ProfilerMetricsProvider::RecordProfilerData(
    132     const tracked_objects::ProcessDataSnapshot& process_data,
    133     int process_type) {
    134   if (tracked_objects::GetTimeSourceType() !=
    135       tracked_objects::TIME_SOURCE_TYPE_WALL_TIME) {
    136     // We currently only support the default time source, wall clock time.
    137     return;
    138   }
    139 
    140   has_profiler_data_ = true;
    141   profiler_event_cache_.set_profile_type(ProfilerEventProto::STARTUP_PROFILE);
    142   profiler_event_cache_.set_time_source(ProfilerEventProto::WALL_CLOCK_TIME);
    143   WriteProfilerData(process_data, process_type, &profiler_event_cache_);
    144 }
    145