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/trace_event/trace_event_impl.h" 6 7 #include <fcntl.h> 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include "base/format_macros.h" 12 #include "base/logging.h" 13 #include "base/posix/eintr_wrapper.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/synchronization/waitable_event.h" 16 #include "base/trace_event/trace_event.h" 17 18 namespace base { 19 namespace trace_event { 20 21 namespace { 22 23 int g_atrace_fd = -1; 24 const char kATraceMarkerFile[] = "/sys/kernel/debug/tracing/trace_marker"; 25 26 void WriteToATrace(int fd, const char* buffer, size_t size) { 27 size_t total_written = 0; 28 while (total_written < size) { 29 ssize_t written = HANDLE_EINTR(write( 30 fd, buffer + total_written, size - total_written)); 31 if (written <= 0) 32 break; 33 total_written += written; 34 } 35 if (total_written < size) { 36 PLOG(WARNING) << "Failed to write buffer '" << std::string(buffer, size) 37 << "' to " << kATraceMarkerFile; 38 } 39 } 40 41 void WriteEvent( 42 char phase, 43 const char* category_group, 44 const char* name, 45 unsigned long long id, 46 const char** arg_names, 47 const unsigned char* arg_types, 48 const TraceEvent::TraceValue* arg_values, 49 const std::unique_ptr<ConvertableToTraceFormat>* convertable_values, 50 unsigned int flags) { 51 std::string out = StringPrintf("%c|%d|%s", phase, getpid(), name); 52 if (flags & TRACE_EVENT_FLAG_HAS_ID) 53 StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id)); 54 out += '|'; 55 56 for (int i = 0; i < kTraceMaxNumArgs && arg_names[i]; 57 ++i) { 58 if (i) 59 out += ';'; 60 out += arg_names[i]; 61 out += '='; 62 std::string::size_type value_start = out.length(); 63 if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) 64 convertable_values[i]->AppendAsTraceFormat(&out); 65 else 66 TraceEvent::AppendValueAsJSON(arg_types[i], arg_values[i], &out); 67 68 // Remove the quotes which may confuse the atrace script. 69 ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'"); 70 ReplaceSubstringsAfterOffset(&out, value_start, "\"", ""); 71 // Replace chars used for separators with similar chars in the value. 72 std::replace(out.begin() + value_start, out.end(), ';', ','); 73 std::replace(out.begin() + value_start, out.end(), '|', '!'); 74 } 75 76 out += '|'; 77 out += category_group; 78 WriteToATrace(g_atrace_fd, out.c_str(), out.size()); 79 } 80 81 void NoOpOutputCallback(WaitableEvent* complete_event, 82 const scoped_refptr<RefCountedString>&, 83 bool has_more_events) { 84 if (!has_more_events) 85 complete_event->Signal(); 86 } 87 88 void EndChromeTracing(TraceLog* trace_log, 89 WaitableEvent* complete_event) { 90 trace_log->SetDisabled(); 91 // Delete the buffered trace events as they have been sent to atrace. 92 trace_log->Flush(Bind(&NoOpOutputCallback, complete_event)); 93 } 94 95 } // namespace 96 97 // These functions support Android systrace.py when 'webview' category is 98 // traced. With the new adb_profile_chrome, we may have two phases: 99 // - before WebView is ready for combined tracing, we can use adb_profile_chrome 100 // to trace android categories other than 'webview' and chromium categories. 101 // In this way we can avoid the conflict between StartATrace/StopATrace and 102 // the intents. 103 // - TODO(wangxianzhu): after WebView is ready for combined tracing, remove 104 // StartATrace, StopATrace and SendToATrace, and perhaps send Java traces 105 // directly to atrace in trace_event_binding.cc. 106 107 void TraceLog::StartATrace() { 108 if (g_atrace_fd != -1) 109 return; 110 111 g_atrace_fd = HANDLE_EINTR(open(kATraceMarkerFile, O_WRONLY)); 112 if (g_atrace_fd == -1) { 113 PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile; 114 return; 115 } 116 TraceConfig trace_config; 117 trace_config.SetTraceRecordMode(RECORD_CONTINUOUSLY); 118 SetEnabled(trace_config, TraceLog::RECORDING_MODE); 119 } 120 121 void TraceLog::StopATrace() { 122 if (g_atrace_fd == -1) 123 return; 124 125 close(g_atrace_fd); 126 g_atrace_fd = -1; 127 128 // TraceLog::Flush() requires the current thread to have a message loop, but 129 // this thread called from Java may not have one, so flush in another thread. 130 Thread end_chrome_tracing_thread("end_chrome_tracing"); 131 WaitableEvent complete_event(WaitableEvent::ResetPolicy::AUTOMATIC, 132 WaitableEvent::InitialState::NOT_SIGNALED); 133 end_chrome_tracing_thread.Start(); 134 end_chrome_tracing_thread.task_runner()->PostTask( 135 FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this), 136 Unretained(&complete_event))); 137 complete_event.Wait(); 138 } 139 140 void TraceEvent::SendToATrace() { 141 if (g_atrace_fd == -1) 142 return; 143 144 const char* category_group = 145 TraceLog::GetCategoryGroupName(category_group_enabled_); 146 147 switch (phase_) { 148 case TRACE_EVENT_PHASE_BEGIN: 149 WriteEvent('B', category_group, name_, id_, 150 arg_names_, arg_types_, arg_values_, convertable_values_, 151 flags_); 152 break; 153 154 case TRACE_EVENT_PHASE_COMPLETE: 155 WriteEvent(duration_.ToInternalValue() == -1 ? 'B' : 'E', 156 category_group, name_, id_, 157 arg_names_, arg_types_, arg_values_, convertable_values_, 158 flags_); 159 break; 160 161 case TRACE_EVENT_PHASE_END: 162 // Though a single 'E' is enough, here append pid, name and 163 // category_group etc. So that unpaired events can be found easily. 164 WriteEvent('E', category_group, name_, id_, 165 arg_names_, arg_types_, arg_values_, convertable_values_, 166 flags_); 167 break; 168 169 case TRACE_EVENT_PHASE_INSTANT: 170 // Simulate an instance event with a pair of begin/end events. 171 WriteEvent('B', category_group, name_, id_, 172 arg_names_, arg_types_, arg_values_, convertable_values_, 173 flags_); 174 WriteToATrace(g_atrace_fd, "E", 1); 175 break; 176 177 case TRACE_EVENT_PHASE_COUNTER: 178 for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { 179 DCHECK(arg_types_[i] == TRACE_VALUE_TYPE_INT); 180 std::string out = base::StringPrintf( 181 "C|%d|%s-%s", getpid(), name_, arg_names_[i]); 182 if (flags_ & TRACE_EVENT_FLAG_HAS_ID) 183 StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id_)); 184 StringAppendF(&out, "|%d|%s", 185 static_cast<int>(arg_values_[i].as_int), category_group); 186 WriteToATrace(g_atrace_fd, out.c_str(), out.size()); 187 } 188 break; 189 190 default: 191 // Do nothing. 192 break; 193 } 194 } 195 196 void TraceLog::AddClockSyncMetadataEvent() { 197 int atrace_fd = HANDLE_EINTR(open(kATraceMarkerFile, O_WRONLY | O_APPEND)); 198 if (atrace_fd == -1) { 199 PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile; 200 return; 201 } 202 203 // Android's kernel trace system has a trace_marker feature: this is a file on 204 // debugfs that takes the written data and pushes it onto the trace 205 // buffer. So, to establish clock sync, we write our monotonic clock into that 206 // trace buffer. 207 double now_in_seconds = (TimeTicks::Now() - TimeTicks()).InSecondsF(); 208 std::string marker = StringPrintf( 209 "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds); 210 WriteToATrace(atrace_fd, marker.c_str(), marker.size()); 211 close(atrace_fd); 212 } 213 214 } // namespace trace_event 215 } // namespace base 216