blob: 78d9de66747541906bdb585cde021534d34fb20f [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000010#include "base/format_macros.h"
11#include "base/logging.h"
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010012#include "base/strings/stringprintf.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000013
14namespace {
15
16int g_atrace_fd = -1;
17const char* kATraceMarkerFile = "/sys/kernel/debug/tracing/trace_marker";
18
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010019void 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) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030 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 += '=';
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000040 std::string::size_type value_start = out.length();
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010041 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 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000048 // 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 += '|';
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010057 out += category_group;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000058 write(g_atrace_fd, out.c_str(), out.size());
59}
60
Torne (Richard Coles)58218062012-11-14 11:43:16 +000061} // namespace
62
63namespace base {
64namespace debug {
65
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000066void TraceLog::StartATrace() {
67 AutoLock lock(lock_);
68 if (g_atrace_fd == -1) {
69 g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010070 if (g_atrace_fd == -1) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000071 LOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010072 } else {
Ben Murdochbb1529c2013-08-08 10:24:53 +010073 UpdateCategoryGroupEnabledFlags();
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010074 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000075 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000076}
77
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000078void TraceLog::StopATrace() {
79 AutoLock lock(lock_);
80 if (g_atrace_fd != -1) {
81 close(g_atrace_fd);
82 g_atrace_fd = -1;
Ben Murdochbb1529c2013-08-08 10:24:53 +010083 UpdateCategoryGroupEnabledFlags();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000084 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085}
86
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010087void 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) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000098 if (g_atrace_fd == -1)
Torne (Richard Coles)58218062012-11-14 11:43:16 +000099 return;
100
101 switch (phase) {
102 case TRACE_EVENT_PHASE_BEGIN:
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100103 WriteEvent('B', category_group, name, id,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100104 num_args, arg_names, arg_types, arg_values, convertable_values,
105 flags);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000106 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000107
108 case TRACE_EVENT_PHASE_END:
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100109 // 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,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100112 num_args, arg_names, arg_types, arg_values, convertable_values,
113 flags);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000114 break;
115
116 case TRACE_EVENT_PHASE_INSTANT:
117 // Simulate an instance event with a pair of begin/end events.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100118 WriteEvent('B', category_group, name, id,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100119 num_args, arg_names, arg_types, arg_values, convertable_values,
120 flags);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000121 write(g_atrace_fd, "E", 1);
122 break;
123
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000124 case TRACE_EVENT_PHASE_COUNTER:
125 for (int i = 0; i < num_args; ++i) {
126 DCHECK(arg_types[i] == TRACE_VALUE_TYPE_INT);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000127 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",
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100132 static_cast<int>(arg_values[i]), category_group);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000133 write(g_atrace_fd, out.c_str(), out.size());
134 }
135 break;
136
137 default:
138 // Do nothing.
139 break;
140 }
141}
142
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000143// Must be called with lock_ locked.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100144void TraceLog::ApplyATraceEnabledFlag(unsigned char* category_group_enabled) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100145 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;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000155}
156
157} // namespace debug
158} // namespace base