diff --git a/BUILD.gn b/BUILD.gn index 70b8cb5c34..975d560278 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1030,8 +1030,12 @@ if (skia_enable_tools) { "tools/sk_tool_utils.cpp", "tools/sk_tool_utils_font.cpp", "tools/timer/Timer.cpp", + "tools/trace/SkChromeTracingTracer.cpp", + "tools/trace/SkChromeTracingTracer.h", "tools/trace/SkDebugfTracer.cpp", "tools/trace/SkDebugfTracer.h", + "tools/trace/SkEventTracingPriv.cpp", + "tools/trace/SkEventTracingPriv.h", ] libs = [] if (is_ios) { diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index 7148bc26fd..05c475a391 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -33,6 +33,7 @@ #include "SkCommonFlagsPathRenderer.h" #include "SkData.h" #include "SkDebugfTracer.h" +#include "SkEventTracingPriv.h" #include "SkGraphics.h" #include "SkLeanWindows.h" #include "SkOSFile.h" @@ -1104,9 +1105,9 @@ static void start_keepalive() { int main(int argc, char** argv) { SkCommandLineFlags::Parse(argc, argv); - if (FLAGS_trace) { - SkEventTracer::SetInstance(new SkDebugfTracer); - } + + initializeEventTracingForTools(&FLAGS_threads); + #if defined(SK_BUILD_FOR_IOS) cd_Documents(); #endif diff --git a/dm/DM.cpp b/dm/DM.cpp index 06ad765f3d..6310ed77f4 100644 --- a/dm/DM.cpp +++ b/dm/DM.cpp @@ -11,6 +11,7 @@ #include "Resources.h" #include "SkBBHFactory.h" #include "SkChecksum.h" +#include "SkChromeTracingTracer.h" #include "SkCodec.h" #include "SkColorPriv.h" #include "SkColorSpace.h" @@ -20,7 +21,7 @@ #include "SkCommonFlagsPathRenderer.h" #include "SkData.h" #include "SkDebugfTracer.h" -#include "SkEventTracer.h" +#include "SkEventTracingPriv.h" #include "SkFontMgr.h" #include "SkGraphics.h" #include "SkHalf.h" @@ -1272,10 +1273,10 @@ extern sk_sp (*gCreateTypefaceDelegate)(const char [], SkFontStyle ) int main(int argc, char** argv) { SkCommandLineFlags::Parse(argc, argv); - if (FLAGS_trace) { - SkAssertResult(SkEventTracer::SetInstance(new SkDebugfTracer())); - } - #if defined(SK_BUILD_FOR_IOS) + + initializeEventTracingForTools(&FLAGS_threads); + +#if defined(SK_BUILD_FOR_IOS) cd_Documents(); #endif setbuf(stdout, nullptr); @@ -1386,6 +1387,7 @@ int main(int argc, char** argv) { SkGraphics::PurgeAllCaches(); info("Finished!\n"); + return 0; } diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp index 35fc0cf82f..0148bcd820 100644 --- a/tools/flags/SkCommonFlags.cpp +++ b/tools/flags/SkCommonFlags.cpp @@ -72,8 +72,6 @@ DEFINE_bool(forceAnalyticAA, false, "Force analytic anti-aliasing even if the pa "whether it's concave or convex, we consider a path complicated" "if its number of points is comparable to its resolution."); -DEFINE_bool(trace, false, "Show trace events using SkDebugf."); - bool CollectImages(SkCommandLineFlags::StringArray images, SkTArray* output) { SkASSERT(output); diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h index 71ff8c3753..92ac141dad 100644 --- a/tools/flags/SkCommonFlags.h +++ b/tools/flags/SkCommonFlags.h @@ -34,7 +34,6 @@ DECLARE_string(writePath); DECLARE_bool(pre_log); DECLARE_bool(analyticAA); DECLARE_bool(forceAnalyticAA); -DECLARE_bool(trace) DECLARE_string(key); DECLARE_string(properties); diff --git a/tools/trace/SkChromeTracingTracer.cpp b/tools/trace/SkChromeTracingTracer.cpp new file mode 100644 index 0000000000..aa71ff0448 --- /dev/null +++ b/tools/trace/SkChromeTracingTracer.cpp @@ -0,0 +1,96 @@ +/* + * 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 + +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) { + Json::Value traceEvent; + char phaseString[2] = { phase, 0 }; + traceEvent["ph"] = phaseString; + traceEvent["name"] = name; + traceEvent["cat"] = "skia"; // TODO + auto now = std::chrono::high_resolution_clock::now(); + std::chrono::duration ns = now.time_since_epoch(); + traceEvent["ts"] = ns.count() * 1E-3; + traceEvent["tid"] = static_cast(SkGetThreadID()); + traceEvent["pid"] = 1; // TODO + + if (numArgs) { + Json::Value args; + for (int i = 0; i < numArgs; ++i) { + switch (argTypes[i]) { + case TRACE_VALUE_TYPE_BOOL: + args[argNames[i]] = (*reinterpret_cast(argValues[i]) ? true : false); + break; + case TRACE_VALUE_TYPE_UINT: + args[argNames[i]] = static_cast(argValues[i]); + break; + case TRACE_VALUE_TYPE_INT: + args[argNames[i]] = static_cast(argValues[i]); + break; + case TRACE_VALUE_TYPE_DOUBLE: + args[argNames[i]] = *SkTCast(&argValues[i]); + break; + case TRACE_VALUE_TYPE_POINTER: + args[argNames[i]] = reinterpret_cast(argValues[i]); + break; + case TRACE_VALUE_TYPE_STRING: + case TRACE_VALUE_TYPE_COPY_STRING: + args[argNames[i]] = reinterpret_cast(argValues[i]); + break; + default: + args[argNames[i]] = ""; + break; + } + } + traceEvent["args"] = args; + } + Json::Value& newValue(fRoot.append(traceEvent)); + return reinterpret_cast(&newValue); +} + +void SkChromeTracingTracer::updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) { + Json::Value* traceEvent = reinterpret_cast(handle); + auto now = std::chrono::high_resolution_clock::now(); + std::chrono::duration ns = now.time_since_epoch(); + auto us = ns.count() * 1E-3; + (*traceEvent)["dur"] = us - (*traceEvent)["ts"].asDouble(); +} + +const uint8_t* SkChromeTracingTracer::getCategoryGroupEnabled(const char* name) { + static uint8_t yes = SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags; + return &yes; +} + +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(); +} diff --git a/tools/trace/SkChromeTracingTracer.h b/tools/trace/SkChromeTracingTracer.h new file mode 100644 index 0000000000..da34205aa5 --- /dev/null +++ b/tools/trace/SkChromeTracingTracer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkChromeTracingTracer_DEFINED +#define SkChromeTracingTracer_DEFINED + +#include "SkEventTracer.h" +#include "SkJSONCPP.h" +#include "SkString.h" + +/** + * A SkEventTracer implementation that logs events to JSON for viewing with chrome://tracing. + */ +class SkChromeTracingTracer : public SkEventTracer { +public: + SkChromeTracingTracer(const char* filename) : fRoot(Json::arrayValue), fFilename(filename) {} + ~SkChromeTracingTracer() override { this->flush(); } + + SkEventTracer::Handle 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) override; + + void updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) override; + + const uint8_t* getCategoryGroupEnabled(const char* name) override; + + const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) override { + static const char* category = "category?"; + return category; + } + +private: + void flush(); + + Json::Value fRoot; + SkString fFilename; +}; + +#endif diff --git a/tools/trace/SkEventTracingPriv.cpp b/tools/trace/SkEventTracingPriv.cpp new file mode 100644 index 0000000000..217511ffa7 --- /dev/null +++ b/tools/trace/SkEventTracingPriv.cpp @@ -0,0 +1,44 @@ +/* + * 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 "SkEventTracingPriv.h" + +#include "SkATrace.h" +#include "SkCommandLineFlags.h" +#include "SkEventTracer.h" +#include "SkChromeTracingTracer.h" +#include "SkDebugfTracer.h" + +DEFINE_string(trace, "", + "Log trace events in one of several modes:\n" + " debugf : Show events using SkDebugf\n" + " atrace : Send events to Android ATrace\n" + " : Any other string is interpreted as a filename. Writes\n" + " trace events to specified file as JSON, for viewing\n" + " with chrome://tracing"); + +void initializeEventTracingForTools(int32_t* threadsFlag) { + if (FLAGS_trace.isEmpty()) { + return; + } + + const char* traceFlag = FLAGS_trace[0]; + SkEventTracer* eventTracer = nullptr; + if (0 == strcmp(traceFlag, "atrace")) { + eventTracer = new SkATrace(); + } else if (0 == strcmp(traceFlag, "debugf")) { + eventTracer = new SkDebugfTracer(); + } else { + if (threadsFlag && *threadsFlag != 0) { + SkDebugf("JSON tracing is not yet thread-safe, disabling threading.\n"); + *threadsFlag = 0; + } + eventTracer = new SkChromeTracingTracer(traceFlag); + } + + SkAssertResult(SkEventTracer::SetInstance(eventTracer)); +} diff --git a/tools/trace/SkEventTracingPriv.h b/tools/trace/SkEventTracingPriv.h new file mode 100644 index 0000000000..330f3f83ed --- /dev/null +++ b/tools/trace/SkEventTracingPriv.h @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEventTracingPriv_DEFINED +#define SkEventTracingPriv_DEFINED + +#include "SkTypes.h" + +/** + * Construct and install an SkEventTracer, based on the 'trace' command line argument. + * + * @param threadsFlag Pointer to the FLAGS_threads variable (or nullptr). This is used to disable + * threading when tracing to JSON. (Remove this param when JSON tracer is thread + * safe). + */ +void initializeEventTracingForTools(int32_t* threadsFlag); + +#endif diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp index 6753b6b63e..6e20cbb4f9 100644 --- a/tools/viewer/Viewer.cpp +++ b/tools/viewer/Viewer.cpp @@ -21,6 +21,7 @@ #include "SkCommandLineFlags.h" #include "SkCommonFlagsPathRenderer.h" #include "SkDashPathEffect.h" +#include "SkEventTracingPriv.h" #include "SkGraphics.h" #include "SkImagePriv.h" #include "SkMetaData.h" @@ -157,12 +158,11 @@ static DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from."); static DEFINE_string2(backend, b, "sw", "Backend to use. Allowed values are " BACKENDS_STR "."); -static DEFINE_bool(atrace, false, "Enable support for using ATrace. ATrace is only supported on Android."); - DEFINE_int32(msaa, 0, "Number of subpixel samples. 0 for no HW antialiasing."); DEFINE_pathrenderer_flag; DEFINE_bool(instancedRendering, false, "Enable instanced rendering on GPU backends."); +DECLARE_int32(threads) const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = { "OpenGL", @@ -255,7 +255,6 @@ Viewer::Viewer(int argc, char** argv, void* platformData) , fZoomLevel(0.0f) , fGestureDevice(GestureDevice::kNone) { - static SkTaskGroup::Enabler kTaskGroupEnabler; SkGraphics::Init(); static SkOnce initPathRendererNames; @@ -285,9 +284,8 @@ Viewer::Viewer(int argc, char** argv, void* platformData) SetResourcePath("/data/local/tmp/resources"); #endif - if (FLAGS_atrace) { - SkAssertResult(SkEventTracer::SetInstance(new SkATrace())); - } + initializeEventTracingForTools(&FLAGS_threads); + static SkTaskGroup::Enabler kTaskGroupEnabler(FLAGS_threads); fBackendType = get_backend_type(FLAGS_backend[0]); fWindow = Window::CreateNativeWindow(platformData);