etnaviv: support SE performance counters
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_query_pm.c
1 /*
2 * Copyright (c) 2017 Etnaviv Project
3 * Copyright (C) 2017 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Christian Gmeiner <christian.gmeiner@gmail.com>
26 */
27
28 #include "util/u_inlines.h"
29 #include "util/u_memory.h"
30
31 #include "etnaviv_context.h"
32 #include "etnaviv_query_pm.h"
33 #include "etnaviv_screen.h"
34
35 struct etna_perfmon_source
36 {
37 const char *domain;
38 const char *signal;
39 };
40
41 struct etna_perfmon_config
42 {
43 const char *name;
44 unsigned type;
45 const struct etna_perfmon_source *source;
46 };
47
48 static const struct etna_perfmon_config query_config[] = {
49 {
50 .name = "hi-total-cyles",
51 .type = ETNA_QUERY_HI_TOTAL_CYCLES,
52 .source = (const struct etna_perfmon_source[]) {
53 { "HI", "TOTAL_CYCLES" }
54 }
55 },
56 {
57 .name = "hi-idle-cyles",
58 .type = ETNA_QUERY_HI_IDLE_CYCLES,
59 .source = (const struct etna_perfmon_source[]) {
60 { "HI", "IDLE_CYCLES" }
61 }
62 },
63 {
64 .name = "hi-axi-cycles-read-request-stalled",
65 .type = ETNA_QUERY_HI_AXI_CYCLES_READ_REQUEST_STALLED,
66 .source = (const struct etna_perfmon_source[]) {
67 { "HI", "AXI_CYCLES_READ_REQUEST_STALLED" }
68 }
69 },
70 {
71 .name = "hi-axi-cycles-write-request-stalled",
72 .type = ETNA_QUERY_HI_AXI_CYCLES_WRITE_REQUEST_STALLED,
73 .source = (const struct etna_perfmon_source[]) {
74 { "HI", "AXI_CYCLES_WRITE_REQUEST_STALLED" }
75 }
76 },
77 {
78 .name = "hi-axi-cycles-write-data-stalled",
79 .type = ETNA_QUERY_HI_AXI_CYCLES_WRITE_DATA_STALLED,
80 .source = (const struct etna_perfmon_source[]) {
81 { "HI", "AXI_CYCLES_WRITE_DATA_STALLED" }
82 }
83 },
84 {
85 .name = "pe-pixel-count-killed-by-color-pipe",
86 .type = ETNA_QUERY_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE,
87 .source = (const struct etna_perfmon_source[]) {
88 { "PE", "PIXEL_COUNT_KILLED_BY_COLOR_PIPE" }
89 }
90 },
91 {
92 .name = "pe-pixel-count-killed-by-depth-pipe",
93 .type = ETNA_QUERY_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE,
94 .source = (const struct etna_perfmon_source[]) {
95 { "PE", "PIXEL_COUNT_KILLED_BY_DEPTH_PIPE" }
96 }
97 },
98 {
99 .name = "pe-pixel-count-drawn-by-color-pipe",
100 .type = ETNA_QUERY_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE,
101 .source = (const struct etna_perfmon_source[]) {
102 { "PE", "PIXEL_COUNT_DRAWN_BY_COLOR_PIPE" }
103 }
104 },
105 {
106 .name = "pe-pixel-count-drawn-by-depth-pipe",
107 .type = ETNA_QUERY_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE,
108 .source = (const struct etna_perfmon_source[]) {
109 { "PE", "PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE" }
110 }
111 },
112 {
113 .name = "sh-shader-cycles",
114 .type = ETNA_QUERY_SH_SHADER_CYCLES,
115 .source = (const struct etna_perfmon_source[]) {
116 { "SH", "SHADER_CYCLES" }
117 }
118 },
119 {
120 .name = "sh-ps-inst-counter",
121 .type = ETNA_QUERY_SH_PS_INST_COUNTER,
122 .source = (const struct etna_perfmon_source[]) {
123 { "SH", "PS_INST_COUNTER" }
124 }
125 },
126 {
127 .name = "sh-rendered-pixel-counter",
128 .type = ETNA_QUERY_SH_RENDERED_PIXEL_COUNTER,
129 .source = (const struct etna_perfmon_source[]) {
130 { "SH", "RENDERED_PIXEL_COUNTER" }
131 }
132 },
133 {
134 .name = "sh-vs-inst-counter",
135 .type = ETNA_QUERY_SH_VS_INST_COUNTER,
136 .source = (const struct etna_perfmon_source[]) {
137 { "SH", "VS_INST_COUNTER" }
138 }
139 },
140 {
141 .name = "sh-rendered-vertice-counter",
142 .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
143 .source = (const struct etna_perfmon_source[]) {
144 { "SH", "RENDERED_VERTICE_COUNTER" }
145 }
146 },
147 {
148 .name = "sh-vtx-branch-inst-counter",
149 .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
150 .source = (const struct etna_perfmon_source[]) {
151 { "SH", "VTX_BRANCH_INST_COUNTER" }
152 }
153 },
154 {
155 .name = "sh-vtx-texld-inst-counter",
156 .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
157 .source = (const struct etna_perfmon_source[]) {
158 { "SH", "VTX_TEXLD_INST_COUNTER" }
159 }
160 },
161 {
162 .name = "sh-plx-branch-inst-counter",
163 .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
164 .source = (const struct etna_perfmon_source[]) {
165 { "SH", "PXL_BRANCH_INST_COUNTER" }
166 }
167 },
168 {
169 .name = "sh-plx-texld-inst-counter",
170 .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
171 .source = (const struct etna_perfmon_source[]) {
172 { "SH", "PXL_TEXLD_INST_COUNTER" }
173 }
174 },
175 {
176 .name = "pa-input-vtx-counter",
177 .type = ETNA_QUERY_PA_INPUT_VTX_COUNTER,
178 .source = (const struct etna_perfmon_source[]) {
179 { "PA", "INPUT_VTX_COUNTER" }
180 }
181 },
182 {
183 .name = "pa-input-prim-counter",
184 .type = ETNA_QUERY_PA_INPUT_PRIM_COUNTER,
185 .source = (const struct etna_perfmon_source[]) {
186 { "PA", "INPUT_PRIM_COUNTER" }
187 }
188 },
189 {
190 .name = "pa-output-prim-counter",
191 .type = ETNA_QUERY_PA_OUTPUT_PRIM_COUNTER,
192 .source = (const struct etna_perfmon_source[]) {
193 { "PA", "OUTPUT_PRIM_COUNTER" }
194 }
195 },
196 {
197 .name = "pa-depth-clipped-counter",
198 .type = ETNA_QUERY_PA_DEPTH_CLIPPED_COUNTER,
199 .source = (const struct etna_perfmon_source[]) {
200 { "PA", "DEPTH_CLIPPED_COUNTER" }
201 }
202 },
203 {
204 .name = "pa-trivial-rejected-counter",
205 .type = ETNA_QUERY_PA_TRIVIAL_REJECTED_COUNTER,
206 .source = (const struct etna_perfmon_source[]) {
207 { "PA", "TRIVIAL_REJECTED_COUNTER" }
208 }
209 },
210 {
211 .name = "pa-culled-counter",
212 .type = ETNA_QUERY_PA_CULLED_COUNTER,
213 .source = (const struct etna_perfmon_source[]) {
214 { "PA", "CULLED_COUNTER" }
215 }
216 },
217 {
218 .name = "se-culled-triangle-count",
219 .type = ETNA_QUERY_SE_CULLED_TRIANGLE_COUNT,
220 .source = (const struct etna_perfmon_source[]) {
221 { "SE", "CULLED_TRIANGLE_COUNT" }
222 }
223 },
224 {
225 .name = "se-culled-lines-count",
226 .type = ETNA_QUERY_SE_CULLED_LINES_COUNT,
227 .source = (const struct etna_perfmon_source[]) {
228 { "SE", "CULLED_LINES_COUNT" }
229 }
230 }
231 };
232
233 static const struct etna_perfmon_config *
234 etna_pm_query_config(unsigned type)
235 {
236 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
237 if (query_config[i].type == type)
238 return &query_config[i];
239
240 return NULL;
241 }
242
243 static struct etna_perfmon_signal *
244 etna_pm_query_signal(struct etna_perfmon *perfmon,
245 const struct etna_perfmon_source *source)
246 {
247 struct etna_perfmon_domain *domain;
248
249 domain = etna_perfmon_get_dom_by_name(perfmon, source->domain);
250 if (!domain)
251 return NULL;
252
253 return etna_perfmon_get_sig_by_name(domain, source->signal);
254 }
255
256 static inline bool
257 etna_pm_cfg_supported(struct etna_perfmon *perfmon,
258 const struct etna_perfmon_config *cfg)
259 {
260 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
261
262 return !!signal;
263 }
264
265 static inline void
266 etna_pm_add_signal(struct etna_pm_query *pq, struct etna_perfmon *perfmon,
267 const struct etna_perfmon_config *cfg)
268 {
269 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
270
271 pq->signal = signal;
272 }
273
274 static bool
275 realloc_query_bo(struct etna_context *ctx, struct etna_pm_query *pq)
276 {
277 if (pq->bo)
278 etna_bo_del(pq->bo);
279
280 pq->bo = etna_bo_new(ctx->screen->dev, 64, DRM_ETNA_GEM_CACHE_WC);
281 if (unlikely(!pq->bo))
282 return false;
283
284 pq->data = etna_bo_map(pq->bo);
285
286 return true;
287 }
288
289 static void
290 etna_pm_query_get(struct etna_cmd_stream *stream, struct etna_query *q,
291 unsigned flags)
292 {
293 struct etna_pm_query *pq = etna_pm_query(q);
294 unsigned offset;
295 assert(flags);
296
297 if (flags == ETNA_PM_PROCESS_PRE)
298 offset = 2;
299 else
300 offset = 3;
301
302 struct etna_perf p = {
303 .flags = flags,
304 .sequence = pq->sequence,
305 .bo = pq->bo,
306 .signal = pq->signal,
307 .offset = offset
308 };
309
310 etna_cmd_stream_perf(stream, &p);
311 }
312
313 static inline void
314 etna_pm_query_update(struct etna_query *q)
315 {
316 struct etna_pm_query *pq = etna_pm_query(q);
317
318 if (pq->data[0] == pq->sequence)
319 pq->ready = true;
320 }
321
322 static void
323 etna_pm_destroy_query(struct etna_context *ctx, struct etna_query *q)
324 {
325 struct etna_pm_query *pq = etna_pm_query(q);
326
327 etna_bo_del(pq->bo);
328 FREE(pq);
329 }
330
331 static boolean
332 etna_pm_begin_query(struct etna_context *ctx, struct etna_query *q)
333 {
334 struct etna_pm_query *pq = etna_pm_query(q);
335
336 pq->ready = false;
337 pq->sequence++;
338
339 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_PRE);
340
341 return true;
342 }
343
344 static void
345 etna_pm_end_query(struct etna_context *ctx, struct etna_query *q)
346 {
347 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_POST);
348 }
349
350 static boolean
351 etna_pm_get_query_result(struct etna_context *ctx, struct etna_query *q,
352 boolean wait, union pipe_query_result *result)
353 {
354 struct etna_pm_query *pq = etna_pm_query(q);
355
356 etna_pm_query_update(q);
357
358 if (!pq->ready) {
359 if (!wait)
360 return false;
361
362 if (!etna_bo_cpu_prep(pq->bo, DRM_ETNA_PREP_READ))
363 return false;
364
365 pq->ready = true;
366 etna_bo_cpu_fini(pq->bo);
367 }
368
369 result->u32 = pq->data[2] - pq->data[1];
370
371 return true;
372 }
373
374 static const struct etna_query_funcs hw_query_funcs = {
375 .destroy_query = etna_pm_destroy_query,
376 .begin_query = etna_pm_begin_query,
377 .end_query = etna_pm_end_query,
378 .get_query_result = etna_pm_get_query_result,
379 };
380
381 struct etna_query *
382 etna_pm_create_query(struct etna_context *ctx, unsigned query_type)
383 {
384 struct etna_perfmon *perfmon = ctx->screen->perfmon;
385 const struct etna_perfmon_config *cfg;
386 struct etna_pm_query *pq;
387 struct etna_query *q;
388
389 cfg = etna_pm_query_config(query_type);
390 if (!cfg)
391 return NULL;
392
393 if (!etna_pm_cfg_supported(perfmon, cfg))
394 return NULL;
395
396 pq = CALLOC_STRUCT(etna_pm_query);
397 if (!pq)
398 return NULL;
399
400 if (!realloc_query_bo(ctx, pq)) {
401 FREE(pq);
402 return NULL;
403 }
404
405 q = &pq->base;
406 q->funcs = &hw_query_funcs;
407 q->type = query_type;
408
409 etna_pm_add_signal(pq, perfmon, cfg);
410
411 return q;
412 }
413
414 void
415 etna_pm_query_setup(struct etna_screen *screen)
416 {
417 screen->perfmon = etna_perfmon_create(screen->pipe);
418
419 if (!screen->perfmon)
420 return;
421
422 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++) {
423 const struct etna_perfmon_config *cfg = &query_config[i];
424
425 if (!etna_pm_cfg_supported(screen->perfmon, cfg))
426 continue;
427
428 util_dynarray_append(&screen->supported_pm_queries, unsigned, i);
429 }
430 }
431
432 int
433 etna_pm_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
434 struct pipe_driver_query_info *info)
435 {
436 const struct etna_screen *screen = etna_screen(pscreen);
437 const unsigned num = screen->supported_pm_queries.size / sizeof(unsigned);
438 unsigned i;
439
440 if (!info)
441 return num;
442
443 if (index >= num)
444 return 0;
445
446 i = *util_dynarray_element(&screen->supported_pm_queries, unsigned, index);
447 assert(i < ARRAY_SIZE(query_config));
448
449 info->name = query_config[i].name;
450 info->query_type = query_config[i].type;
451 info->group_id = 0;
452
453 return 1;
454 }