15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/task_profiler/task_profiler_data_serializer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_string_value_serializer.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/tracked_objects.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/chrome_content_client.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/process_type.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::DictionaryValue;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::ListValue;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Value;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::BirthOnThreadSnapshot;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::DeathDataSnapshot;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::LocationSnapshot;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::ParentChildPairSnapshot;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::TaskSnapshot;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tracked_objects::ProcessDataSnapshot;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Re-serializes the |location| into |dictionary|.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocationSnapshotToValue(const LocationSnapshot& location,
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             base::DictionaryValue* dictionary) {
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetString("file_name", location.file_name);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: This function name is not escaped, and templates have less-than
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // characters, which means this is not suitable for display as HTML unless
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // properly escaped.
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetString("function_name", location.function_name);
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("line_number", location.line_number);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Re-serializes the |birth| into |dictionary|.  Prepends the |prefix| to the
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "thread" and "location" key names in the dictionary.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BirthOnThreadSnapshotToValue(const BirthOnThreadSnapshot& birth,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& prefix,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  base::DictionaryValue* dictionary) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!prefix.empty());
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> location_value(new base::DictionaryValue);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LocationSnapshotToValue(birth.location, location_value.get());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->Set(prefix + "_location", location_value.release());
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  dictionary->Set(prefix + "_thread", new base::StringValue(birth.thread_name));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Re-serializes the |death_data| into |dictionary|.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeathDataSnapshotToValue(const DeathDataSnapshot& death_data,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              base::DictionaryValue* dictionary) {
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("count", death_data.count);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("run_ms", death_data.run_duration_sum);
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("run_ms_max", death_data.run_duration_max);
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("run_ms_sample", death_data.run_duration_sample);
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("queue_ms", death_data.queue_duration_sum);
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("queue_ms_max", death_data.queue_duration_max);
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetInteger("queue_ms_sample", death_data.queue_duration_sample);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Re-serializes the |snapshot| into |dictionary|.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TaskSnapshotToValue(const TaskSnapshot& snapshot,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::DictionaryValue* dictionary) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BirthOnThreadSnapshotToValue(snapshot.birth, "birth", dictionary);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> death_data(new base::DictionaryValue);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeathDataSnapshotToValue(snapshot.death_data, death_data.get());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->Set("death_data", death_data.release());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dictionary->SetString("death_thread", snapshot.death_thread_name);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace task_profiler {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TaskProfilerDataSerializer::ToValue(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProcessDataSnapshot& process_data,
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int process_type,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* dictionary) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> tasks_list(new base::ListValue);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<TaskSnapshot>::const_iterator it =
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           process_data.tasks.begin();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != process_data.tasks.end(); ++it) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> snapshot(new base::DictionaryValue);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TaskSnapshotToValue(*it, snapshot.get());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tasks_list->Append(snapshot.release());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->Set("list", tasks_list.release());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetInteger("process_id", process_data.process_id);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("process_type",
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        content::GetProcessTypeNameInEnglish(process_type));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> descendants_list(new base::ListValue);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<ParentChildPairSnapshot>::const_iterator it =
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           process_data.descendants.begin();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != process_data.descendants.end(); ++it) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> parent_child(new base::DictionaryValue);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BirthOnThreadSnapshotToValue(it->parent, "parent", parent_child.get());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BirthOnThreadSnapshotToValue(it->child, "child", parent_child.get());
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    descendants_list->Append(parent_child.release());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->Set("descendants", descendants_list.release());
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TaskProfilerDataSerializer::WriteToFile(const base::FilePath& path) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONStringValueSerializer serializer(&output);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  serializer.set_pretty_print(true);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue());
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* snapshot_list = new base::ListValue();
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* shutdown_snapshot = new base::DictionaryValue();
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* per_process_data = new base::ListValue();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  root->SetInteger("version", 1);
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  root->SetString("userAgent", GetUserAgent());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(ramant): Collect data from other processes, then add that data to the
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'per_process_data' array here. Should leverage the TrackingSynchronizer
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // class to implement this.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcessDataSnapshot this_process_data;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracked_objects::ThreadData::Snapshot(false, &this_process_data);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> this_process_data_json(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new base::DictionaryValue);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TaskProfilerDataSerializer::ToValue(this_process_data,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      content::PROCESS_TYPE_BROWSER,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      this_process_data_json.get());
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  per_process_data->Append(this_process_data_json.release());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_snapshot->SetInteger(
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "timestamp",
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (base::Time::Now() - base::Time::UnixEpoch()).InSeconds());
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_snapshot->Set("data", per_process_data);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot_list->Append(shutdown_snapshot);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  root->Set("snapshots", snapshot_list);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  serializer.Serialize(*root);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data_size = static_cast<int>(output.size());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return data_size == base::WriteFile(path, output.data(), data_size);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace task_profiler
153