Home | History | Annotate | Download | only in debug
      1 // Copyright (c) 2012 The Chromium 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 "base/debug/trace_event_impl.h"
      6 
      7 #include <fcntl.h>
      8 
      9 #include "base/debug/trace_event.h"
     10 #include "base/format_macros.h"
     11 #include "base/logging.h"
     12 #include "base/strings/stringprintf.h"
     13 
     14 namespace {
     15 
     16 int g_atrace_fd = -1;
     17 const char* kATraceMarkerFile = "/sys/kernel/debug/tracing/trace_marker";
     18 
     19 void WriteEvent(
     20     char phase,
     21     const char* category_group,
     22     const char* name,
     23     unsigned long long id,
     24     int num_args,
     25     const char** arg_names,
     26     const unsigned char* arg_types,
     27     const unsigned long long* arg_values,
     28     scoped_ptr<base::debug::ConvertableToTraceFormat> convertable_values[],
     29     unsigned char flags) {
     30   std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name);
     31   if (flags & TRACE_EVENT_FLAG_HAS_ID)
     32     base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
     33   out += '|';
     34 
     35   for (int i = 0; i < num_args; ++i) {
     36     if (i)
     37       out += ';';
     38     out += arg_names[i];
     39     out += '=';
     40     std::string::size_type value_start = out.length();
     41     if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
     42       convertable_values[i]->AppendAsTraceFormat(&out);
     43     } else {
     44       base::debug::TraceEvent::TraceValue value;
     45       value.as_uint = arg_values[i];
     46       base::debug::TraceEvent::AppendValueAsJSON(arg_types[i], value, &out);
     47     }
     48     // Remove the quotes which may confuse the atrace script.
     49     ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
     50     ReplaceSubstringsAfterOffset(&out, value_start, "\"", "");
     51     // Replace chars used for separators with similar chars in the value.
     52     std::replace(out.begin() + value_start, out.end(), ';', ',');
     53     std::replace(out.begin() + value_start, out.end(), '|', '!');
     54   }
     55 
     56   out += '|';
     57   out += category_group;
     58   write(g_atrace_fd, out.c_str(), out.size());
     59 }
     60 
     61 }  // namespace
     62 
     63 namespace base {
     64 namespace debug {
     65 
     66 void TraceLog::StartATrace() {
     67   AutoLock lock(lock_);
     68   if (g_atrace_fd == -1) {
     69     g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
     70     if (g_atrace_fd == -1) {
     71       LOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
     72     } else {
     73       UpdateCategoryGroupEnabledFlags();
     74     }
     75   }
     76 }
     77 
     78 void TraceLog::StopATrace() {
     79   AutoLock lock(lock_);
     80   if (g_atrace_fd != -1) {
     81     close(g_atrace_fd);
     82     g_atrace_fd = -1;
     83     UpdateCategoryGroupEnabledFlags();
     84   }
     85 }
     86 
     87 void TraceLog::SendToATrace(
     88     char phase,
     89     const char* category_group,
     90     const char* name,
     91     unsigned long long id,
     92     int num_args,
     93     const char** arg_names,
     94     const unsigned char* arg_types,
     95     const unsigned long long* arg_values,
     96     scoped_ptr<ConvertableToTraceFormat> convertable_values[],
     97     unsigned char flags) {
     98   if (g_atrace_fd == -1)
     99     return;
    100 
    101   switch (phase) {
    102     case TRACE_EVENT_PHASE_BEGIN:
    103       WriteEvent('B', category_group, name, id,
    104                  num_args, arg_names, arg_types, arg_values, convertable_values,
    105                  flags);
    106       break;
    107 
    108     case TRACE_EVENT_PHASE_END:
    109       // Though a single 'E' is enough, here append pid, name and
    110       // category_group etc. So that unpaired events can be found easily.
    111       WriteEvent('E', category_group, name, id,
    112                  num_args, arg_names, arg_types, arg_values, convertable_values,
    113                  flags);
    114       break;
    115 
    116     case TRACE_EVENT_PHASE_INSTANT:
    117       // Simulate an instance event with a pair of begin/end events.
    118       WriteEvent('B', category_group, name, id,
    119                  num_args, arg_names, arg_types, arg_values, convertable_values,
    120                  flags);
    121       write(g_atrace_fd, "E", 1);
    122       break;
    123 
    124     case TRACE_EVENT_PHASE_COUNTER:
    125       for (int i = 0; i < num_args; ++i) {
    126         DCHECK(arg_types[i] == TRACE_VALUE_TYPE_INT);
    127         std::string out = base::StringPrintf("C|%d|%s-%s",
    128                                        getpid(), name, arg_names[i]);
    129         if (flags & TRACE_EVENT_FLAG_HAS_ID)
    130           StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
    131         StringAppendF(&out, "|%d|%s",
    132                       static_cast<int>(arg_values[i]), category_group);
    133         write(g_atrace_fd, out.c_str(), out.size());
    134       }
    135       break;
    136 
    137     default:
    138       // Do nothing.
    139       break;
    140   }
    141 }
    142 
    143 // Must be called with lock_ locked.
    144 void TraceLog::ApplyATraceEnabledFlag(unsigned char* category_group_enabled) {
    145   if (g_atrace_fd == -1)
    146     return;
    147 
    148   // Don't enable disabled-by-default categories for atrace.
    149   const char* category_group = GetCategoryGroupName(category_group_enabled);
    150   if (strncmp(category_group, TRACE_DISABLED_BY_DEFAULT(""),
    151               strlen(TRACE_DISABLED_BY_DEFAULT(""))) == 0)
    152     return;
    153 
    154   *category_group_enabled |= ATRACE_ENABLED;
    155 }
    156 
    157 }  // namespace debug
    158 }  // namespace base
    159