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