[UMA] Add performance profile data to UMA uploads.

BUG=103480
TEST=unit_test --gtest_filter=MetricsLogTest.*


Review URL: http://codereview.chromium.org/9702015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133773 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index 58cdfa1c..47071fa 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -12,11 +12,13 @@
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/perftimer.h"
+#include "base/profiler/alternate_timer.h"
 #include "base/string_number_conversions.h"
 #include "base/string_util.h"
 #include "base/sys_info.h"
 #include "base/third_party/nspr/prtime.h"
 #include "base/time.h"
+#include "base/tracked_objects.h"
 #include "base/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
@@ -27,12 +29,13 @@
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/metrics/proto/omnibox_event.pb.h"
+#include "chrome/common/metrics/proto/profiler_event.pb.h"
 #include "chrome/common/metrics/proto/system_profile.pb.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/gpu_data_manager.h"
-#include "content/public/common/gpu_info.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/gpu_info.h"
 #include "googleurl/src/gurl.h"
 #include "ui/gfx/screen.h"
 #include "webkit/plugins/webplugininfo.h"
@@ -46,7 +49,9 @@
 
 using content::GpuDataManager;
 using metrics::OmniboxEventProto;
+using metrics::ProfilerEventProto;
 using metrics::SystemProfileProto;
+using tracked_objects::ProcessDataSnapshot;
 typedef base::FieldTrial::NameGroupId NameGroupId;
 
 namespace {
@@ -141,6 +146,41 @@
   }
 }
 
+ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType(
+    content::ProcessType process_type) {
+  switch (process_type) {
+    case content::PROCESS_TYPE_BROWSER:
+      return ProfilerEventProto::TrackedObject::BROWSER;
+    case content::PROCESS_TYPE_RENDERER:
+      return ProfilerEventProto::TrackedObject::RENDERER;
+    case content::PROCESS_TYPE_PLUGIN:
+      return ProfilerEventProto::TrackedObject::PLUGIN;
+    case content::PROCESS_TYPE_WORKER:
+      return ProfilerEventProto::TrackedObject::WORKER;
+    case content::PROCESS_TYPE_NACL_LOADER:
+      return ProfilerEventProto::TrackedObject::NACL_LOADER;
+    case content::PROCESS_TYPE_UTILITY:
+      return ProfilerEventProto::TrackedObject::UTILITY;
+    case content::PROCESS_TYPE_PROFILE_IMPORT:
+      return ProfilerEventProto::TrackedObject::PROFILE_IMPORT;
+    case content::PROCESS_TYPE_ZYGOTE:
+      return ProfilerEventProto::TrackedObject::ZYGOTE;
+    case content::PROCESS_TYPE_SANDBOX_HELPER:
+      return ProfilerEventProto::TrackedObject::SANDBOX_HELPER;
+    case content::PROCESS_TYPE_NACL_BROKER:
+      return ProfilerEventProto::TrackedObject::NACL_BROKER;
+    case content::PROCESS_TYPE_GPU:
+      return ProfilerEventProto::TrackedObject::GPU;
+    case content::PROCESS_TYPE_PPAPI_PLUGIN:
+      return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
+    case content::PROCESS_TYPE_PPAPI_BROKER:
+      return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
+    default:
+      NOTREACHED();
+      return ProfilerEventProto::TrackedObject::UNKNOWN;
+  }
+}
+
 // Returns the plugin preferences corresponding for this user, if available.
 // If multiple user profiles are loaded, returns the preferences corresponding
 // to an arbitrary one of the profiles.
@@ -181,6 +221,44 @@
   }
 }
 
+void WriteProfilerData(const ProcessDataSnapshot& profiler_data,
+                       content::ProcessType process_type,
+                       ProfilerEventProto* performance_profile) {
+  for (std::vector<tracked_objects::TaskSnapshot>::const_iterator it =
+           profiler_data.tasks.begin();
+       it != profiler_data.tasks.end(); ++it) {
+    std::string ignored;
+    uint64 birth_thread_name_hash;
+    uint64 exec_thread_name_hash;
+    uint64 source_file_name_hash;
+    uint64 source_function_name_hash;
+    MetricsLogBase::CreateHashes(it->birth.thread_name,
+                                 &ignored, &birth_thread_name_hash);
+    MetricsLogBase::CreateHashes(it->death_thread_name,
+                                 &ignored, &exec_thread_name_hash);
+    MetricsLogBase::CreateHashes(it->birth.location.function_name,
+                                 &ignored, &source_file_name_hash);
+    MetricsLogBase::CreateHashes(it->birth.location.file_name,
+                                 &ignored, &source_function_name_hash);
+
+    const tracked_objects::DeathDataSnapshot& death_data = it->death_data;
+    ProfilerEventProto::TrackedObject* tracked_object =
+        performance_profile->add_tracked_object();
+    tracked_object->set_birth_thread_name_hash(birth_thread_name_hash);
+    tracked_object->set_exec_thread_name_hash(exec_thread_name_hash);
+    tracked_object->set_source_file_name_hash(source_file_name_hash);
+    tracked_object->set_source_function_name_hash(source_function_name_hash);
+    tracked_object->set_source_line_number(it->birth.location.line_number);
+    tracked_object->set_exec_count(death_data.count);
+    tracked_object->set_exec_time_total(death_data.run_duration_sum);
+    tracked_object->set_exec_time_sampled(death_data.run_duration_sample);
+    tracked_object->set_queue_time_total(death_data.queue_duration_sum);
+    tracked_object->set_queue_time_sampled(death_data.queue_duration_sample);
+    tracked_object->set_process_type(AsProtobufProcessType(process_type));
+    tracked_object->set_process_id(profiler_data.process_id);
+  }
+}
+
 }  // namespace
 
 static base::LazyInstance<std::string>::Leaky
@@ -704,6 +782,30 @@
   WriteFieldTrials(field_trial_ids, system_profile);
 }
 
+void MetricsLog::RecordProfilerData(
+    const tracked_objects::ProcessDataSnapshot& process_data,
+    content::ProcessType process_type) {
+  DCHECK(!locked());
+
+  if (tracked_objects::GetAlternateTimeSource()) {
+    // We currently only support the default time source, wall clock time.
+    return;
+  }
+
+  ProfilerEventProto* profile;
+  if (!uma_proto()->profiler_event_size()) {
+    // For the first process's data, add a new field to the protocol buffer.
+    profile = uma_proto()->add_profiler_event();
+    profile->set_profile_type(ProfilerEventProto::STARTUP_PROFILE);
+    profile->set_time_source(ProfilerEventProto::WALL_CLOCK_TIME);
+  } else {
+    // For the remaining calls, re-use the existing field.
+    profile = uma_proto()->mutable_profiler_event(0);
+  }
+
+  WriteProfilerData(process_data, process_type, profile);
+}
+
 void MetricsLog::WriteAllProfilesMetrics(
     const DictionaryValue& all_profiles_metrics) {
   const std::string profile_prefix(prefs::kProfilePrefix);