Home | History | Annotate | Download | only in task_profiler
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/task_profiler/task_profiler_data_serializer.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/file_path.h"
      9 #include "base/json/json_string_value_serializer.h"
     10 #include "base/time/time.h"
     11 #include "base/tracked_objects.h"
     12 #include "content/public/common/content_client.h"
     13 #include "content/public/common/process_type.h"
     14 #include "url/gurl.h"
     15 
     16 using base::DictionaryValue;
     17 using base::ListValue;
     18 using base::Value;
     19 using tracked_objects::BirthOnThreadSnapshot;
     20 using tracked_objects::DeathDataSnapshot;
     21 using tracked_objects::LocationSnapshot;
     22 using tracked_objects::ParentChildPairSnapshot;
     23 using tracked_objects::TaskSnapshot;
     24 using tracked_objects::ProcessDataSnapshot;
     25 
     26 namespace {
     27 
     28 // Re-serializes the |location| into |dictionary|.
     29 void LocationSnapshotToValue(const LocationSnapshot& location,
     30                              DictionaryValue* dictionary) {
     31   dictionary->Set("file_name", Value::CreateStringValue(location.file_name));
     32   // Note: This function name is not escaped, and templates have less-than
     33   // characters, which means this is not suitable for display as HTML unless
     34   // properly escaped.
     35   dictionary->Set("function_name",
     36                   Value::CreateStringValue(location.function_name));
     37   dictionary->Set("line_number",
     38                   Value::CreateIntegerValue(location.line_number));
     39 }
     40 
     41 // Re-serializes the |birth| into |dictionary|.  Prepends the |prefix| to the
     42 // "thread" and "location" key names in the dictionary.
     43 void BirthOnThreadSnapshotToValue(const BirthOnThreadSnapshot& birth,
     44                                   const std::string& prefix,
     45                                   DictionaryValue* dictionary) {
     46   DCHECK(!prefix.empty());
     47 
     48   scoped_ptr<DictionaryValue> location_value(new DictionaryValue);
     49   LocationSnapshotToValue(birth.location, location_value.get());
     50   dictionary->Set(prefix + "_location", location_value.release());
     51 
     52   dictionary->Set(prefix + "_thread",
     53                   Value::CreateStringValue(birth.thread_name));
     54 }
     55 
     56 // Re-serializes the |death_data| into |dictionary|.
     57 void DeathDataSnapshotToValue(const DeathDataSnapshot& death_data,
     58                               base::DictionaryValue* dictionary) {
     59   dictionary->Set("count",
     60                   Value::CreateIntegerValue(death_data.count));
     61   dictionary->Set("run_ms",
     62                   Value::CreateIntegerValue(death_data.run_duration_sum));
     63   dictionary->Set("run_ms_max",
     64                   Value::CreateIntegerValue(death_data.run_duration_max));
     65   dictionary->Set("run_ms_sample",
     66                   Value::CreateIntegerValue(death_data.run_duration_sample));
     67   dictionary->Set("queue_ms",
     68                   Value::CreateIntegerValue(death_data.queue_duration_sum));
     69   dictionary->Set("queue_ms_max",
     70                   Value::CreateIntegerValue(death_data.queue_duration_max));
     71   dictionary->Set("queue_ms_sample",
     72                   Value::CreateIntegerValue(death_data.queue_duration_sample));
     73 
     74 }
     75 
     76 // Re-serializes the |snapshot| into |dictionary|.
     77 void TaskSnapshotToValue(const TaskSnapshot& snapshot,
     78                          base::DictionaryValue* dictionary) {
     79   BirthOnThreadSnapshotToValue(snapshot.birth, "birth", dictionary);
     80 
     81   scoped_ptr<DictionaryValue> death_data(new DictionaryValue);
     82   DeathDataSnapshotToValue(snapshot.death_data, death_data.get());
     83   dictionary->Set("death_data", death_data.release());
     84 
     85   dictionary->Set("death_thread",
     86                   Value::CreateStringValue(snapshot.death_thread_name));
     87 
     88 }
     89 
     90 }  // anonymous namespace
     91 
     92 namespace task_profiler {
     93 
     94 // static
     95 void TaskProfilerDataSerializer::ToValue(
     96     const ProcessDataSnapshot& process_data,
     97     int process_type,
     98     base::DictionaryValue* dictionary) {
     99   scoped_ptr<base::ListValue> tasks_list(new base::ListValue);
    100   for (std::vector<TaskSnapshot>::const_iterator it =
    101            process_data.tasks.begin();
    102        it != process_data.tasks.end(); ++it) {
    103     scoped_ptr<DictionaryValue> snapshot(new DictionaryValue);
    104     TaskSnapshotToValue(*it, snapshot.get());
    105     tasks_list->Append(snapshot.release());
    106   }
    107   dictionary->Set("list", tasks_list.release());
    108 
    109   dictionary->SetInteger("process_id", process_data.process_id);
    110   dictionary->SetString("process_type",
    111                         content::GetProcessTypeNameInEnglish(process_type));
    112 
    113   scoped_ptr<base::ListValue> descendants_list(new base::ListValue);
    114   for (std::vector<ParentChildPairSnapshot>::const_iterator it =
    115            process_data.descendants.begin();
    116        it != process_data.descendants.end(); ++it) {
    117     scoped_ptr<base::DictionaryValue> parent_child(new base::DictionaryValue);
    118     BirthOnThreadSnapshotToValue(it->parent, "parent", parent_child.get());
    119     BirthOnThreadSnapshotToValue(it->child, "child", parent_child.get());
    120     descendants_list->Append(parent_child.release());
    121   }
    122   dictionary->Set("descendants", descendants_list.release());
    123 }
    124 
    125 
    126 bool TaskProfilerDataSerializer::WriteToFile(const base::FilePath& path) {
    127   std::string output;
    128   JSONStringValueSerializer serializer(&output);
    129   serializer.set_pretty_print(true);
    130 
    131   scoped_ptr<base::DictionaryValue> root(new DictionaryValue());
    132 
    133   base::ListValue* snapshot_list = new ListValue();
    134   base::DictionaryValue* shutdown_snapshot = new DictionaryValue();
    135   base::ListValue* per_process_data = new ListValue();
    136 
    137   root->SetInteger("version", 1);
    138   root->SetString("userAgent", content::GetUserAgent(GURL()));
    139 
    140   // TODO(ramant): Collect data from other processes, then add that data to the
    141   // 'per_process_data' array here. Should leverage the TrackingSynchronizer
    142   // class to implement this.
    143   ProcessDataSnapshot this_process_data;
    144   tracked_objects::ThreadData::Snapshot(false, &this_process_data);
    145   scoped_ptr<base::DictionaryValue> this_process_data_json(
    146       new base::DictionaryValue);
    147   TaskProfilerDataSerializer::ToValue(this_process_data,
    148                                       content::PROCESS_TYPE_BROWSER,
    149                                       this_process_data_json.get());
    150   per_process_data->Append(this_process_data_json.release());
    151 
    152   shutdown_snapshot->SetInteger(
    153       "timestamp",
    154       (base::Time::Now() - base::Time::UnixEpoch()).InSeconds());
    155   shutdown_snapshot->Set("data", per_process_data);
    156   snapshot_list->Append(shutdown_snapshot);
    157   root->Set("snapshots", snapshot_list);
    158 
    159   serializer.Serialize(*root);
    160   int data_size = static_cast<int>(output.size());
    161 
    162   return data_size == file_util::WriteFile(path, output.data(), data_size);
    163 }
    164 
    165 }  // namespace task_profiler
    166