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