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