aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/trace/SkChromeTracingTracer.cpp
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-07-24 11:38:01 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-24 17:13:05 +0000
commitbc8150feef7aebb92811e8d976b65b04767c44f8 (patch)
tree350590451ea59f88ca5b5f9bdc45c9c1f1ead598 /tools/trace/SkChromeTracingTracer.cpp
parentff46ace077da67957dc74754db960a3e78e7c41b (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.cpp136
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();
}