Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tracerecorder.cc
Go to the documentation of this file.
1 
18 #include <limits>
19 #include <memory>
20 #include <stack>
21 #include <string>
22 
24 
25 #include "ion/base/serialize.h"
26 #include "ion/base/stringutils.h"
27 #include "ion/port/threadutils.h"
34 #include "third_party/jsoncpp/include/json/json.h"
35 
36 namespace ion {
37 namespace profile {
38 
41 
42 namespace {
43 
46 static const uint32 kEmptyScopeMarker = 0xfeeb1e57;
47 
48 } // namespace
49 
52 size_t TraceRecorder::s_default_buffer_size_ =
53 #if ION_PRODUCTION
54  1 * 1024 * 1024;
55 #else
56  20 * 1024 * 1024;
57 #endif
58 
59 bool TraceRecorder::s_reserve_buffer_ = false;
60 
62  : manager_(manager),
63  trace_buffer_(s_default_buffer_size_ / sizeof(uint32),
64  GetAllocator(),
65  s_reserve_buffer_),
66  scope_level_(0),
67  thread_id_(ion::port::GetCurrentThreadId()),
68  thread_name_("UnnamedThread"),
69  frame_level_(0),
70  current_frame_number_(0) {
71  trace_buffer_.AddItem(kEmptyScopeMarker);
72 }
73 
74 TraceRecorder::TraceRecorder(CallTraceManager* manager, size_t buffer_size)
75  : manager_(manager),
76  trace_buffer_(
77  buffer_size / sizeof(uint32), GetAllocator(), s_reserve_buffer_),
78  scope_level_(0),
79  thread_id_(ion::port::GetCurrentThreadId()),
80  thread_name_("UnnamedThread"),
81  frame_level_(0),
82  current_frame_number_(0) {
83  trace_buffer_.AddItem(kEmptyScopeMarker);
84 }
85 
86 void TraceRecorder::EnterScope(int event_id) {
87  EnterScopeAtTime(manager_->GetTimeInUs(), event_id);
88 }
89 
90 void TraceRecorder::AnnotateCurrentScope(const std::string& name,
91  const std::string& value) {
93 }
94 
96  LeaveScopeAtTime(manager_->GetTimeInUs());
97 }
98 
99 void TraceRecorder::EnterScopeAtTime(uint32 timestamp, int event_id) {
100  trace_buffer_.AddItem(event_id);
101  trace_buffer_.AddItem(timestamp);
102  ++scope_level_;
103 }
104 
106  const std::string& name,
107  const std::string& value) {
108  DCHECK(!name.empty());
109  DCHECK(!value.empty());
111  DCHECK_NE(ValueToString(std::numeric_limits<double>::quiet_NaN()), value);
112  DCHECK_NE(ValueToString(-std::numeric_limits<double>::quiet_NaN()), value);
113  DCHECK_NE(ValueToString(std::numeric_limits<double>::infinity()), value);
114  DCHECK_NE(ValueToString(-std::numeric_limits<double>::infinity()), value);
115  uint32 name_index = GetStringIndex(TrimEndWhitespace(name));
116  uint32 value_index = GetStringIndex(TrimEndWhitespace(value));
117 
119  trace_buffer_.AddItem(timestamp);
120  trace_buffer_.AddItem(name_index);
121  trace_buffer_.AddItem(value_index);
122 }
123 
124 void TraceRecorder::LeaveScopeAtTime(uint32 timestamp) {
126  trace_buffer_.AddItem(timestamp);
127  DCHECK_GT(scope_level_, 0);
128  --scope_level_;
129  if (scope_level_ == 0) {
130  trace_buffer_.AddItem(kEmptyScopeMarker);
131  }
132 }
133 
134 void TraceRecorder::EnterFrame(uint32 frame_number) {
135  if (frame_level_ == 0) {
137  current_frame_number_ = frame_number;
139  trace_buffer_.AddItem(manager_->GetTimeInUs());
140  trace_buffer_.AddItem(frame_number);
141  }
142  ++frame_level_;
143 }
144 
146  if (!IsInFrameScope()) {
148  << "LeaveFrame() should not be called outside of a frame.";
149  return;
150  }
151  --frame_level_;
153  if (frame_level_ == 0) {
155  trace_buffer_.AddItem(manager_->GetTimeInUs());
156  trace_buffer_.AddItem(current_frame_number_);
157  }
158 }
159 
161  uint32 unique_id, const char* name, const char* value) {
162  DCHECK(name);
163  uint32 name_index = GetStringIndex(TrimEndWhitespace(name));
164 
165  uint32 value_index = -1;
166  if (value) {
167  value_index = GetStringIndex(TrimEndWhitespace(value));
168  }
169 
171  trace_buffer_.AddItem(manager_->GetTimeInUs());
172  trace_buffer_.AddItem(unique_id);
173  trace_buffer_.AddItem(name_index);
174  trace_buffer_.AddItem(value_index);
175 }
176 
177 uint32 TraceRecorder::EnterTimeRange(const char* name, const char* value) {
178  DCHECK(name);
179  uint32 name_index = GetStringIndex(TrimEndWhitespace(name));
180 
181  uint32 value_index = -1;
182  if (value) {
183  value_index = GetStringIndex(TrimEndWhitespace(value));
184  }
185 
187  trace_buffer_.AddItem(manager_->GetTimeInUs());
191  trace_buffer_.AddItem(name_index);
192  trace_buffer_.AddItem(name_index);
193  trace_buffer_.AddItem(value_index);
194 
195  return name_index;
196 }
197 
200  trace_buffer_.AddItem(manager_->GetTimeInUs());
201  trace_buffer_.AddItem(id);
202 }
203 
204 void TraceRecorder::CreateTimeStamp(const char* name, const char* value) {
206 }
207 
209  uint32 timestamp, const char* name, const char* value) {
210  DCHECK(name);
211  uint32 name_index = GetStringIndex(TrimEndWhitespace(name));
212 
213  uint32 value_index = -1;
214  if (value) {
215  value_index = GetStringIndex(TrimEndWhitespace(value));
216  }
217 
219  trace_buffer_.AddItem(timestamp);
220  trace_buffer_.AddItem(name_index);
221  trace_buffer_.AddItem(value_index);
222 }
223 
225  size_t index = 0;
227  while (index < trace_buffer_.GetSize() &&
228  trace_buffer_.GetItem(index) != kEmptyScopeMarker) {
229  index++;
230  }
231 
232  size_t length = 0;
233  while (index < trace_buffer_.GetSize()) {
235  uint32 wire_id = trace_buffer_.GetItem(index);
236  if (wire_id == kEmptyScopeMarker) {
237  index++;
238  } else {
239  index += 2 + CallTraceManager::GetNumArgsForEvent(wire_id);
240  length++;
241  }
242  }
243  return length;
244 }
245 
246 uint32 TraceRecorder::GetStringIndex(const std::string& str) {
249  uint32 index = static_cast<uint32>(string_buffer_.size());
250  return string_buffer_.insert(
251  std::make_pair(str, index)).first->second;
252 }
253 
254 void TraceRecorder::DumpStrings(std::vector<std::string>* table) const {
255  size_t base = table->size();
256  table->resize(base + string_buffer_.size());
257  for (auto it = string_buffer_.begin(); it != string_buffer_.end(); ++it) {
258  DCHECK_LT(base + it->second, table->size());
259  (*table)[base + it->second] = it->first;
260  }
261 }
262 
264  std::string* output, uint32 string_index_offset) const {
265  size_t index = 0;
266 
268  while (index < trace_buffer_.GetSize() &&
269  trace_buffer_.GetItem(index) != kEmptyScopeMarker) {
270  index++;
271  }
272 
274  while (index < trace_buffer_.GetSize()) {
275  uint32 wire_id = trace_buffer_.GetItem(index);
276  if (wire_id == kEmptyScopeMarker) {
277  index++;
278  } else {
280  base::AppendBytes(output, wire_id);
281  base::AppendBytes(output, trace_buffer_.GetItem(index + 1));
282 
284  const int num_args = CallTraceManager::GetNumArgsForEvent(wire_id);
285  for (int i = 0; i < num_args; ++i) {
286  const CallTraceManager::EventArgType arg_type =
287  CallTraceManager::GetArgType(wire_id, i);
288  DCHECK(arg_type != CallTraceManager::kArgNone);
289  uint32 item = trace_buffer_.GetItem(index + 2 + i);
290  if (arg_type == CallTraceManager::kArgString &&
291  item != 0xffffffff) {
292  base::AppendBytes(output, string_index_offset + item);
293  } else {
294  base::AppendBytes(output, item);
295  }
296  }
297  index += num_args + 2;
298  }
299  }
300 }
301 
302 std::string TraceRecorder::GetStringArg(
303  size_t index, int arg_index,
304  const IndexToStringMap& inverse_string_buffer) const {
305  const uint32 wire_id = trace_buffer_.GetItem(index);
306  CHECK_LT(arg_index, CallTraceManager::GetNumArgsForEvent(wire_id));
308  CallTraceManager::GetArgType(wire_id, arg_index));
309  const uint32 string_index = trace_buffer_.GetItem(index + 2 + arg_index);
312  if (string_index == 0xffffffff) return std::string();
313  return inverse_string_buffer.at(string_index);
314 }
315 
316 std::unique_ptr<TimelineEvent> TraceRecorder::GetTimelineEvent(
317  size_t index, const IndexToStringMap& inverse_string_buffer) const {
318  const uint32 wire_id = trace_buffer_.GetItem(index);
319  const uint32 timestamp = trace_buffer_.GetItem(index + 1);
320  Json::Reader json_reader;
321 
322  std::string event_name;
323  Json::Value args(Json::objectValue);
324 
326  event_name = GetStringArg(index, 1, inverse_string_buffer);
327  json_reader.parse(GetStringArg(index, 2, inverse_string_buffer), args);
328  return std::unique_ptr<TimelineEvent>(
329  new TimelineRange(event_name, timestamp, 0, args));
330  } else if (wire_id == CallTraceManager::kFrameStartEvent) {
331  const uint32 frame_number = trace_buffer_.GetItem(index + 2);
332  event_name = std::string("Frame_") + base::ValueToString(frame_number);
333  return std::unique_ptr<TimelineEvent>(
334  new TimelineFrame(event_name, timestamp, 0, args, frame_number));
335  } else if (wire_id >= CallTraceManager::kCustomScopeEvent) {
336  event_name = manager_->GetScopeEnterEventName(wire_id);
337  return std::unique_ptr<TimelineEvent>(
338  new TimelineScope(event_name, timestamp, 0, args));
339  } else {
340  CHECK(false) << "Event type not supported by timeline exporter!";
341  return std::unique_ptr<TimelineEvent>(
342  new TimelineEvent(event_name, timestamp, 0, args));
343  }
344 }
345 
347  CHECK(root);
348  TimelineNode* parent_candidate = root;
349  std::stack<TimelineEvent*> open_events;
350  uint32 previous_begin = 0;
351  bool first_event = true;
352  size_t index = 0;
353  Json::Reader json_reader;
354 
355  IndexToStringMap inverse_string_buffer;
356  for (auto it = string_buffer_.begin(); it != string_buffer_.end(); ++it) {
357  inverse_string_buffer[it->second] = it->first;
358  }
359 
361  while (index < trace_buffer_.GetSize() &&
362  trace_buffer_.GetItem(index) != kEmptyScopeMarker) {
363  ++index;
364  }
365 
367  while (index < trace_buffer_.GetSize()) {
368  const uint32 wire_id = trace_buffer_.GetItem(index);
369  if (wire_id == kEmptyScopeMarker) {
370  ++index;
371  continue;
372  }
373 
374  const uint32 timestamp = trace_buffer_.GetItem(index + 1);
375  CHECK(first_event || timestamp >= previous_begin)
376  << "Timestamps not monotonically increasing!\n";
377  first_event = false;
378  previous_begin = timestamp;
379 
384  TimelineNode* parent = parent_candidate;
385  while (parent->GetParent() &&
386  (open_events.empty() || parent != open_events.top()) &&
387  parent->GetEnd() < timestamp) {
388  parent = parent->GetParent();
389  }
390 
391  DCHECK(parent);
392 
396  std::unique_ptr<TimelineEvent> timeline_event =
397  GetTimelineEvent(index, inverse_string_buffer);
398  open_events.push(timeline_event.get());
402  parent_candidate = timeline_event.get();
403  parent->AddChild(std::move(timeline_event));
404  } else if (wire_id == CallTraceManager::kTimeRangeEndEvent ||
407  DCHECK_LT(0U, open_events.size());
408  open_events.top()->UpdateDuration(timestamp);
409  open_events.pop();
412  parent_candidate = parent->GetParent();
413  } else if (wire_id == CallTraceManager::kScopeAppendDataEvent) {
414  const std::string arg_name =
415  GetStringArg(index, 0, inverse_string_buffer);
416  const std::string arg_value =
417  GetStringArg(index, 1, inverse_string_buffer);
418  open_events.top()->GetArgs()[arg_name] = Json::objectValue;
419  json_reader.parse(arg_value, open_events.top()->GetArgs()[arg_name]);
420  }
421 
422  const int num_args = CallTraceManager::GetNumArgsForEvent(wire_id);
423  index += num_args + 2;
424  }
425 }
426 
428  if (!IsInFrameScope()) {
429  LOG_ONCE(WARNING) << "GetCurrentFrameNumber() should not be called outside "
430  "of a frame.";
431  return 0;
432  }
433  return current_frame_number_;
434 }
435 
436 } // namespace profile
437 } // namespace ion
uint32 GetCurrentFrameNumber() const
Returns the frame number of the current frame scope, or 0 (and a warning message) if TraceRecorder is...
void AnnotateCurrentScopeAtTime(uint32 timestamp, const std::string &name, const std::string &value)
Same as AnnotateCurrentScope, but with specified timestamp.
size_t GetSize() const
Get the current number of items in the buffer.
Copyright 2016 Google Inc.
Definition: timelinescope.h:29
void EnterTimeRange(uint32 unique_id, const char *name, const char *value)
Records the start of a time range event.
void AnnotateCurrentScope(const std::string &name, const std::string &value)
Attaches data to the current scope, which will be visible on mouse-over.
const std::string & str
#define CHECK(expr)
Definition: logging.h:323
static int GetNumArgsForEvent(uint32 event_id)
Gets the number of arguments for a particular event.
Copyright 2016 Google Inc.
Definition: timelinerange.h:28
#define DCHECK(expr)
Definition: logging.h:331
double value
void AddChild(std::unique_ptr< TimelineNode > child)
Add a node to the children. It becomes the last child.
Definition: timelinenode.h:71
#define DCHECK_GT(val1, val2)
Definition: logging.h:337
size_t GetNumTraces() const
Returns the total number of recorded trace events.
static EventArgType GetArgType(uint32 event_id, int arg_index)
Gets the argument types for a particular event.
Table table
Definition: printer.cc:333
void EnterScopeAtTime(uint32 timestamp, int event_id)
Same as EnterScope, but with specified timestamp.
TraceRecorder(CallTraceManager *manager)
uint32 length
#define CHECK_LT(val1, val2)
Definition: logging.h:327
void AddTraceToTimelineNode(TimelineNode *root) const
Adds all events in the trace as a sub-tree under the passed in root node.
void LeaveScope()
Leaves the current (most recent) scope.
void CreateTimeStampAtTime(uint32 timestamp, const char *name, const char *value)
Same as CreateTimeStamp, but with specified timestamp.
virtual uint32 GetTimeInUs() const
Returns the time in microseconds, relative to the timebase.
std::string ValueToString(const T &val)
ValueToString.
Definition: serialize.h:209
#define DCHECK_NE(val1, val2)
Definition: logging.h:333
void CreateTimeStamp(const char *name, const char *value)
Records a timeStamp event.
Copyright 2016 Google Inc.
Definition: timelineevent.h:29
void AppendBytes(std::string *s, const T &value)
Convenience method to append bytes to string.
Definition: stringutils.h:253
void DumpStrings(std::vector< std::string > *table) const
Dumps the strings one by one to a string table.
std::string name
Definition: printer.cc:324
const TimelineNode * GetParent() const
Definition: timelinenode.h:51
EventArgType
Defines argument types for WTF events.
void LeaveFrame()
Records a frame exit event for the current frame index.
void AddItem(const T &item)
Add an item to the buffer.
#define LOG_ONCE(severity)
Logs the streamed message once per process run with a severity of severity.
Definition: logging.h:219
#define CHECK_EQ(val1, val2)
Definition: logging.h:324
Copyright 2016 Google Inc.
Definition: timelinenode.h:28
const T & GetItem(size_t i) const
Return the item at position i.
void LeaveTimeRange(uint32 id)
Records the end of a time range event for the specified unique id.
std::unordered_map< uint32, std::string > IndexToStringMap
Definition: tracerecorder.h:52
void EnterScope(int event_id)
Queries and records the event corresponding to the provided event_id.
void DumpTrace(std::string *output, uint32 string_index_offset) const
Appends a binary dump of the trace to the output string.
void EnterFrame(uint32 frame_number)
Records a frame enter event with a specified frame index.
bool IsInFrameScope() const
Returns if the TraceRecorder is currently in a frame scope.
Manages call trace recording for visualization in Web Tracing Framework (WTF) format.
Copyright 2016 Google Inc.
Definition: timelineframe.h:28
std::string TrimEndWhitespace(const std::string &target)
Removes any whitespace characters at the end of the string.
Definition: stringutils.h:146
The starting offset for scope event ids, purposefully set high to make room for built-in WTF events...
uint32 GetEnd() const
Definition: timelinenode.h:46
void LeaveScopeAtTime(uint32 timestamp)
Same as LeaveScope, but with specified timestamp.
#define DCHECK_LT(val1, val2)
Definition: logging.h:335
ThreadId GetCurrentThreadId()
Thread ID functions.
Definition: threadutils.cc:363
const char * GetScopeEnterEventName(uint32 event_id) const
Returns the name of the scope enter event with the given id.