Line data Source code
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.
19 : V8_INLINE static void WriteJSONStringToStream(const char* str,
20 : std::ostream& stream) {
21 35 : size_t len = strlen(str);
22 35 : stream << "\"";
23 355 : 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 160 : switch (str[i]) {
27 : case '\b':
28 0 : stream << "\\b";
29 : break;
30 : case '\f':
31 0 : stream << "\\f";
32 : break;
33 : case '\n':
34 0 : stream << "\\n";
35 : break;
36 : case '\r':
37 0 : stream << "\\r";
38 : break;
39 : case '\t':
40 0 : stream << "\\t";
41 : break;
42 : case '\"':
43 30 : stream << "\\\"";
44 : break;
45 : case '\\':
46 0 : 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 35 : stream << "\"";
56 : }
57 :
58 120 : void JSONTraceWriter::AppendArgValue(uint8_t type,
59 : TraceObject::ArgValue value) {
60 120 : switch (type) {
61 : case TRACE_VALUE_TYPE_BOOL:
62 10 : stream_ << (value.as_bool ? "true" : "false");
63 10 : break;
64 : case TRACE_VALUE_TYPE_UINT:
65 25 : stream_ << value.as_uint;
66 : break;
67 : case TRACE_VALUE_TYPE_INT:
68 20 : stream_ << value.as_int;
69 : break;
70 : case TRACE_VALUE_TYPE_DOUBLE: {
71 : std::string real;
72 25 : double val = value.as_double;
73 25 : if (std::isfinite(val)) {
74 20 : std::ostringstream convert_stream;
75 : convert_stream << val;
76 10 : 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 30 : if (real.find('.') == std::string::npos &&
81 15 : real.find('e') == std::string::npos &&
82 5 : real.find('E') == std::string::npos) {
83 : real += ".0";
84 : }
85 15 : } 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 10 : } else if (val < 0) {
90 : real = "\"-Infinity\"";
91 : } else {
92 : real = "\"Infinity\"";
93 : }
94 25 : 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 10 : stream_ << "\"" << value.as_pointer << "\"";
101 5 : break;
102 : case TRACE_VALUE_TYPE_STRING:
103 : case TRACE_VALUE_TYPE_COPY_STRING:
104 35 : if (value.as_string == nullptr) {
105 0 : stream_ << "\"nullptr\"";
106 : } else {
107 35 : WriteJSONStringToStream(value.as_string, stream_);
108 : }
109 : break;
110 : default:
111 0 : UNREACHABLE();
112 : break;
113 : }
114 120 : }
115 :
116 20 : void JSONTraceWriter::AppendArgValue(ConvertableToTraceFormat* value) {
117 : std::string arg_stringified;
118 20 : value->AppendAsTraceFormat(&arg_stringified);
119 20 : stream_ << arg_stringified;
120 20 : }
121 :
122 11 : JSONTraceWriter::JSONTraceWriter(std::ostream& stream)
123 22 : : JSONTraceWriter(stream, "traceEvents") {}
124 :
125 16 : JSONTraceWriter::JSONTraceWriter(std::ostream& stream, const std::string& tag)
126 16 : : stream_(stream) {
127 16 : stream_ << "{\"" << tag << "\":[";
128 16 : }
129 :
130 32 : JSONTraceWriter::~JSONTraceWriter() { stream_ << "]}"; }
131 :
132 150 : void JSONTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
133 150 : if (append_comma_) stream_ << ",";
134 150 : append_comma_ = true;
135 300 : stream_ << "{\"pid\":" << trace_event->pid()
136 150 : << ",\"tid\":" << trace_event->tid()
137 : << ",\"ts\":" << trace_event->ts()
138 : << ",\"tts\":" << trace_event->tts() << ",\"ph\":\""
139 : << trace_event->phase() << "\",\"cat\":\""
140 : << TracingController::GetCategoryGroupName(
141 300 : trace_event->category_enabled_flag())
142 150 : << "\",\"name\":\"" << trace_event->name()
143 : << "\",\"dur\":" << trace_event->duration()
144 : << ",\"tdur\":" << trace_event->cpu_duration();
145 150 : if (trace_event->flags() &
146 : (TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT)) {
147 10 : stream_ << ",\"bind_id\":\"0x" << std::hex << trace_event->bind_id() << "\""
148 : << std::dec;
149 10 : if (trace_event->flags() & TRACE_EVENT_FLAG_FLOW_IN) {
150 10 : stream_ << ",\"flow_in\":true";
151 : }
152 10 : if (trace_event->flags() & TRACE_EVENT_FLAG_FLOW_OUT) {
153 10 : stream_ << ",\"flow_out\":true";
154 : }
155 : }
156 150 : if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_ID) {
157 10 : if (trace_event->scope() != nullptr) {
158 0 : stream_ << ",\"scope\":\"" << trace_event->scope() << "\"";
159 : }
160 : // So as not to lose bits from a 64-bit integer, output as a hex string.
161 10 : stream_ << ",\"id\":\"0x" << std::hex << trace_event->id() << "\""
162 : << std::dec;
163 : }
164 150 : stream_ << ",\"args\":{";
165 : const char** arg_names = trace_event->arg_names();
166 : const uint8_t* arg_types = trace_event->arg_types();
167 : TraceObject::ArgValue* arg_values = trace_event->arg_values();
168 : std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables =
169 : trace_event->arg_convertables();
170 430 : for (int i = 0; i < trace_event->num_args(); ++i) {
171 140 : if (i > 0) stream_ << ",";
172 280 : stream_ << "\"" << arg_names[i] << "\":";
173 140 : if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
174 40 : AppendArgValue(arg_convertables[i].get());
175 : } else {
176 120 : AppendArgValue(arg_types[i], arg_values[i]);
177 : }
178 : }
179 150 : stream_ << "}}";
180 : // TODO(fmeawad): Add support for Flow Events.
181 150 : }
182 :
183 16 : void JSONTraceWriter::Flush() {}
184 :
185 11 : TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream) {
186 11 : return new JSONTraceWriter(stream);
187 : }
188 :
189 5 : TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream,
190 : const std::string& tag) {
191 5 : return new JSONTraceWriter(stream, tag);
192 : }
193 :
194 : } // namespace tracing
195 : } // namespace platform
196 : } // namespace v8
|