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
8 #include "include/core/SkImageInfo.h"
9 #include "include/core/SkPoint.h"
10 #include "include/core/SkRect.h"
11 #include "src/core/SkLeanWindows.h"
12 #include "src/core/SkTraceEvent.h"
13 #include "tests/Test.h"
14 #include "tools/flags/CommandLineFlags.h"
15
16 static DEFINE_bool(slowTracingTest, false,
17 "Artificially slow down tracing test to produce nicer JSON");
18
19 namespace {
20
21 /**
22 * Helper types for demonstrating usage of TRACE_EVENT_OBJECT_XXX macros.
23 */
24 struct TracingShape {
TracingShape__anon415cd4b60111::TracingShape25 TracingShape() {
26 TRACE_EVENT_OBJECT_CREATED_WITH_ID("skia.objects", this->typeName(), this);
27 }
~TracingShape__anon415cd4b60111::TracingShape28 virtual ~TracingShape() {
29 TRACE_EVENT_OBJECT_DELETED_WITH_ID("skia.objects", this->typeName(), this);
30 }
traceSnapshot__anon415cd4b60111::TracingShape31 void traceSnapshot() {
32 // The state of an object can be specified at any point with the OBJECT_SNAPSHOT macro.
33 // This takes the "name" (actually the type name), the ID of the object (typically a
34 // pointer), and a single (unnnamed) argument, which is the "snapshot" of that object.
35 //
36 // Tracing viewer requires that all object macros use the same name and id for creation,
37 // deletion, and snapshots. However: It's convenient to put creation and deletion in the
38 // base-class constructor/destructor where the actual type name isn't known yet. That's
39 // what we're doing here. The JSON for snapshots can therefore include the actual type
40 // name, and a special tag that refers to the type name originally used at creation time.
41 // Skia's JSON tracer handles this automatically, so SNAPSHOT macros can simply use the
42 // derived type name, and the JSON will be formatted correctly to link the events.
43 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("skia.objects", this->typeName(), this,
44 TRACE_STR_COPY(this->toString().c_str()));
45 }
46
typeName__anon415cd4b60111::TracingShape47 virtual const char* typeName() { return "TracingShape"; }
toString__anon415cd4b60111::TracingShape48 virtual SkString toString() { return SkString("Shape()"); }
49 };
50
51 struct TracingCircle : public TracingShape {
TracingCircle__anon415cd4b60111::TracingCircle52 TracingCircle(SkPoint center, SkScalar radius) : fCenter(center), fRadius(radius) {}
typeName__anon415cd4b60111::TracingCircle53 const char* typeName() override { return "TracingCircle"; }
toString__anon415cd4b60111::TracingCircle54 SkString toString() override {
55 return SkStringPrintf("Circle(%f, %f, %f)", fCenter.fX, fCenter.fY, fRadius);
56 }
57
58 SkPoint fCenter;
59 SkScalar fRadius;
60 };
61
62 struct TracingRect : public TracingShape {
TracingRect__anon415cd4b60111::TracingRect63 TracingRect(SkRect rect) : fRect(rect) {}
typeName__anon415cd4b60111::TracingRect64 const char* typeName() override { return "TracingRect"; }
toString__anon415cd4b60111::TracingRect65 SkString toString() override {
66 return SkStringPrintf("Rect(%f, %f, %f, %f)",
67 fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom);
68 }
69
70 SkRect fRect;
71 };
72
73 } // namespace
74
75 static SkScalar gTracingTestWorkSink = 1.0f;
76
do_work(int howMuchWork)77 static void do_work(int howMuchWork) {
78 // Do busy work so the trace marker durations are large enough to be readable in trace viewer
79 if (FLAGS_slowTracingTest) {
80 for (int i = 0; i < howMuchWork * 100; ++i) {
81 gTracingTestWorkSink += SkScalarSin(i);
82 }
83 }
84 }
85
test_trace_simple()86 static void test_trace_simple() {
87 // Simple event that lasts until the end of the current scope. TRACE_FUNC is an easy way
88 // to insert the current function name.
89 TRACE_EVENT0("skia", TRACE_FUNC);
90
91 {
92 // There are versions of the macro that take 1 or 2 named arguments. The arguments
93 // can be any simple type. Strings need to be static/literal - we just copy pointers.
94 // Argument names & values are shown when the event is selected in the viewer.
95 TRACE_EVENT1("skia", "Nested work",
96 "isBGRA", kN32_SkColorType == kBGRA_8888_SkColorType);
97 do_work(500);
98 }
99
100 {
101 // If you must copy a string as an argument value, use the TRACE_STR_COPY macro.
102 // This will instruct the tracing system (if one is active) to make a copy.
103 SkString message = SkStringPrintf("%s %s", "Hello", "World");
104 TRACE_EVENT1("skia", "Dynamic String", "message", TRACE_STR_COPY(message.c_str()));
105 do_work(500);
106 }
107 }
108
test_trace_counters()109 static void test_trace_counters() {
110 TRACE_EVENT0("skia", TRACE_FUNC);
111
112 {
113 TRACE_EVENT0("skia", "Single Counter");
114
115 // Counter macros allow recording a named value (which must be a 32-bit integer).
116 // The value will be graphed in the viewer.
117 for (int i = 0; i < 180; ++i) {
118 SkScalar rad = SkDegreesToRadians(SkIntToScalar(i));
119 TRACE_COUNTER1("skia", "sin", SkScalarSin(rad) * 1000.0f + 1000.0f);
120 do_work(10);
121 }
122 }
123
124 {
125 TRACE_EVENT0("skia", "Independent Counters");
126
127 // Recording multiple counters with separate COUNTER1 macros will make separate graphs.
128 for (int i = 0; i < 180; ++i) {
129 SkScalar rad = SkDegreesToRadians(SkIntToScalar(i));
130 TRACE_COUNTER1("skia", "sin", SkScalarSin(rad) * 1000.0f + 1000.0f);
131 TRACE_COUNTER1("skia", "cos", SkScalarCos(rad) * 1000.0f + 1000.0f);
132 do_work(10);
133 }
134 }
135
136 {
137 TRACE_EVENT0("skia", "Stacked Counters");
138
139 // Two counters can be recorded together with COUNTER2. They will be graphed together,
140 // as a stacked bar graph. The combined graph needs a name, as does each data series.
141 for (int i = 0; i < 180; ++i) {
142 SkScalar rad = SkDegreesToRadians(SkIntToScalar(i));
143 TRACE_COUNTER2("skia", "trig",
144 "sin", SkScalarSin(rad) * 1000.0f + 1000.0f,
145 "cos", SkScalarCos(rad) * 1000.0f + 1000.0f);
146 do_work(10);
147 }
148 }
149 }
150
test_trace_objects()151 static void test_trace_objects() {
152 TRACE_EVENT0("skia", TRACE_FUNC);
153
154 // Objects can be tracked through time with the TRACE_EVENT_OBJECT_ macros.
155 // The macros in use (and their idiosyncracies) are commented in the TracingShape class above.
156
157 TracingCircle* circle = new TracingCircle(SkPoint::Make(20, 20), 15);
158 circle->traceSnapshot();
159 do_work(100);
160
161 // Make another object. Objects with the same base type are shown in the same row in the viewer.
162 TracingRect* rect = new TracingRect(SkRect::MakeWH(100, 50));
163 rect->traceSnapshot();
164 do_work(100);
165
166 // We can create multiple snapshots of objects to reflect their state over time.
167 circle->fCenter.offset(10, 10);
168 circle->traceSnapshot();
169
170 {
171 // Other events (duration or instant) can refer directly to objects. For Skia's JSON
172 // tracer, having an argument whose name starts with '#' will trigger the creation of JSON
173 // that links the event to the object (with a direct link to the most recent snapshot).
174 TRACE_EVENT1("skia", "Processing Shape", "#shape", circle);
175 do_work(100);
176 }
177
178 delete circle;
179 delete rect;
180 }
181
DEF_TEST(Tracing,reporter)182 DEF_TEST(Tracing, reporter) {
183 test_trace_simple();
184 test_trace_counters();
185 test_trace_objects();
186 }
187