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