blob: 74dc83b699e2149484113e1911c18ed6034cdb87 [file] [log] [blame]
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +02001// Copyright 2015 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 "apps/benchmark/event.h"
6
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +02007#include <map>
8#include <stack>
9
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020010#include "base/json/json_reader.h"
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020011#include "base/macros.h"
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020012#include "base/memory/scoped_ptr.h"
13#include "base/values.h"
14
15namespace benchmark {
16
17Event::Event() {}
18
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020019Event::Event(EventType type,
20 std::string name,
21 std::string categories,
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020022 base::TimeTicks timestamp,
23 base::TimeDelta duration)
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020024 : type(type),
25 name(name),
26 categories(categories),
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020027 timestamp(timestamp),
28 duration(duration) {}
29
30Event::~Event() {}
31
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020032namespace {
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020033
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020034// Finds the matching "duration end" event for each "duration begin" event and
35// rewrites the "begin event" as a "complete" event with a duration. Leaves all
36// events that are not "duration begin" unchanged.
37bool JoinDurationEvents(base::ListValue* event_list) {
38 // Maps thread ids to stacks of unmatched duration begin events on the given
39 // thread.
40 std::map<int, std::stack<base::DictionaryValue*>> open_begin_events;
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +020041
42 for (base::Value* val : *event_list) {
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +020043 base::DictionaryValue* event_dict;
44 if (!val->GetAsDictionary(&event_dict))
45 return false;
46
47 std::string phase;
48 if (!event_dict->GetString("ph", &phase)) {
49 LOG(ERROR) << "Incorrect trace event (missing phase)";
50 return false;
51 }
52
53 if (phase != "B" && phase != "E")
54 continue;
55
56 int tid;
57 if (!event_dict->GetInteger("tid", &tid)) {
58 LOG(ERROR) << "Incorrect trace event (missing tid).";
59 return false;
60 }
61
62 if (phase == "B") {
63 open_begin_events[tid].push(event_dict);
64 } else if (phase == "E") {
65 if (!open_begin_events.count(tid) || open_begin_events[tid].empty()) {
66 LOG(ERROR) << "Incorrect trace event (duration end without begin).";
67 return false;
68 }
69
70 base::DictionaryValue* begin_event_dict = open_begin_events[tid].top();
71 open_begin_events[tid].pop();
72 double begin_ts;
73 if (!begin_event_dict->GetDouble("ts", &begin_ts)) {
74 LOG(ERROR) << "Incorrect trace event (no timestamp)";
75 return false;
76 }
77
78 double end_ts;
79 if (!event_dict->GetDouble("ts", &end_ts)) {
80 LOG(ERROR) << "Incorrect trace event (no timestamp)";
81 return false;
82 }
83
84 if (end_ts < begin_ts) {
85 LOG(ERROR) << "Incorrect trace event (duration timestamps decreasing)";
86 return false;
87 }
88
89 begin_event_dict->SetDouble("dur", end_ts - begin_ts);
90 begin_event_dict->SetString("ph", "X");
91 } else {
92 NOTREACHED();
93 }
94 }
95 return true;
96}
97
98bool ParseEvents(base::ListValue* event_list, std::vector<Event>* result) {
99 result->clear();
100
101 for (base::Value* val : *event_list) {
102 base::DictionaryValue* event_dict;
Przemyslaw Pietrzkiewicz447d2f92015-09-16 15:57:36 +0200103 if (!val->GetAsDictionary(&event_dict)) {
104 LOG(WARNING) << "Ignoring incorrect trace event (not a dictionary)";
105 continue;
106 }
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200107
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200108 Event event;
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200109
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200110 std::string phase;
111 if (!event_dict->GetString("ph", &phase)) {
Przemyslaw Pietrzkiewicz447d2f92015-09-16 15:57:36 +0200112 LOG(WARNING) << "Ignoring incorrect trace event (missing phase)";
113 continue;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200114 }
115 if (phase == "X") {
116 event.type = EventType::COMPLETE;
117 } else if (phase == "I") {
118 event.type = EventType::INSTANT;
119 } else {
120 // Skip all event types we do not handle.
121 continue;
122 }
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200123
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200124 if (!event_dict->GetString("name", &event.name)) {
125 LOG(ERROR) << "Incorrect trace event (no name)";
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200126 return false;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200127 }
128
129 if (!event_dict->GetString("cat", &event.categories)) {
Przemyslaw Pietrzkiewicz447d2f92015-09-16 15:57:36 +0200130 LOG(WARNING) << "Ignoring incorrect trace event (no categories)";
131 continue;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200132 }
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200133
134 double timestamp;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200135 if (!event_dict->GetDouble("ts", &timestamp)) {
Przemyslaw Pietrzkiewicz447d2f92015-09-16 15:57:36 +0200136 LOG(WARNING) << "Ingoring incorrect trace event (no timestamp)";
137 continue;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200138 }
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200139 event.timestamp = base::TimeTicks::FromInternalValue(timestamp);
140
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200141 if (event.type == EventType::COMPLETE) {
142 double duration;
143 if (!event_dict->GetDouble("dur", &duration)) {
Przemyslaw Pietrzkiewicz447d2f92015-09-16 15:57:36 +0200144 LOG(WARNING) << "Ignoring incorrect complete event (no duration)";
145 continue;
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200146 }
147
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200148 event.duration = base::TimeDelta::FromInternalValue(duration);
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200149 } else {
150 event.duration = base::TimeDelta();
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200151 }
152
153 result->push_back(event);
154 }
155 return true;
156}
Przemyslaw Pietrzkiewicz421c1f72015-09-08 14:52:36 +0200157
158} // namespace
159
160bool GetEvents(const std::string& trace_json, std::vector<Event>* result) {
161 // Parse the JSON string describing the events.
162 base::JSONReader reader;
163 scoped_ptr<base::Value> trace_data = reader.ReadToValue(trace_json);
164 if (!trace_data) {
165 LOG(ERROR) << "Failed to parse the JSON string: "
166 << reader.GetErrorMessage();
167 return false;
168 }
169
170 base::ListValue* event_list;
171 if (!trace_data->GetAsList(&event_list)) {
172 LOG(ERROR) << "Incorrect format of the trace data.";
173 return false;
174 }
175
176 if (!JoinDurationEvents(event_list))
177 return false;
178
179 if (!ParseEvents(event_list, result))
180 return false;
181 return true;
182}
Przemyslaw Pietrzkiewicz1d909942015-08-28 16:27:56 +0200183} // namespace benchmark