Home | History | Annotate | Download | only in tracing
      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   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 
     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_ << "\"NULL\"";
    106       } else {
    107         WriteJSONStringToStream(value.as_string, stream_);
    108       }
    109       break;
    110     default:
    111       UNREACHABLE();
    112       break;
    113   }
    114 }
    115 
    116 void JSONTraceWriter::AppendArgValue(ConvertableToTraceFormat* value) {
    117   std::string arg_stringified;
    118   value->AppendAsTraceFormat(&arg_stringified);
    119   stream_ << arg_stringified;
    120 }
    121 
    122 JSONTraceWriter::JSONTraceWriter(std::ostream& stream) : stream_(stream) {
    123   stream_ << "{\"traceEvents\":[";
    124 }
    125 
    126 JSONTraceWriter::~JSONTraceWriter() { stream_ << "]}"; }
    127 
    128 void JSONTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
    129   if (append_comma_) stream_ << ",";
    130   append_comma_ = true;
    131   stream_ << "{\"pid\":" << trace_event->pid()
    132           << ",\"tid\":" << trace_event->tid()
    133           << ",\"ts\":" << trace_event->ts()
    134           << ",\"tts\":" << trace_event->tts() << ",\"ph\":\""
    135           << trace_event->phase() << "\",\"cat\":\""
    136           << TracingController::GetCategoryGroupName(
    137                  trace_event->category_enabled_flag())
    138           << "\",\"name\":\"" << trace_event->name()
    139           << "\",\"dur\":" << trace_event->duration()
    140           << ",\"tdur\":" << trace_event->cpu_duration();
    141   if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_ID) {
    142     if (trace_event->scope() != nullptr) {
    143       stream_ << ",\"scope\":\"" << trace_event->scope() << "\"";
    144     }
    145     // So as not to lose bits from a 64-bit integer, output as a hex string.
    146     stream_ << ",\"id\":\"0x" << std::hex << trace_event->id() << "\""
    147             << std::dec;
    148   }
    149   stream_ << ",\"args\":{";
    150   const char** arg_names = trace_event->arg_names();
    151   const uint8_t* arg_types = trace_event->arg_types();
    152   TraceObject::ArgValue* arg_values = trace_event->arg_values();
    153   std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables =
    154       trace_event->arg_convertables();
    155   for (int i = 0; i < trace_event->num_args(); ++i) {
    156     if (i > 0) stream_ << ",";
    157     stream_ << "\"" << arg_names[i] << "\":";
    158     if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
    159       AppendArgValue(arg_convertables[i].get());
    160     } else {
    161       AppendArgValue(arg_types[i], arg_values[i]);
    162     }
    163   }
    164   stream_ << "}}";
    165   // TODO(fmeawad): Add support for Flow Events.
    166 }
    167 
    168 void JSONTraceWriter::Flush() {}
    169 
    170 TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream) {
    171   return new JSONTraceWriter(stream);
    172 }
    173 
    174 }  // namespace tracing
    175 }  // namespace platform
    176 }  // namespace v8
    177