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