Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/core/SkStream.h" |
| 9 | #include "include/private/SkThreadID.h" |
| 10 | #include "src/core/SkOSFile.h" |
| 11 | #include "src/core/SkTraceEvent.h" |
| 12 | #include "src/utils/SkJSONWriter.h" |
| 13 | #include "src/utils/SkOSPath.h" |
| 14 | #include "tools/trace/ChromeTracingTracer.h" |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 15 | |
| 16 | #include <chrono> |
| 17 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 18 | namespace { |
| 19 | |
| 20 | /** |
| 21 | * All events have a fixed block of information (TraceEvent), plus variable length payload: |
| 22 | * {TraceEvent} {TraceEventArgs} {Inline Payload} |
| 23 | */ |
| 24 | struct TraceEventArg { |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 25 | uint8_t fArgType; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 26 | const char* fArgName; |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 27 | uint64_t fArgValue; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 28 | }; |
| 29 | |
| 30 | // These fields are ordered to minimize size due to alignment. Argument types could be packed |
| 31 | // better, but very few events have many arguments, so the net loss is pretty small. |
| 32 | struct TraceEvent { |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 33 | char fPhase; |
| 34 | uint8_t fNumArgs; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 35 | uint32_t fSize; |
| 36 | |
| 37 | const char* fName; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 38 | // TODO: Merge fID and fClockEnd (never used together) |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 39 | uint64_t fID; |
| 40 | uint64_t fClockBegin; |
| 41 | uint64_t fClockEnd; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 42 | SkThreadID fThreadID; |
| 43 | |
| 44 | TraceEvent* next() { |
| 45 | return reinterpret_cast<TraceEvent*>(reinterpret_cast<char*>(this) + fSize); |
| 46 | } |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 47 | TraceEventArg* args() { return reinterpret_cast<TraceEventArg*>(this + 1); } |
| 48 | char* stringTable() { return reinterpret_cast<char*>(this->args() + fNumArgs); } |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 49 | }; |
| 50 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 51 | } // namespace |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 52 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 53 | ChromeTracingTracer::ChromeTracingTracer(const char* filename) : fFilename(filename) { |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 54 | this->createBlock(); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 55 | } |
| 56 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 57 | ChromeTracingTracer::~ChromeTracingTracer() { this->flush(); } |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 58 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 59 | void ChromeTracingTracer::createBlock() { |
| 60 | fCurBlock.fBlock = BlockPtr(new uint8_t[kBlockSize]); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 61 | fCurBlock.fEventsInBlock = 0; |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 62 | fCurBlockUsed = 0; |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 63 | } |
| 64 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 65 | SkEventTracer::Handle ChromeTracingTracer::appendEvent(const void* data, size_t size) { |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 66 | SkASSERT(size > 0 && size <= kBlockSize); |
| 67 | |
Herb Derby | a1b7be6 | 2019-05-09 16:59:18 -0400 | [diff] [blame] | 68 | SkAutoSpinlock lock(fMutex); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 69 | if (fCurBlockUsed + size > kBlockSize) { |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 70 | fBlocks.push_back(std::move(fCurBlock)); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 71 | this->createBlock(); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 72 | } |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 73 | memcpy(fCurBlock.fBlock.get() + fCurBlockUsed, data, size); |
| 74 | Handle handle = reinterpret_cast<Handle>(fCurBlock.fBlock.get() + fCurBlockUsed); |
| 75 | fCurBlockUsed += size; |
| 76 | fCurBlock.fEventsInBlock++; |
| 77 | return handle; |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 78 | } |
| 79 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 80 | SkEventTracer::Handle ChromeTracingTracer::addTraceEvent(char phase, |
| 81 | const uint8_t* categoryEnabledFlag, |
| 82 | const char* name, |
| 83 | uint64_t id, |
| 84 | int numArgs, |
| 85 | const char** argNames, |
| 86 | const uint8_t* argTypes, |
| 87 | const uint64_t* argValues, |
| 88 | uint8_t flags) { |
Brian Osman | de6e5bf | 2017-07-21 15:30:14 -0400 | [diff] [blame] | 89 | // TODO: Respect flags (or assert). INSTANT events encode scope in flags, should be stored |
| 90 | // using "s" key in JSON. COPY flag should be supported or rejected. |
| 91 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 92 | // Figure out how much extra storage we need for copied strings |
| 93 | int size = static_cast<int>(sizeof(TraceEvent) + numArgs * sizeof(TraceEventArg)); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 94 | for (int i = 0; i < numArgs; ++i) { |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 95 | if (TRACE_VALUE_TYPE_COPY_STRING == argTypes[i]) { |
| 96 | skia::tracing_internals::TraceValueUnion value; |
Brian Osman | de6e5bf | 2017-07-21 15:30:14 -0400 | [diff] [blame] | 97 | value.as_uint = argValues[i]; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 98 | size += strlen(value.as_string) + 1; |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 99 | } |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 100 | } |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 101 | |
Brian Osman | 3fa1043 | 2018-10-24 13:22:32 -0400 | [diff] [blame] | 102 | size = SkAlign8(size); |
| 103 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 104 | SkSTArray<128, uint8_t, true> storage; |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 105 | uint8_t* storagePtr = storage.push_back_n(size); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 106 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 107 | TraceEvent* traceEvent = reinterpret_cast<TraceEvent*>(storagePtr); |
| 108 | traceEvent->fPhase = phase; |
| 109 | traceEvent->fNumArgs = numArgs; |
| 110 | traceEvent->fSize = size; |
| 111 | traceEvent->fName = name; |
| 112 | traceEvent->fID = id; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 113 | traceEvent->fClockBegin = std::chrono::steady_clock::now().time_since_epoch().count(); |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 114 | traceEvent->fClockEnd = 0; |
| 115 | traceEvent->fThreadID = SkGetThreadID(); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 116 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 117 | TraceEventArg* traceEventArgs = traceEvent->args(); |
| 118 | char* stringTableBase = traceEvent->stringTable(); |
| 119 | char* stringTable = stringTableBase; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 120 | for (int i = 0; i < numArgs; ++i) { |
| 121 | traceEventArgs[i].fArgName = argNames[i]; |
| 122 | traceEventArgs[i].fArgType = argTypes[i]; |
| 123 | if (TRACE_VALUE_TYPE_COPY_STRING == argTypes[i]) { |
| 124 | // Just write an offset into the arguments array |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 125 | traceEventArgs[i].fArgValue = stringTable - stringTableBase; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 126 | |
| 127 | // Copy string into our buffer (and advance) |
| 128 | skia::tracing_internals::TraceValueUnion value; |
| 129 | value.as_uint = argValues[i]; |
| 130 | while (*value.as_string) { |
| 131 | *stringTable++ = *value.as_string++; |
| 132 | } |
| 133 | *stringTable++ = 0; |
| 134 | } else { |
| 135 | traceEventArgs[i].fArgValue = argValues[i]; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | return this->appendEvent(storagePtr, size); |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 140 | } |
| 141 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 142 | void ChromeTracingTracer::updateTraceEventDuration(const uint8_t* categoryEnabledFlag, |
| 143 | const char* name, |
| 144 | SkEventTracer::Handle handle) { |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 145 | // We could probably get away with not locking here, but let's be totally safe. |
Herb Derby | a1b7be6 | 2019-05-09 16:59:18 -0400 | [diff] [blame] | 146 | SkAutoSpinlock lock(fMutex); |
| 147 | TraceEvent* traceEvent = reinterpret_cast<TraceEvent*>(handle); |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 148 | traceEvent->fClockEnd = std::chrono::steady_clock::now().time_since_epoch().count(); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 149 | } |
| 150 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 151 | static void trace_value_to_json(SkJSONWriter* writer, |
| 152 | uint64_t argValue, |
| 153 | uint8_t argType, |
| 154 | const char* stringTableBase) { |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 155 | skia::tracing_internals::TraceValueUnion value; |
| 156 | value.as_uint = argValue; |
| 157 | |
| 158 | switch (argType) { |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 159 | case TRACE_VALUE_TYPE_BOOL: writer->appendBool(value.as_bool); break; |
| 160 | case TRACE_VALUE_TYPE_UINT: writer->appendU64(value.as_uint); break; |
| 161 | case TRACE_VALUE_TYPE_INT: writer->appendS64(value.as_int); break; |
| 162 | case TRACE_VALUE_TYPE_DOUBLE: writer->appendDouble(value.as_double); break; |
| 163 | case TRACE_VALUE_TYPE_POINTER: writer->appendPointer(value.as_pointer); break; |
| 164 | case TRACE_VALUE_TYPE_STRING: writer->appendString(value.as_string); break; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 165 | case TRACE_VALUE_TYPE_COPY_STRING: |
| 166 | writer->appendString(stringTableBase + value.as_uint); |
| 167 | break; |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 168 | default: writer->appendString("<unknown type>"); break; |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 169 | } |
| 170 | } |
| 171 | |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 172 | namespace { |
| 173 | |
| 174 | struct TraceEventSerializationState { |
| 175 | TraceEventSerializationState(uint64_t clockOffset) |
| 176 | : fClockOffset(clockOffset), fNextThreadID(0) {} |
| 177 | |
| 178 | int getShortThreadID(SkThreadID id) { |
| 179 | if (int* shortIDPtr = fShortThreadIDMap.find(id)) { |
| 180 | return *shortIDPtr; |
| 181 | } |
| 182 | int shortID = fNextThreadID++; |
| 183 | fShortThreadIDMap.set(id, shortID); |
| 184 | return shortID; |
| 185 | } |
| 186 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 187 | uint64_t fClockOffset; |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 188 | SkTHashMap<uint64_t, const char*> fBaseTypeResolver; |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 189 | int fNextThreadID; |
| 190 | SkTHashMap<SkThreadID, int> fShortThreadIDMap; |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 191 | }; |
| 192 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 193 | } // namespace |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 194 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 195 | static void trace_event_to_json(SkJSONWriter* writer, |
| 196 | TraceEvent* traceEvent, |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 197 | TraceEventSerializationState* serializationState) { |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 198 | // We track the original (creation time) "name" of each currently live object, so we can |
| 199 | // automatically insert "base_name" fields in object snapshot events. |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 200 | auto baseTypeResolver = &(serializationState->fBaseTypeResolver); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 201 | if (TRACE_EVENT_PHASE_CREATE_OBJECT == traceEvent->fPhase) { |
| 202 | SkASSERT(nullptr == baseTypeResolver->find(traceEvent->fID)); |
| 203 | baseTypeResolver->set(traceEvent->fID, traceEvent->fName); |
| 204 | } else if (TRACE_EVENT_PHASE_DELETE_OBJECT == traceEvent->fPhase) { |
| 205 | SkASSERT(nullptr != baseTypeResolver->find(traceEvent->fID)); |
| 206 | baseTypeResolver->remove(traceEvent->fID); |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 207 | } |
| 208 | |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 209 | writer->beginObject(); |
| 210 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 211 | char phaseString[2] = {traceEvent->fPhase, 0}; |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 212 | writer->appendString("ph", phaseString); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 213 | writer->appendString("name", traceEvent->fName); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 214 | if (0 != traceEvent->fID) { |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 215 | // IDs are (almost) always pointers |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 216 | writer->appendPointer("id", reinterpret_cast<void*>(traceEvent->fID)); |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 217 | } |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 218 | |
| 219 | // Offset timestamps to reduce JSON length, then convert nanoseconds to microseconds |
| 220 | // (standard time unit for tracing JSON files). |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 221 | uint64_t relativeTimestamp = |
| 222 | static_cast<int64_t>(traceEvent->fClockBegin - serializationState->fClockOffset); |
Brian Osman | b500ef7 | 2019-06-17 16:14:45 -0400 | [diff] [blame] | 223 | writer->appendDouble("ts", static_cast<double>(relativeTimestamp) * 1E-3); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 224 | if (0 != traceEvent->fClockEnd) { |
| 225 | double dur = static_cast<double>(traceEvent->fClockEnd - traceEvent->fClockBegin) * 1E-3; |
Brian Osman | b500ef7 | 2019-06-17 16:14:45 -0400 | [diff] [blame] | 226 | writer->appendDouble("dur", dur); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 227 | } |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 228 | |
| 229 | writer->appendS64("tid", serializationState->getShortThreadID(traceEvent->fThreadID)); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 230 | // Trace events *must* include a process ID, but for internal tools this isn't particularly |
| 231 | // important (and certainly not worth adding a cross-platform API to get it). |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 232 | writer->appendS32("pid", 0); |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 233 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 234 | if (traceEvent->fNumArgs) { |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 235 | writer->beginObject("args"); |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 236 | const char* stringTable = traceEvent->stringTable(); |
| 237 | bool addedSnapshot = false; |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 238 | if (TRACE_EVENT_PHASE_SNAPSHOT_OBJECT == traceEvent->fPhase && |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 239 | baseTypeResolver->find(traceEvent->fID) && |
| 240 | 0 != strcmp(*baseTypeResolver->find(traceEvent->fID), traceEvent->fName)) { |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 241 | // Special handling for snapshots where the name differs from creation. |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 242 | writer->beginObject("snapshot"); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 243 | writer->appendString("base_type", *baseTypeResolver->find(traceEvent->fID)); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 244 | addedSnapshot = true; |
Brian Osman | b6705c2 | 2017-08-01 10:23:38 -0400 | [diff] [blame] | 245 | } |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 246 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 247 | for (int i = 0; i < traceEvent->fNumArgs; ++i) { |
| 248 | const TraceEventArg* arg = traceEvent->args() + i; |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 249 | // TODO: Skip '#' |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 250 | writer->appendName(arg->fArgName); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 251 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 252 | if (arg->fArgName && '#' == arg->fArgName[0]) { |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 253 | writer->beginObject(); |
| 254 | writer->appendName("id_ref"); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 255 | trace_value_to_json(writer, arg->fArgValue, arg->fArgType, stringTable); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 256 | writer->endObject(); |
| 257 | } else { |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 258 | trace_value_to_json(writer, arg->fArgValue, arg->fArgType, stringTable); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 259 | } |
| 260 | } |
| 261 | |
| 262 | if (addedSnapshot) { |
| 263 | writer->endObject(); |
| 264 | } |
| 265 | |
| 266 | writer->endObject(); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 267 | } |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 268 | |
| 269 | writer->endObject(); |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 270 | } |
| 271 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 272 | void ChromeTracingTracer::flush() { |
Herb Derby | a1b7be6 | 2019-05-09 16:59:18 -0400 | [diff] [blame] | 273 | SkAutoSpinlock lock(fMutex); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 274 | |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 275 | SkString dirname = SkOSPath::Dirname(fFilename.c_str()); |
Brian Osman | bc8150f | 2017-07-24 11:38:01 -0400 | [diff] [blame] | 276 | if (!dirname.isEmpty() && !sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) { |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 277 | if (!sk_mkdir(dirname.c_str())) { |
| 278 | SkDebugf("Failed to create directory."); |
| 279 | } |
| 280 | } |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 281 | |
| 282 | SkFILEWStream fileStream(fFilename.c_str()); |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 283 | SkJSONWriter writer(&fileStream, SkJSONWriter::Mode::kFast); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 284 | writer.beginArray(); |
| 285 | |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 286 | uint64_t clockOffset = 0; |
| 287 | if (fBlocks.count() > 0) { |
| 288 | clockOffset = reinterpret_cast<TraceEvent*>(fBlocks[0].fBlock.get())->fClockBegin; |
| 289 | } else if (fCurBlock.fEventsInBlock > 0) { |
| 290 | clockOffset = reinterpret_cast<TraceEvent*>(fCurBlock.fBlock.get())->fClockBegin; |
| 291 | } |
| 292 | |
| 293 | TraceEventSerializationState serializationState(clockOffset); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 294 | |
Mike Klein | eb678fc | 2019-03-20 12:01:47 -0500 | [diff] [blame] | 295 | auto event_block_to_json = [](SkJSONWriter* writer, |
| 296 | const TraceEventBlock& block, |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 297 | TraceEventSerializationState* serializationState) { |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 298 | TraceEvent* traceEvent = reinterpret_cast<TraceEvent*>(block.fBlock.get()); |
| 299 | for (int i = 0; i < block.fEventsInBlock; ++i) { |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 300 | trace_event_to_json(writer, traceEvent, serializationState); |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 301 | traceEvent = traceEvent->next(); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 302 | } |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 303 | }; |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 304 | |
Brian Osman | c7f2676 | 2017-08-16 10:31:29 -0400 | [diff] [blame] | 305 | for (int i = 0; i < fBlocks.count(); ++i) { |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 306 | event_block_to_json(&writer, fBlocks[i], &serializationState); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 307 | } |
Brian Osman | b6f8212 | 2017-08-16 16:56:04 -0400 | [diff] [blame] | 308 | event_block_to_json(&writer, fCurBlock, &serializationState); |
Brian Osman | 69fd008 | 2017-08-09 09:25:39 -0400 | [diff] [blame] | 309 | |
| 310 | writer.endArray(); |
| 311 | writer.flush(); |
| 312 | fileStream.flush(); |
Brian Osman | 53136aa | 2017-07-20 15:43:35 -0400 | [diff] [blame] | 313 | } |