• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 the V8 project 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 "src/libplatform/tracing/trace-writer.h"
6 
7 #include <cmath>
8 
9 #include "base/trace_event/common/trace_event_common.h"
10 #include "include/v8-platform.h"
11 #include "src/base/platform/platform.h"
12 
13 namespace v8 {
14 namespace platform {
15 namespace tracing {
16 
17 // Writes the given string to a stream, taking care to escape characters
18 // when necessary.
WriteJSONStringToStream(const char * str,std::ostream & stream)19 V8_INLINE static void WriteJSONStringToStream(const char* str,
20                                               std::ostream& stream) {
21   size_t len = strlen(str);
22   stream << "\"";
23   for (size_t i = 0; i < len; ++i) {
24     // All of the permitted escape sequences in JSON strings, as per
25     // https://mathiasbynens.be/notes/javascript-escapes
26     switch (str[i]) {
27       case '\b':
28         stream << "\\b";
29         break;
30       case '\f':
31         stream << "\\f";
32         break;
33       case '\n':
34         stream << "\\n";
35         break;
36       case '\r':
37         stream << "\\r";
38         break;
39       case '\t':
40         stream << "\\t";
41         break;
42       case '\"':
43         stream << "\\\"";
44         break;
45       case '\\':
46         stream << "\\\\";
47         break;
48       // Note that because we use double quotes for JSON strings,
49       // we don't need to escape single quotes.
50       default:
51         stream << str[i];
52         break;
53     }
54   }
55   stream << "\"";
56 }
57 
AppendArgValue(uint8_t type,TraceObject::ArgValue value)58 void JSONTraceWriter::AppendArgValue(uint8_t type,
59                                      TraceObject::ArgValue value) {
60   switch (type) {
61     case TRACE_VALUE_TYPE_BOOL:
62       stream_ << (value.as_bool ? "true" : "false");
63       break;
64     case TRACE_VALUE_TYPE_UINT:
65       stream_ << value.as_uint;
66       break;
67     case TRACE_VALUE_TYPE_INT:
68       stream_ << value.as_int;
69       break;
70     case TRACE_VALUE_TYPE_DOUBLE: {
71       std::string real;
72       double val = value.as_double;
73       if (std::isfinite(val)) {
74         std::ostringstream convert_stream;
75         convert_stream << val;
76         real = convert_stream.str();
77         // Ensure that the number has a .0 if there's no decimal or 'e'.  This
78         // makes sure that when we read the JSON back, it's interpreted as a
79         // real rather than an int.
80         if (real.find('.') == std::string::npos &&
81             real.find('e') == std::string::npos &&
82             real.find('E') == std::string::npos) {
83           real += ".0";
84         }
85       } else if (std::isnan(val)) {
86         // The JSON spec doesn't allow NaN and Infinity (since these are
87         // objects in EcmaScript).  Use strings instead.
88         real = "\"NaN\"";
89       } else if (val < 0) {
90         real = "\"-Infinity\"";
91       } else {
92         real = "\"Infinity\"";
93       }
94       stream_ << real;
95       break;
96     }
97     case TRACE_VALUE_TYPE_POINTER:
98       // JSON only supports double and int numbers.
99       // So as not to lose bits from a 64-bit pointer, output as a hex string.
100       stream_ << "\"" << value.as_pointer << "\"";
101       break;
102     case TRACE_VALUE_TYPE_STRING:
103     case TRACE_VALUE_TYPE_COPY_STRING:
104       if (value.as_string == nullptr) {
105         stream_ << "\"nullptr\"";
106       } else {
107         WriteJSONStringToStream(value.as_string, stream_);
108       }
109       break;
110     default:
111       UNREACHABLE();
112       break;
113   }
114 }
115 
AppendArgValue(ConvertableToTraceFormat * value)116 void JSONTraceWriter::AppendArgValue(ConvertableToTraceFormat* value) {
117   std::string arg_stringified;
118   value->AppendAsTraceFormat(&arg_stringified);
119   stream_ << arg_stringified;
120 }
121 
JSONTraceWriter(std::ostream & stream)122 JSONTraceWriter::JSONTraceWriter(std::ostream& stream)
123     : JSONTraceWriter(stream, "traceEvents") {}
124 
JSONTraceWriter(std::ostream & stream,const std::string & tag)125 JSONTraceWriter::JSONTraceWriter(std::ostream& stream, const std::string& tag)
126     : stream_(stream) {
127   stream_ << "{\"" << tag << "\":[";
128 }
129 
~JSONTraceWriter()130 JSONTraceWriter::~JSONTraceWriter() { stream_ << "]}"; }
131 
AppendTraceEvent(TraceObject * trace_event)132 void JSONTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
133   if (append_comma_) stream_ << ",";
134   append_comma_ = true;
135   stream_ << "{\"pid\":" << trace_event->pid()
136           << ",\"tid\":" << trace_event->tid()
137           << ",\"ts\":" << trace_event->ts()
138           << ",\"tts\":" << trace_event->tts() << ",\"ph\":\""
139           << trace_event->phase() << "\",\"cat\":\""
140           << TracingController::GetCategoryGroupName(
141                  trace_event->category_enabled_flag())
142           << "\",\"name\":\"" << trace_event->name()
143           << "\",\"dur\":" << trace_event->duration()
144           << ",\"tdur\":" << trace_event->cpu_duration();
145   if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_ID) {
146     if (trace_event->scope() != nullptr) {
147       stream_ << ",\"scope\":\"" << trace_event->scope() << "\"";
148     }
149     // So as not to lose bits from a 64-bit integer, output as a hex string.
150     stream_ << ",\"id\":\"0x" << std::hex << trace_event->id() << "\""
151             << std::dec;
152   }
153   stream_ << ",\"args\":{";
154   const char** arg_names = trace_event->arg_names();
155   const uint8_t* arg_types = trace_event->arg_types();
156   TraceObject::ArgValue* arg_values = trace_event->arg_values();
157   std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables =
158       trace_event->arg_convertables();
159   for (int i = 0; i < trace_event->num_args(); ++i) {
160     if (i > 0) stream_ << ",";
161     stream_ << "\"" << arg_names[i] << "\":";
162     if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
163       AppendArgValue(arg_convertables[i].get());
164     } else {
165       AppendArgValue(arg_types[i], arg_values[i]);
166     }
167   }
168   stream_ << "}}";
169   // TODO(fmeawad): Add support for Flow Events.
170 }
171 
Flush()172 void JSONTraceWriter::Flush() {}
173 
CreateJSONTraceWriter(std::ostream & stream)174 TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream) {
175   return new JSONTraceWriter(stream);
176 }
177 
CreateJSONTraceWriter(std::ostream & stream,const std::string & tag)178 TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream,
179                                                 const std::string& tag) {
180   return new JSONTraceWriter(stream, tag);
181 }
182 
183 }  // namespace tracing
184 }  // namespace platform
185 }  // namespace v8
186