blob: 0cfb1bf5f918df41d4ca2684874c2766a92a6a57 [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkChromeTracingTracer.h"
#include "SkThreadID.h"
#include "SkTraceEvent.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
#include "SkStream.h"
#include <chrono>
SkEventTracer::Handle SkChromeTracingTracer::addTraceEvent(char phase,
const uint8_t* categoryEnabledFlag,
const char* name,
uint64_t id,
int numArgs,
const char** argNames,
const uint8_t* argTypes,
const uint64_t* argValues,
uint8_t flags) {
// 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());
// 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::Value args;
skia::tracing_internals::TraceValueUnion value;
for (int i = 0; i < numArgs; ++i) {
value.as_uint = argValues[i];
switch (argTypes[i]) {
case TRACE_VALUE_TYPE_BOOL:
args[argNames[i]] = value.as_bool;
break;
case TRACE_VALUE_TYPE_UINT:
args[argNames[i]] = static_cast<Json::UInt64>(argValues[i]);
break;
case TRACE_VALUE_TYPE_INT:
args[argNames[i]] = static_cast<Json::Int64>(argValues[i]);
break;
case TRACE_VALUE_TYPE_DOUBLE:
args[argNames[i]] = value.as_double;
break;
case TRACE_VALUE_TYPE_POINTER:
args[argNames[i]] = value.as_pointer;
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
args[argNames[i]] = value.as_string;
break;
default:
args[argNames[i]] = "<unknown type>";
break;
}
}
traceEvent["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();
}
void SkChromeTracingTracer::flush() {
SkString dirname = SkOSPath::Dirname(fFilename.c_str());
if (!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.flush();
}