1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2021 Google, Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
5bf215546Sopenharmony_ci */
6bf215546Sopenharmony_ci
7bf215546Sopenharmony_ci#include "fd_pps_driver.h"
8bf215546Sopenharmony_ci
9bf215546Sopenharmony_ci#include <cstring>
10bf215546Sopenharmony_ci#include <iostream>
11bf215546Sopenharmony_ci#include <perfetto.h>
12bf215546Sopenharmony_ci
13bf215546Sopenharmony_ci#include "pps/pps.h"
14bf215546Sopenharmony_ci#include "pps/pps_algorithm.h"
15bf215546Sopenharmony_ci
16bf215546Sopenharmony_cinamespace pps
17bf215546Sopenharmony_ci{
18bf215546Sopenharmony_ci
19bf215546Sopenharmony_cidouble
20bf215546Sopenharmony_cisafe_div(uint64_t a, uint64_t b)
21bf215546Sopenharmony_ci{
22bf215546Sopenharmony_ci   if (b == 0)
23bf215546Sopenharmony_ci      return 0;
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci   return a / static_cast<double>(b);
26bf215546Sopenharmony_ci}
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_cifloat
29bf215546Sopenharmony_cipercent(uint64_t a, uint64_t b)
30bf215546Sopenharmony_ci{
31bf215546Sopenharmony_ci   /* Sometimes we get bogus values but we want for the timeline
32bf215546Sopenharmony_ci    * to look nice without higher than 100% values.
33bf215546Sopenharmony_ci    */
34bf215546Sopenharmony_ci   if (b == 0 || a > b)
35bf215546Sopenharmony_ci      return 0;
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci   return 100.f * (a / static_cast<double>(b));
38bf215546Sopenharmony_ci}
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ciuint64_t
41bf215546Sopenharmony_ciFreedrenoDriver::get_min_sampling_period_ns()
42bf215546Sopenharmony_ci{
43bf215546Sopenharmony_ci   return 100000;
44bf215546Sopenharmony_ci}
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/*
47bf215546Sopenharmony_ciTODO this sees like it would be largely the same for a5xx as well
48bf215546Sopenharmony_ci(ie. same countable names)..
49bf215546Sopenharmony_ci */
50bf215546Sopenharmony_civoid
51bf215546Sopenharmony_ciFreedrenoDriver::setup_a6xx_counters()
52bf215546Sopenharmony_ci{
53bf215546Sopenharmony_ci   /* TODO is there a reason to want more than one group? */
54bf215546Sopenharmony_ci   CounterGroup group = {};
55bf215546Sopenharmony_ci   group.name = "counters";
56bf215546Sopenharmony_ci   groups.clear();
57bf215546Sopenharmony_ci   counters.clear();
58bf215546Sopenharmony_ci   countables.clear();
59bf215546Sopenharmony_ci   enabled_counters.clear();
60bf215546Sopenharmony_ci   groups.emplace_back(std::move(group));
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   /*
63bf215546Sopenharmony_ci    * Create the countables that we'll be using.
64bf215546Sopenharmony_ci    */
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   auto PERF_CP_ALWAYS_COUNT = countable("PERF_CP_ALWAYS_COUNT");
67bf215546Sopenharmony_ci   auto PERF_CP_BUSY_CYCLES  = countable("PERF_CP_BUSY_CYCLES");
68bf215546Sopenharmony_ci   auto PERF_RB_3D_PIXELS    = countable("PERF_RB_3D_PIXELS");
69bf215546Sopenharmony_ci   auto PERF_TP_L1_CACHELINE_MISSES = countable("PERF_TP_L1_CACHELINE_MISSES");
70bf215546Sopenharmony_ci   auto PERF_TP_L1_CACHELINE_REQUESTS = countable("PERF_TP_L1_CACHELINE_REQUESTS");
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   auto PERF_TP_OUTPUT_PIXELS  = countable("PERF_TP_OUTPUT_PIXELS");
73bf215546Sopenharmony_ci   auto PERF_TP_OUTPUT_PIXELS_ANISO  = countable("PERF_TP_OUTPUT_PIXELS_ANISO");
74bf215546Sopenharmony_ci   auto PERF_TP_OUTPUT_PIXELS_BILINEAR = countable("PERF_TP_OUTPUT_PIXELS_BILINEAR");
75bf215546Sopenharmony_ci   auto PERF_TP_OUTPUT_PIXELS_POINT = countable("PERF_TP_OUTPUT_PIXELS_POINT");
76bf215546Sopenharmony_ci   auto PERF_TP_OUTPUT_PIXELS_ZERO_LOD = countable("PERF_TP_OUTPUT_PIXELS_ZERO_LOD");
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   auto PERF_TSE_INPUT_PRIM  = countable("PERF_TSE_INPUT_PRIM");
79bf215546Sopenharmony_ci   auto PERF_TSE_CLIPPED_PRIM  = countable("PERF_TSE_CLIPPED_PRIM");
80bf215546Sopenharmony_ci   auto PERF_TSE_TRIVAL_REJ_PRIM  = countable("PERF_TSE_TRIVAL_REJ_PRIM");
81bf215546Sopenharmony_ci   auto PERF_TSE_OUTPUT_VISIBLE_PRIM = countable("PERF_TSE_OUTPUT_VISIBLE_PRIM");
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci   auto PERF_SP_BUSY_CYCLES  = countable("PERF_SP_BUSY_CYCLES");
84bf215546Sopenharmony_ci   auto PERF_SP_ALU_WORKING_CYCLES = countable("PERF_SP_ALU_WORKING_CYCLES");
85bf215546Sopenharmony_ci   auto PERF_SP_EFU_WORKING_CYCLES = countable("PERF_SP_EFU_WORKING_CYCLES");
86bf215546Sopenharmony_ci   auto PERF_SP_VS_STAGE_EFU_INSTRUCTIONS = countable("PERF_SP_VS_STAGE_EFU_INSTRUCTIONS");
87bf215546Sopenharmony_ci   auto PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS = countable("PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS");
88bf215546Sopenharmony_ci   auto PERF_SP_VS_STAGE_TEX_INSTRUCTIONS = countable("PERF_SP_VS_STAGE_TEX_INSTRUCTIONS");
89bf215546Sopenharmony_ci   auto PERF_SP_FS_STAGE_EFU_INSTRUCTIONS = countable("PERF_SP_FS_STAGE_EFU_INSTRUCTIONS");
90bf215546Sopenharmony_ci   auto PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS = countable("PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS");
91bf215546Sopenharmony_ci   auto PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS = countable("PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS");
92bf215546Sopenharmony_ci   auto PERF_SP_STALL_CYCLES_TP = countable("PERF_SP_STALL_CYCLES_TP");
93bf215546Sopenharmony_ci   auto PERF_SP_ANY_EU_WORKING_FS_STAGE = countable("PERF_SP_ANY_EU_WORKING_FS_STAGE");
94bf215546Sopenharmony_ci   auto PERF_SP_ANY_EU_WORKING_VS_STAGE = countable("PERF_SP_ANY_EU_WORKING_VS_STAGE");
95bf215546Sopenharmony_ci   auto PERF_SP_ANY_EU_WORKING_CS_STAGE = countable("PERF_SP_ANY_EU_WORKING_CS_STAGE");
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   auto PERF_UCHE_STALL_CYCLES_ARBITER = countable("PERF_UCHE_STALL_CYCLES_ARBITER");
98bf215546Sopenharmony_ci   auto PERF_UCHE_VBIF_READ_BEATS_TP = countable("PERF_UCHE_VBIF_READ_BEATS_TP");
99bf215546Sopenharmony_ci   auto PERF_UCHE_VBIF_READ_BEATS_VFD = countable("PERF_UCHE_VBIF_READ_BEATS_VFD");
100bf215546Sopenharmony_ci   auto PERF_UCHE_VBIF_READ_BEATS_SP = countable("PERF_UCHE_VBIF_READ_BEATS_SP");
101bf215546Sopenharmony_ci   auto PERF_UCHE_READ_REQUESTS_TP = countable("PERF_UCHE_READ_REQUESTS_TP");
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   auto PERF_PC_STALL_CYCLES_VFD = countable("PERF_PC_STALL_CYCLES_VFD");
104bf215546Sopenharmony_ci   auto PERF_PC_VS_INVOCATIONS = countable("PERF_PC_VS_INVOCATIONS");
105bf215546Sopenharmony_ci   auto PERF_PC_VERTEX_HITS = countable("PERF_PC_VERTEX_HITS");
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   auto PERF_HLSQ_QUADS = countable("PERF_HLSQ_QUADS"); /* Quads (fragments / 4) produced */
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   auto PERF_CP_NUM_PREEMPTIONS = countable("PERF_CP_NUM_PREEMPTIONS");
110bf215546Sopenharmony_ci   auto PERF_CP_PREEMPTION_REACTION_DELAY = countable("PERF_CP_PREEMPTION_REACTION_DELAY");
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   /* TODO: resolve() tells there is no PERF_CMPDECMP_VBIF_READ_DATA */
113bf215546Sopenharmony_ci   // auto PERF_CMPDECMP_VBIF_READ_DATA = countable("PERF_CMPDECMP_VBIF_READ_DATA");
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   /*
116bf215546Sopenharmony_ci    * And then setup the derived counters that we are exporting to
117bf215546Sopenharmony_ci    * pps based on the captured countable values.
118bf215546Sopenharmony_ci    *
119bf215546Sopenharmony_ci    * We try to expose the same counters as blob:
120bf215546Sopenharmony_ci    * https://gpuinspector.dev/docs/gpu-counters/qualcomm
121bf215546Sopenharmony_ci    */
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   counter("GPU Frequency", Counter::Units::Hertz, [=]() {
124bf215546Sopenharmony_ci         return PERF_CP_ALWAYS_COUNT / time;
125bf215546Sopenharmony_ci      }
126bf215546Sopenharmony_ci   );
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   counter("GPU % Utilization", Counter::Units::Percent, [=]() {
129bf215546Sopenharmony_ci         return percent(PERF_CP_BUSY_CYCLES / time, max_freq);
130bf215546Sopenharmony_ci      }
131bf215546Sopenharmony_ci   );
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   counter("TP L1 Cache Misses", Counter::Units::None, [=]() {
134bf215546Sopenharmony_ci         return PERF_TP_L1_CACHELINE_MISSES / time;
135bf215546Sopenharmony_ci      }
136bf215546Sopenharmony_ci   );
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   counter("Shader Core Utilization", Counter::Units::Percent, [=]() {
139bf215546Sopenharmony_ci         return percent(PERF_SP_BUSY_CYCLES / time, max_freq * info->num_sp_cores);
140bf215546Sopenharmony_ci      }
141bf215546Sopenharmony_ci   );
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   /* TODO: verify */
144bf215546Sopenharmony_ci   counter("(?) % Texture Fetch Stall", Counter::Units::Percent, [=]() {
145bf215546Sopenharmony_ci         return percent(PERF_SP_STALL_CYCLES_TP / time, max_freq * info->num_sp_cores);
146bf215546Sopenharmony_ci      }
147bf215546Sopenharmony_ci   );
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   /* TODO: verify */
150bf215546Sopenharmony_ci   counter("(?) % Vertex Fetch Stall", Counter::Units::Percent, [=]() {
151bf215546Sopenharmony_ci         return percent(PERF_PC_STALL_CYCLES_VFD / time, max_freq * info->num_sp_cores);
152bf215546Sopenharmony_ci      }
153bf215546Sopenharmony_ci   );
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   counter("L1 Texture Cache Miss Per Pixel", Counter::Units::None, [=]() {
156bf215546Sopenharmony_ci         return safe_div(PERF_TP_L1_CACHELINE_MISSES, PERF_HLSQ_QUADS * 4);
157bf215546Sopenharmony_ci      }
158bf215546Sopenharmony_ci   );
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   counter("% Texture L1 Miss", Counter::Units::Percent, [=]() {
161bf215546Sopenharmony_ci         return percent(PERF_TP_L1_CACHELINE_MISSES, PERF_TP_L1_CACHELINE_REQUESTS);
162bf215546Sopenharmony_ci      }
163bf215546Sopenharmony_ci   );
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   counter("% Texture L2 Miss", Counter::Units::Percent, [=]() {
166bf215546Sopenharmony_ci         return percent(PERF_UCHE_VBIF_READ_BEATS_TP / 2, PERF_UCHE_READ_REQUESTS_TP);
167bf215546Sopenharmony_ci      }
168bf215546Sopenharmony_ci   );
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   /* TODO: verify */
171bf215546Sopenharmony_ci   counter("(?) % Stalled on System Memory", Counter::Units::Percent, [=]() {
172bf215546Sopenharmony_ci         return percent(PERF_UCHE_STALL_CYCLES_ARBITER / time, max_freq * info->num_sp_cores);
173bf215546Sopenharmony_ci      }
174bf215546Sopenharmony_ci   );
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   counter("Pre-clipped Polygons / Second", Counter::Units::None, [=]() {
177bf215546Sopenharmony_ci         return PERF_TSE_INPUT_PRIM * (1.f / time);
178bf215546Sopenharmony_ci      }
179bf215546Sopenharmony_ci   );
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   counter("% Prims Trivially Rejected", Counter::Units::Percent, [=]() {
182bf215546Sopenharmony_ci         return percent(PERF_TSE_TRIVAL_REJ_PRIM, PERF_TSE_INPUT_PRIM);
183bf215546Sopenharmony_ci      }
184bf215546Sopenharmony_ci   );
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   counter("% Prims Clipped", Counter::Units::Percent, [=]() {
187bf215546Sopenharmony_ci         return percent(PERF_TSE_CLIPPED_PRIM, PERF_TSE_INPUT_PRIM);
188bf215546Sopenharmony_ci      }
189bf215546Sopenharmony_ci   );
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   counter("Average Vertices / Polygon", Counter::Units::None, [=]() {
192bf215546Sopenharmony_ci         return PERF_PC_VS_INVOCATIONS / PERF_TSE_INPUT_PRIM;
193bf215546Sopenharmony_ci      }
194bf215546Sopenharmony_ci   );
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   counter("Reused Vertices / Second", Counter::Units::None, [=]() {
197bf215546Sopenharmony_ci         return PERF_PC_VERTEX_HITS * (1.f / time);
198bf215546Sopenharmony_ci      }
199bf215546Sopenharmony_ci   );
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   counter("Average Polygon Area", Counter::Units::None, [=]() {
202bf215546Sopenharmony_ci         return safe_div(PERF_HLSQ_QUADS * 4, PERF_TSE_OUTPUT_VISIBLE_PRIM);
203bf215546Sopenharmony_ci      }
204bf215546Sopenharmony_ci   );
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   /* TODO: find formula */
207bf215546Sopenharmony_ci   // counter("% Shaders Busy", Counter::Units::Percent, [=]() {
208bf215546Sopenharmony_ci   //       return 100.0 * 0;
209bf215546Sopenharmony_ci   //    }
210bf215546Sopenharmony_ci   // );
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   counter("Vertices Shaded / Second", Counter::Units::None, [=]() {
213bf215546Sopenharmony_ci         return PERF_PC_VS_INVOCATIONS * (1.f / time);
214bf215546Sopenharmony_ci      }
215bf215546Sopenharmony_ci   );
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   counter("Fragments Shaded / Second", Counter::Units::None, [=]() {
218bf215546Sopenharmony_ci         return PERF_HLSQ_QUADS * 4 * (1.f / time);
219bf215546Sopenharmony_ci      }
220bf215546Sopenharmony_ci   );
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   counter("Vertex Instructions / Second", Counter::Units::None, [=]() {
223bf215546Sopenharmony_ci         return (PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS +
224bf215546Sopenharmony_ci                 PERF_SP_VS_STAGE_EFU_INSTRUCTIONS) * (1.f / time);
225bf215546Sopenharmony_ci      }
226bf215546Sopenharmony_ci   );
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   counter("Fragment Instructions / Second", Counter::Units::None, [=]() {
229bf215546Sopenharmony_ci         return (PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS +
230bf215546Sopenharmony_ci                 PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2 +
231bf215546Sopenharmony_ci                 PERF_SP_FS_STAGE_EFU_INSTRUCTIONS) * (1.f / time);
232bf215546Sopenharmony_ci      }
233bf215546Sopenharmony_ci   );
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   counter("Fragment ALU Instructions / Sec (Full)", Counter::Units::None, [=]() {
236bf215546Sopenharmony_ci         return PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS * (1.f / time);
237bf215546Sopenharmony_ci      }
238bf215546Sopenharmony_ci   );
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   counter("Fragment ALU Instructions / Sec (Half)", Counter::Units::None, [=]() {
241bf215546Sopenharmony_ci         return PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS * (1.f / time);
242bf215546Sopenharmony_ci      }
243bf215546Sopenharmony_ci   );
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   counter("Fragment EFU Instructions / Second", Counter::Units::None, [=]() {
246bf215546Sopenharmony_ci         return PERF_SP_FS_STAGE_EFU_INSTRUCTIONS * (1.f / time);
247bf215546Sopenharmony_ci      }
248bf215546Sopenharmony_ci   );
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   counter("Textures / Vertex", Counter::Units::None, [=]() {
251bf215546Sopenharmony_ci         return safe_div(PERF_SP_VS_STAGE_TEX_INSTRUCTIONS, PERF_PC_VS_INVOCATIONS);
252bf215546Sopenharmony_ci      }
253bf215546Sopenharmony_ci   );
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   counter("Textures / Fragment", Counter::Units::None, [=]() {
256bf215546Sopenharmony_ci         return safe_div(PERF_TP_OUTPUT_PIXELS, PERF_HLSQ_QUADS * 4);
257bf215546Sopenharmony_ci      }
258bf215546Sopenharmony_ci   );
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   counter("ALU / Vertex", Counter::Units::None, [=]() {
261bf215546Sopenharmony_ci         return safe_div(PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS, PERF_PC_VS_INVOCATIONS);
262bf215546Sopenharmony_ci      }
263bf215546Sopenharmony_ci   );
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   counter("EFU / Vertex", Counter::Units::None, [=]() {
266bf215546Sopenharmony_ci         return safe_div(PERF_SP_VS_STAGE_EFU_INSTRUCTIONS, PERF_PC_VS_INVOCATIONS);
267bf215546Sopenharmony_ci      }
268bf215546Sopenharmony_ci   );
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   counter("ALU / Fragment", Counter::Units::None, [=]() {
271bf215546Sopenharmony_ci         return safe_div(PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS +
272bf215546Sopenharmony_ci                         PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2, PERF_HLSQ_QUADS);
273bf215546Sopenharmony_ci      }
274bf215546Sopenharmony_ci   );
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   counter("EFU / Fragment", Counter::Units::None, [=]() {
277bf215546Sopenharmony_ci         return safe_div(PERF_SP_FS_STAGE_EFU_INSTRUCTIONS, PERF_HLSQ_QUADS);
278bf215546Sopenharmony_ci      }
279bf215546Sopenharmony_ci   );
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   counter("% Time Shading Vertices", Counter::Units::Percent, [=]() {
282bf215546Sopenharmony_ci         return percent(PERF_SP_ANY_EU_WORKING_VS_STAGE,
283bf215546Sopenharmony_ci                        (PERF_SP_ANY_EU_WORKING_VS_STAGE +
284bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_FS_STAGE +
285bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_CS_STAGE));
286bf215546Sopenharmony_ci      }
287bf215546Sopenharmony_ci   );
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   counter("% Time Shading Fragments", Counter::Units::Percent, [=]() {
290bf215546Sopenharmony_ci         return percent(PERF_SP_ANY_EU_WORKING_FS_STAGE,
291bf215546Sopenharmony_ci                        (PERF_SP_ANY_EU_WORKING_VS_STAGE +
292bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_FS_STAGE +
293bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_CS_STAGE));
294bf215546Sopenharmony_ci      }
295bf215546Sopenharmony_ci   );
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   counter("% Time Compute", Counter::Units::Percent, [=]() {
298bf215546Sopenharmony_ci         return percent(PERF_SP_ANY_EU_WORKING_CS_STAGE,
299bf215546Sopenharmony_ci                        (PERF_SP_ANY_EU_WORKING_VS_STAGE +
300bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_FS_STAGE +
301bf215546Sopenharmony_ci                         PERF_SP_ANY_EU_WORKING_CS_STAGE));
302bf215546Sopenharmony_ci      }
303bf215546Sopenharmony_ci   );
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   counter("% Shader ALU Capacity Utilized", Counter::Units::Percent, [=]() {
306bf215546Sopenharmony_ci         return percent((PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS +
307bf215546Sopenharmony_ci                         PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS +
308bf215546Sopenharmony_ci                         PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2) / 64,
309bf215546Sopenharmony_ci                        PERF_SP_BUSY_CYCLES);
310bf215546Sopenharmony_ci      }
311bf215546Sopenharmony_ci   );
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   counter("% Time ALUs Working", Counter::Units::Percent, [=]() {
314bf215546Sopenharmony_ci         return percent(PERF_SP_ALU_WORKING_CYCLES / 2, PERF_SP_BUSY_CYCLES);
315bf215546Sopenharmony_ci      }
316bf215546Sopenharmony_ci   );
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   counter("% Time EFUs Working", Counter::Units::Percent, [=]() {
319bf215546Sopenharmony_ci         return percent(PERF_SP_EFU_WORKING_CYCLES / 2, PERF_SP_BUSY_CYCLES);
320bf215546Sopenharmony_ci      }
321bf215546Sopenharmony_ci   );
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci   counter("% Anisotropic Filtered", Counter::Units::Percent, [=]() {
324bf215546Sopenharmony_ci         return percent(PERF_TP_OUTPUT_PIXELS_ANISO, PERF_TP_OUTPUT_PIXELS);
325bf215546Sopenharmony_ci      }
326bf215546Sopenharmony_ci   );
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   counter("% Linear Filtered", Counter::Units::Percent, [=]() {
329bf215546Sopenharmony_ci         return percent(PERF_TP_OUTPUT_PIXELS_BILINEAR, PERF_TP_OUTPUT_PIXELS);
330bf215546Sopenharmony_ci      }
331bf215546Sopenharmony_ci   );
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci   counter("% Nearest Filtered", Counter::Units::Percent, [=]() {
334bf215546Sopenharmony_ci         return percent(PERF_TP_OUTPUT_PIXELS_POINT, PERF_TP_OUTPUT_PIXELS);
335bf215546Sopenharmony_ci      }
336bf215546Sopenharmony_ci   );
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   counter("% Non-Base Level Textures", Counter::Units::Percent, [=]() {
339bf215546Sopenharmony_ci         return percent(PERF_TP_OUTPUT_PIXELS_ZERO_LOD, PERF_TP_OUTPUT_PIXELS);
340bf215546Sopenharmony_ci      }
341bf215546Sopenharmony_ci   );
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   /* Reads from KGSL_PERFCOUNTER_GROUP_VBIF countable=63 */
344bf215546Sopenharmony_ci   // counter("Read Total (Bytes/sec)", Counter::Units::Byte, [=]() {
345bf215546Sopenharmony_ci   //       return  * (1.f / time);
346bf215546Sopenharmony_ci   //    }
347bf215546Sopenharmony_ci   // );
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   /* Reads from KGSL_PERFCOUNTER_GROUP_VBIF countable=84 */
350bf215546Sopenharmony_ci   // counter("Write Total (Bytes/sec)", Counter::Units::Byte, [=]() {
351bf215546Sopenharmony_ci   //       return  * (1.f / time);
352bf215546Sopenharmony_ci   //    }
353bf215546Sopenharmony_ci   // );
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   /* Cannot get PERF_CMPDECMP_VBIF_READ_DATA countable */
356bf215546Sopenharmony_ci   // counter("Texture Memory Read BW (Bytes/Second)", Counter::Units::Byte, [=]() {
357bf215546Sopenharmony_ci   //       return (PERF_CMPDECMP_VBIF_READ_DATA + PERF_UCHE_VBIF_READ_BEATS_TP) * (1.f / time);
358bf215546Sopenharmony_ci   //    }
359bf215546Sopenharmony_ci   // );
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci   /* TODO: verify */
362bf215546Sopenharmony_ci   counter("(?) Vertex Memory Read (Bytes/Second)", Counter::Units::Byte, [=]() {
363bf215546Sopenharmony_ci         return PERF_UCHE_VBIF_READ_BEATS_VFD * 32 * (1.f / time);
364bf215546Sopenharmony_ci      }
365bf215546Sopenharmony_ci   );
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   /* TODO: verify */
368bf215546Sopenharmony_ci   counter("SP Memory Read (Bytes/Second)", Counter::Units::Byte, [=]() {
369bf215546Sopenharmony_ci         return PERF_UCHE_VBIF_READ_BEATS_SP * 32 * (1.f / time);
370bf215546Sopenharmony_ci      }
371bf215546Sopenharmony_ci   );
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   counter("Avg Bytes / Fragment", Counter::Units::Byte, [=]() {
374bf215546Sopenharmony_ci         return safe_div(PERF_UCHE_VBIF_READ_BEATS_TP * 32, PERF_HLSQ_QUADS * 4);
375bf215546Sopenharmony_ci      }
376bf215546Sopenharmony_ci   );
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci   counter("Avg Bytes / Vertex", Counter::Units::Byte, [=]() {
379bf215546Sopenharmony_ci         return safe_div(PERF_UCHE_VBIF_READ_BEATS_VFD * 32, PERF_PC_VS_INVOCATIONS);
380bf215546Sopenharmony_ci      }
381bf215546Sopenharmony_ci   );
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   counter("Preemptions / second", Counter::Units::None, [=]() {
384bf215546Sopenharmony_ci         return PERF_CP_NUM_PREEMPTIONS * (1.f / time);
385bf215546Sopenharmony_ci      }
386bf215546Sopenharmony_ci   );
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   counter("Avg Preemption Delay", Counter::Units::None, [=]() {
389bf215546Sopenharmony_ci         return PERF_CP_PREEMPTION_REACTION_DELAY * (1.f / time);
390bf215546Sopenharmony_ci      }
391bf215546Sopenharmony_ci   );
392bf215546Sopenharmony_ci}
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci/**
395bf215546Sopenharmony_ci * Generate an submit the cmdstream to configure the counter/countable
396bf215546Sopenharmony_ci * muxing
397bf215546Sopenharmony_ci */
398bf215546Sopenharmony_civoid
399bf215546Sopenharmony_ciFreedrenoDriver::configure_counters(bool reset, bool wait)
400bf215546Sopenharmony_ci{
401bf215546Sopenharmony_ci   struct fd_submit *submit = fd_submit_new(pipe);
402bf215546Sopenharmony_ci   enum fd_ringbuffer_flags flags =
403bf215546Sopenharmony_ci      (enum fd_ringbuffer_flags)(FD_RINGBUFFER_PRIMARY | FD_RINGBUFFER_GROWABLE);
404bf215546Sopenharmony_ci   struct fd_ringbuffer *ring = fd_submit_new_ringbuffer(submit, 0x1000, flags);
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci   for (auto countable : countables)
407bf215546Sopenharmony_ci      countable.configure(ring, reset);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   struct fd_submit_fence fence = {};
410bf215546Sopenharmony_ci   util_queue_fence_init(&fence.ready);
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   fd_submit_flush(submit, -1, &fence);
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   util_queue_fence_wait(&fence.ready);
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   fd_ringbuffer_del(ring);
417bf215546Sopenharmony_ci   fd_submit_del(submit);
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   if (wait)
420bf215546Sopenharmony_ci      fd_pipe_wait(pipe, &fence.fence);
421bf215546Sopenharmony_ci}
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci/**
424bf215546Sopenharmony_ci * Read the current counter values and record the time.
425bf215546Sopenharmony_ci */
426bf215546Sopenharmony_civoid
427bf215546Sopenharmony_ciFreedrenoDriver::collect_countables()
428bf215546Sopenharmony_ci{
429bf215546Sopenharmony_ci   last_dump_ts = perfetto::base::GetBootTimeNs().count();
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci   for (auto countable : countables)
432bf215546Sopenharmony_ci      countable.collect();
433bf215546Sopenharmony_ci}
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_cibool
436bf215546Sopenharmony_ciFreedrenoDriver::init_perfcnt()
437bf215546Sopenharmony_ci{
438bf215546Sopenharmony_ci   uint64_t val;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   dev = fd_device_new(drm_device.fd);
441bf215546Sopenharmony_ci   pipe = fd_pipe_new(dev, FD_PIPE_3D);
442bf215546Sopenharmony_ci   dev_id = fd_pipe_dev_id(pipe);
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   if (fd_pipe_get_param(pipe, FD_MAX_FREQ, &val)) {
445bf215546Sopenharmony_ci      PERFETTO_FATAL("Could not get MAX_FREQ");
446bf215546Sopenharmony_ci      return false;
447bf215546Sopenharmony_ci   }
448bf215546Sopenharmony_ci   max_freq = val;
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci   if (fd_pipe_get_param(pipe, FD_SUSPEND_COUNT, &val)) {
451bf215546Sopenharmony_ci      PERFETTO_ILOG("Could not get SUSPEND_COUNT");
452bf215546Sopenharmony_ci   } else {
453bf215546Sopenharmony_ci      suspend_count = val;
454bf215546Sopenharmony_ci      has_suspend_count = true;
455bf215546Sopenharmony_ci   }
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci   fd_pipe_set_param(pipe, FD_SYSPROF, 1);
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   perfcntrs = fd_perfcntrs(fd_pipe_dev_id(pipe), &num_perfcntrs);
460bf215546Sopenharmony_ci   if (num_perfcntrs == 0) {
461bf215546Sopenharmony_ci      PERFETTO_FATAL("No hw counters available");
462bf215546Sopenharmony_ci      return false;
463bf215546Sopenharmony_ci   }
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   assigned_counters.resize(num_perfcntrs);
466bf215546Sopenharmony_ci   assigned_counters.assign(assigned_counters.size(), 0);
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   switch (fd_dev_gen(dev_id)) {
469bf215546Sopenharmony_ci   case 6:
470bf215546Sopenharmony_ci      setup_a6xx_counters();
471bf215546Sopenharmony_ci      break;
472bf215546Sopenharmony_ci   default:
473bf215546Sopenharmony_ci      PERFETTO_FATAL("Unsupported GPU: a%03u", fd_dev_gpu_id(dev_id));
474bf215546Sopenharmony_ci      return false;
475bf215546Sopenharmony_ci   }
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   state.resize(next_countable_id);
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   for (auto countable : countables)
480bf215546Sopenharmony_ci      countable.resolve();
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   info = fd_dev_info(dev_id);
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   io = fd_dt_find_io();
485bf215546Sopenharmony_ci   if (!io) {
486bf215546Sopenharmony_ci      PERFETTO_FATAL("Could not map GPU I/O space");
487bf215546Sopenharmony_ci      return false;
488bf215546Sopenharmony_ci   }
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   configure_counters(true, true);
491bf215546Sopenharmony_ci   collect_countables();
492bf215546Sopenharmony_ci
493bf215546Sopenharmony_ci   return true;
494bf215546Sopenharmony_ci}
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_civoid
497bf215546Sopenharmony_ciFreedrenoDriver::enable_counter(const uint32_t counter_id)
498bf215546Sopenharmony_ci{
499bf215546Sopenharmony_ci   enabled_counters.push_back(counters[counter_id]);
500bf215546Sopenharmony_ci}
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_civoid
503bf215546Sopenharmony_ciFreedrenoDriver::enable_all_counters()
504bf215546Sopenharmony_ci{
505bf215546Sopenharmony_ci   enabled_counters.reserve(counters.size());
506bf215546Sopenharmony_ci   for (auto &counter : counters) {
507bf215546Sopenharmony_ci      enabled_counters.push_back(counter);
508bf215546Sopenharmony_ci   }
509bf215546Sopenharmony_ci}
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_civoid
512bf215546Sopenharmony_ciFreedrenoDriver::enable_perfcnt(const uint64_t /* sampling_period_ns */)
513bf215546Sopenharmony_ci{
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_cibool
517bf215546Sopenharmony_ciFreedrenoDriver::dump_perfcnt()
518bf215546Sopenharmony_ci{
519bf215546Sopenharmony_ci   if (has_suspend_count) {
520bf215546Sopenharmony_ci      uint64_t val;
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_ci      fd_pipe_get_param(pipe, FD_SUSPEND_COUNT, &val);
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci      if (suspend_count != val) {
525bf215546Sopenharmony_ci         PERFETTO_ILOG("Device had suspended!");
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci         suspend_count = val;
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci         configure_counters(true, true);
530bf215546Sopenharmony_ci         collect_countables();
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci         /* We aren't going to have anything sensible by comparing
533bf215546Sopenharmony_ci          * current values to values from prior to the suspend, so
534bf215546Sopenharmony_ci          * just skip this sampling period.
535bf215546Sopenharmony_ci          */
536bf215546Sopenharmony_ci         return false;
537bf215546Sopenharmony_ci      }
538bf215546Sopenharmony_ci   }
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci   auto last_ts = last_dump_ts;
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci   /* Capture the timestamp from the *start* of the sampling period: */
543bf215546Sopenharmony_ci   last_capture_ts = last_dump_ts;
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_ci   collect_countables();
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci   auto elapsed_time_ns = last_dump_ts - last_ts;
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   time = (float)elapsed_time_ns / 1000000000.0;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci   /* On older kernels that dont' support querying the suspend-
552bf215546Sopenharmony_ci    * count, just send configuration cmdstream regularly to keep
553bf215546Sopenharmony_ci    * the GPU alive and correctly configured for the countables
554bf215546Sopenharmony_ci    * we want
555bf215546Sopenharmony_ci    */
556bf215546Sopenharmony_ci   if (!has_suspend_count) {
557bf215546Sopenharmony_ci      configure_counters(false, false);
558bf215546Sopenharmony_ci   }
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci   return true;
561bf215546Sopenharmony_ci}
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_ciuint64_t FreedrenoDriver::next()
564bf215546Sopenharmony_ci{
565bf215546Sopenharmony_ci   auto ret = last_capture_ts;
566bf215546Sopenharmony_ci   last_capture_ts = 0;
567bf215546Sopenharmony_ci   return ret;
568bf215546Sopenharmony_ci}
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_civoid FreedrenoDriver::disable_perfcnt()
571bf215546Sopenharmony_ci{
572bf215546Sopenharmony_ci   /* There isn't really any disable, only reconfiguring which countables
573bf215546Sopenharmony_ci    * get muxed to which counters
574bf215546Sopenharmony_ci    */
575bf215546Sopenharmony_ci}
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_ci/*
578bf215546Sopenharmony_ci * Countable
579bf215546Sopenharmony_ci */
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ciFreedrenoDriver::Countable
582bf215546Sopenharmony_ciFreedrenoDriver::countable(std::string name)
583bf215546Sopenharmony_ci{
584bf215546Sopenharmony_ci   auto countable = Countable(this, name);
585bf215546Sopenharmony_ci   countables.emplace_back(countable);
586bf215546Sopenharmony_ci   return countable;
587bf215546Sopenharmony_ci}
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ciFreedrenoDriver::Countable::Countable(FreedrenoDriver *d, std::string name)
590bf215546Sopenharmony_ci   : id {d->next_countable_id++}, d {d}, name {name}
591bf215546Sopenharmony_ci{
592bf215546Sopenharmony_ci}
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci/* Emit register writes on ring to configure counter/countable muxing: */
595bf215546Sopenharmony_civoid
596bf215546Sopenharmony_ciFreedrenoDriver::Countable::configure(struct fd_ringbuffer *ring, bool reset)
597bf215546Sopenharmony_ci{
598bf215546Sopenharmony_ci   const struct fd_perfcntr_countable *countable = d->state[id].countable;
599bf215546Sopenharmony_ci   const struct fd_perfcntr_counter   *counter   = d->state[id].counter;
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci   OUT_PKT7(ring, CP_WAIT_FOR_IDLE, 0);
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci   if (counter->enable && reset) {
604bf215546Sopenharmony_ci      OUT_PKT4(ring, counter->enable, 1);
605bf215546Sopenharmony_ci      OUT_RING(ring, 0);
606bf215546Sopenharmony_ci   }
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   if (counter->clear && reset) {
609bf215546Sopenharmony_ci      OUT_PKT4(ring, counter->clear, 1);
610bf215546Sopenharmony_ci      OUT_RING(ring, 1);
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_ci      OUT_PKT4(ring, counter->clear, 1);
613bf215546Sopenharmony_ci      OUT_RING(ring, 0);
614bf215546Sopenharmony_ci   }
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci   OUT_PKT4(ring, counter->select_reg, 1);
617bf215546Sopenharmony_ci   OUT_RING(ring, countable->selector);
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   if (counter->enable && reset) {
620bf215546Sopenharmony_ci      OUT_PKT4(ring, counter->enable, 1);
621bf215546Sopenharmony_ci      OUT_RING(ring, 1);
622bf215546Sopenharmony_ci   }
623bf215546Sopenharmony_ci}
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci/* Collect current counter value and calculate delta since last sample: */
626bf215546Sopenharmony_civoid
627bf215546Sopenharmony_ciFreedrenoDriver::Countable::collect()
628bf215546Sopenharmony_ci{
629bf215546Sopenharmony_ci   const struct fd_perfcntr_counter *counter = d->state[id].counter;
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci   d->state[id].last_value = d->state[id].value;
632bf215546Sopenharmony_ci
633bf215546Sopenharmony_ci   uint32_t *reg_lo = (uint32_t *)d->io + counter->counter_reg_lo;
634bf215546Sopenharmony_ci   uint32_t *reg_hi = (uint32_t *)d->io + counter->counter_reg_hi;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   uint32_t lo = *reg_lo;
637bf215546Sopenharmony_ci   uint32_t hi = *reg_hi;
638bf215546Sopenharmony_ci
639bf215546Sopenharmony_ci   d->state[id].value = lo | ((uint64_t)hi << 32);
640bf215546Sopenharmony_ci}
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci/* Resolve the countable and assign next counter from it's group: */
643bf215546Sopenharmony_civoid
644bf215546Sopenharmony_ciFreedrenoDriver::Countable::resolve()
645bf215546Sopenharmony_ci{
646bf215546Sopenharmony_ci   for (unsigned i = 0; i < d->num_perfcntrs; i++) {
647bf215546Sopenharmony_ci      const struct fd_perfcntr_group *g = &d->perfcntrs[i];
648bf215546Sopenharmony_ci      for (unsigned j = 0; j < g->num_countables; j++) {
649bf215546Sopenharmony_ci         const struct fd_perfcntr_countable *c = &g->countables[j];
650bf215546Sopenharmony_ci         if (name == c->name) {
651bf215546Sopenharmony_ci            d->state[id].countable = c;
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci            /* Assign a counter from the same group: */
654bf215546Sopenharmony_ci            assert(d->assigned_counters[i] < g->num_counters);
655bf215546Sopenharmony_ci            d->state[id].counter = &g->counters[d->assigned_counters[i]++];
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci            std::cout << "Countable: " << name << ", group=" << g->name <<
658bf215546Sopenharmony_ci                  ", counter=" << d->assigned_counters[i] - 1 << "\n";
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci            return;
661bf215546Sopenharmony_ci         }
662bf215546Sopenharmony_ci      }
663bf215546Sopenharmony_ci   }
664bf215546Sopenharmony_ci   unreachable("no such countable!");
665bf215546Sopenharmony_ci}
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ciuint64_t
668bf215546Sopenharmony_ciFreedrenoDriver::Countable::get_value() const
669bf215546Sopenharmony_ci{
670bf215546Sopenharmony_ci   return d->state[id].value - d->state[id].last_value;
671bf215546Sopenharmony_ci}
672bf215546Sopenharmony_ci
673bf215546Sopenharmony_ci/*
674bf215546Sopenharmony_ci * DerivedCounter
675bf215546Sopenharmony_ci */
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ciFreedrenoDriver::DerivedCounter::DerivedCounter(FreedrenoDriver *d, std::string name,
678bf215546Sopenharmony_ci                                                Counter::Units units,
679bf215546Sopenharmony_ci                                                std::function<int64_t()> derive)
680bf215546Sopenharmony_ci   : Counter(d->next_counter_id++, name, 0)
681bf215546Sopenharmony_ci{
682bf215546Sopenharmony_ci   std::cout << "DerivedCounter: " << name << ", id=" << id << "\n";
683bf215546Sopenharmony_ci   this->units = units;
684bf215546Sopenharmony_ci   set_getter([=](const Counter &c, const Driver &d) {
685bf215546Sopenharmony_ci         return derive();
686bf215546Sopenharmony_ci      }
687bf215546Sopenharmony_ci   );
688bf215546Sopenharmony_ci}
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_ciFreedrenoDriver::DerivedCounter
691bf215546Sopenharmony_ciFreedrenoDriver::counter(std::string name, Counter::Units units,
692bf215546Sopenharmony_ci                         std::function<int64_t()> derive)
693bf215546Sopenharmony_ci{
694bf215546Sopenharmony_ci   auto counter = DerivedCounter(this, name, units, derive);
695bf215546Sopenharmony_ci   counters.emplace_back(counter);
696bf215546Sopenharmony_ci   return counter;
697bf215546Sopenharmony_ci}
698bf215546Sopenharmony_ci
699bf215546Sopenharmony_ciuint32_t
700bf215546Sopenharmony_ciFreedrenoDriver::gpu_clock_id() const
701bf215546Sopenharmony_ci{
702bf215546Sopenharmony_ci   return perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
703bf215546Sopenharmony_ci}
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ciuint64_t
706bf215546Sopenharmony_ciFreedrenoDriver::gpu_timestamp() const
707bf215546Sopenharmony_ci{
708bf215546Sopenharmony_ci   return perfetto::base::GetBootTimeNs().count();
709bf215546Sopenharmony_ci}
710bf215546Sopenharmony_ci
711bf215546Sopenharmony_ci} // namespace pps
712