diff options
author | Brian Osman <brianosman@google.com> | 2017-07-24 11:38:01 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-24 17:13:05 +0000 |
commit | bc8150feef7aebb92811e8d976b65b04767c44f8 (patch) | |
tree | 350590451ea59f88ca5b5f9bdc45c9c1f1ead598 /tools/trace/SkChromeTracingTracer.cpp | |
parent | ff46ace077da67957dc74754db960a3e78e7c41b (diff) |
Faster, thread-safe implementation
Bug: skia:
Change-Id: I401c5a9885c348aa424ab07b094acecddb209490
Reviewed-on: https://skia-review.googlesource.com/25860
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'tools/trace/SkChromeTracingTracer.cpp')
-rw-r--r-- | tools/trace/SkChromeTracingTracer.cpp | 136 |
1 files changed, 99 insertions, 37 deletions
diff --git a/tools/trace/SkChromeTracingTracer.cpp b/tools/trace/SkChromeTracingTracer.cpp index 0cfb1bf5f9..4f424f8801 100644 --- a/tools/trace/SkChromeTracingTracer.cpp +++ b/tools/trace/SkChromeTracingTracer.cpp @@ -14,6 +14,31 @@ #include <chrono> +SkChromeTracingTracer::SkChromeTracingTracer(const char* filename) : fFilename(filename) { + fCurBlock = this->createBlock(); + fEventsInCurBlock = 0; +} + +SkChromeTracingTracer::~SkChromeTracingTracer() { + this->flush(); +} + +SkChromeTracingTracer::BlockPtr SkChromeTracingTracer::createBlock() { + return BlockPtr(new TraceEvent[kEventsPerBlock]); +} + +SkChromeTracingTracer::TraceEvent* SkChromeTracingTracer::appendEvent( + const TraceEvent& traceEvent) { + SkAutoMutexAcquire lock(fMutex); + if (fEventsInCurBlock >= kEventsPerBlock) { + fBlocks.push_back(std::move(fCurBlock)); + fCurBlock = this->createBlock(); + fEventsInCurBlock = 0; + } + fCurBlock[fEventsInCurBlock] = traceEvent; + return &fCurBlock[fEventsInCurBlock++]; +} + SkEventTracer::Handle SkChromeTracingTracer::addTraceEvent(char phase, const uint8_t* categoryEnabledFlag, const char* name, @@ -26,74 +51,111 @@ SkEventTracer::Handle SkChromeTracingTracer::addTraceEvent(char phase, // TODO: Respect flags (or assert). INSTANT events encode scope in flags, should be stored // using "s" key in JSON. COPY flag should be supported or rejected. - Json::Value traceEvent; - char phaseString[2] = { phase, 0 }; - traceEvent["ph"] = phaseString; - traceEvent["name"] = name; - traceEvent["cat"] = this->getCategoryGroupName(categoryEnabledFlag); - auto now = std::chrono::high_resolution_clock::now(); - std::chrono::duration<double, std::nano> ns = now.time_since_epoch(); - traceEvent["ts"] = ns.count() * 1E-3; - traceEvent["tid"] = static_cast<Json::Int64>(SkGetThreadID()); + TraceEvent traceEvent; + traceEvent.fPhase = phase; + traceEvent.fNumArgs = numArgs; + traceEvent.fName = name; + traceEvent.fCategory = fCategories.getCategoryGroupName(categoryEnabledFlag); + traceEvent.fClockBegin = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + traceEvent.fClockEnd = 0; + traceEvent.fThreadID = SkGetThreadID(); + for (int i = 0; i < numArgs; ++i) { + traceEvent.fArgNames[i] = argNames[i]; + traceEvent.fArgTypes[i] = argTypes[i]; + if (TRACE_VALUE_TYPE_COPY_STRING == argTypes[i]) { + skia::tracing_internals::TraceValueUnion value; + value.as_uint = argValues[i]; + value.as_string = SkStrDup(value.as_string); + traceEvent.fArgValues[i] = value.as_uint; + } else { + traceEvent.fArgValues[i] = argValues[i]; + } + } + + return reinterpret_cast<Handle>(this->appendEvent(traceEvent)); +} + +void SkChromeTracingTracer::updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) { + // We could probably get away with not locking here, but let's be totally safe. + SkAutoMutexAcquire lock(fMutex); + TraceEvent* traceEvent = reinterpret_cast<TraceEvent*>(handle); + traceEvent->fClockEnd = std::chrono::high_resolution_clock::now().time_since_epoch().count(); +} + +Json::Value SkChromeTracingTracer::traceEventToJson(const TraceEvent& traceEvent) { + Json::Value json; + char phaseString[2] = { traceEvent.fPhase, 0 }; + json["ph"] = phaseString; + json["name"] = traceEvent.fName; + json["cat"] = traceEvent.fCategory; + json["ts"] = static_cast<double>(traceEvent.fClockBegin) * 1E-3; + if (0 != traceEvent.fClockEnd) { + json["dur"] = static_cast<double>(traceEvent.fClockEnd - traceEvent.fClockBegin) * 1E-3; + } + json["tid"] = static_cast<Json::Int64>(traceEvent.fThreadID); // Trace events *must* include a process ID, but for internal tools this isn't particularly // important (and certainly not worth adding a cross-platform API to get it). - traceEvent["pid"] = 0; - - if (numArgs) { + json["pid"] = 0; + if (traceEvent.fNumArgs) { Json::Value args; skia::tracing_internals::TraceValueUnion value; - for (int i = 0; i < numArgs; ++i) { - value.as_uint = argValues[i]; - switch (argTypes[i]) { + for (int i = 0; i < traceEvent.fNumArgs; ++i) { + value.as_uint = traceEvent.fArgValues[i]; + switch (traceEvent.fArgTypes[i]) { case TRACE_VALUE_TYPE_BOOL: - args[argNames[i]] = value.as_bool; + args[traceEvent.fArgNames[i]] = value.as_bool; break; case TRACE_VALUE_TYPE_UINT: - args[argNames[i]] = static_cast<Json::UInt64>(argValues[i]); + args[traceEvent.fArgNames[i]] = static_cast<Json::UInt64>(value.as_uint); break; case TRACE_VALUE_TYPE_INT: - args[argNames[i]] = static_cast<Json::Int64>(argValues[i]); + args[traceEvent.fArgNames[i]] = static_cast<Json::Int64>(value.as_uint); break; case TRACE_VALUE_TYPE_DOUBLE: - args[argNames[i]] = value.as_double; + args[traceEvent.fArgNames[i]] = value.as_double; break; case TRACE_VALUE_TYPE_POINTER: - args[argNames[i]] = value.as_pointer; + args[traceEvent.fArgNames[i]] = value.as_pointer; break; case TRACE_VALUE_TYPE_STRING: case TRACE_VALUE_TYPE_COPY_STRING: - args[argNames[i]] = value.as_string; + args[traceEvent.fArgNames[i]] = value.as_string; break; default: - args[argNames[i]] = "<unknown type>"; + args[traceEvent.fArgNames[i]] = "<unknown type>"; break; } } - traceEvent["args"] = args; + json["args"] = args; } - Json::Value& newValue(fRoot.append(traceEvent)); - return reinterpret_cast<Handle>(&newValue); -} - -void SkChromeTracingTracer::updateTraceEventDuration(const uint8_t* categoryEnabledFlag, - const char* name, - SkEventTracer::Handle handle) { - Json::Value* traceEvent = reinterpret_cast<Json::Value*>(handle); - auto now = std::chrono::high_resolution_clock::now(); - std::chrono::duration<double, std::nano> ns = now.time_since_epoch(); - auto us = ns.count() * 1E-3; - (*traceEvent)["dur"] = us - (*traceEvent)["ts"].asDouble(); + return json; } void SkChromeTracingTracer::flush() { + SkAutoMutexAcquire lock(fMutex); + + Json::Value root(Json::arrayValue); + + for (int i = 0; i < fBlocks.count(); ++i) { + for (int j = 0; j < kEventsPerBlock; ++j) { + root.append(this->traceEventToJson(fBlocks[i][j])); + } + } + + for (int i = 0; i < fEventsInCurBlock; ++i) { + root.append(this->traceEventToJson(fCurBlock[i])); + } + SkString dirname = SkOSPath::Dirname(fFilename.c_str()); - if (!sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) { + if (!dirname.isEmpty() && !sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) { if (!sk_mkdir(dirname.c_str())) { SkDebugf("Failed to create directory."); } } SkFILEWStream stream(fFilename.c_str()); - stream.writeText(Json::StyledWriter().write(fRoot).c_str()); + stream.writeText(Json::FastWriter().write(root).c_str()); stream.flush(); } |