etnaviv: support TX 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 .name = "ra-valid-pixel-count",
233 .type = ETNA_QUERY_RA_VALID_PIXEL_COUNT,
234 .source = (const struct etna_perfmon_source[]) {
235 { "RA", "VALID_PIXEL_COUNT" }
236 }
237 },
238 {
239 .name = "ra-total-quad-count",
240 .type = ETNA_QUERY_RA_TOTAL_QUAD_COUNT,
241 .source = (const struct etna_perfmon_source[]) {
242 { "RA", "TOTAL_QUAD_COUNT" }
243 }
244 },
245 {
246 .name = "ra-valid-quad-count-after-early-z",
247 .type = ETNA_QUERY_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z,
248 .source = (const struct etna_perfmon_source[]) {
249 { "RA", "VALID_QUAD_COUNT_AFTER_EARLY_Z" }
250 }
251 },
252 {
253 .name = "ra-total-primitive-count",
254 .type = ETNA_QUERY_RA_TOTAL_PRIMITIVE_COUNT,
255 .source = (const struct etna_perfmon_source[]) {
256 { "RA", "TOTAL_PRIMITIVE_COUNT" }
257 }
258 },
259 {
260 .name = "ra-pipe-cache-miss-counter",
261 .type = ETNA_QUERY_RA_PIPE_CACHE_MISS_COUNTER,
262 .source = (const struct etna_perfmon_source[]) {
263 { "RA", "PIPE_CACHE_MISS_COUNTER" }
264 }
265 },
266 {
267 .name = "ra-prefetch-cache-miss-counter",
268 .type = ETNA_QUERY_RA_PREFETCH_CACHE_MISS_COUNTER,
269 .source = (const struct etna_perfmon_source[]) {
270 { "RA", "PREFETCH_CACHE_MISS_COUNTER" }
271 }
272 },
273 {
274 .name = "ra-pculled-quad-count",
275 .type = ETNA_QUERY_RA_CULLED_QUAD_COUNT,
276 .source = (const struct etna_perfmon_source[]) {
277 { "RA", "CULLED_QUAD_COUNT" }
278 }
279 },
280 {
281 .name = "tx-total-bilinear-requests",
282 .type = ETNA_QUERY_TX_TOTAL_BILINEAR_REQUESTS,
283 .source = (const struct etna_perfmon_source[]) {
284 { "TX", "TOTAL_BILINEAR_REQUESTS" }
285 }
286 },
287 {
288 .name = "tx-total-trilinear-requests",
289 .type = ETNA_QUERY_TX_TOTAL_TRILINEAR_REQUESTS,
290 .source = (const struct etna_perfmon_source[]) {
291 { "TX", "TOTAL_TRILINEAR_REQUESTS" }
292 }
293 },
294 {
295 .name = "tx-total-discarded-texture-requests",
296 .type = ETNA_QUERY_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS,
297 .source = (const struct etna_perfmon_source[]) {
298 { "TX", "TOTAL_DISCARDED_TEXTURE_REQUESTS" }
299 }
300 },
301 {
302 .name = "tx-total-texture-requests",
303 .type = ETNA_QUERY_TX_TOTAL_TEXTURE_REQUESTS,
304 .source = (const struct etna_perfmon_source[]) {
305 { "TX", "TOTAL_TEXTURE_REQUESTS" }
306 }
307 },
308 {
309 .name = "tx-mem-read-count",
310 .type = ETNA_QUERY_TX_MEM_READ_COUNT,
311 .source = (const struct etna_perfmon_source[]) {
312 { "TX", "MEM_READ_COUNT" }
313 }
314 },
315 {
316 .name = "tx-mem-read-in-8b-count",
317 .type = ETNA_QUERY_TX_MEM_READ_IN_8B_COUNT,
318 .source = (const struct etna_perfmon_source[]) {
319 { "TX", "MEM_READ_IN_8B_COUNT" }
320 }
321 },
322 {
323 .name = "tx-cache-miss-count",
324 .type = ETNA_QUERY_TX_CACHE_MISS_COUNT,
325 .source = (const struct etna_perfmon_source[]) {
326 { "TX", "CACHE_MISS_COUNT" }
327 }
328 },
329 {
330 .name = "tx-cache-hit-texel-count",
331 .type = ETNA_QUERY_TX_CACHE_HIT_TEXEL_COUNT,
332 .source = (const struct etna_perfmon_source[]) {
333 { "TX", "CACHE_HIT_TEXEL_COUNT" }
334 }
335 },
336 {
337 .name = "tx-cache-miss-texel-count",
338 .type = ETNA_QUERY_TX_CACHE_MISS_TEXEL_COUNT,
339 .source = (const struct etna_perfmon_source[]) {
340 { "TX", "CACHE_MISS_TEXEL_COUNT" }
341 }
342 }
343 };
344
345 static const struct etna_perfmon_config *
346 etna_pm_query_config(unsigned type)
347 {
348 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
349 if (query_config[i].type == type)
350 return &query_config[i];
351
352 return NULL;
353 }
354
355 static struct etna_perfmon_signal *
356 etna_pm_query_signal(struct etna_perfmon *perfmon,
357 const struct etna_perfmon_source *source)
358 {
359 struct etna_perfmon_domain *domain;
360
361 domain = etna_perfmon_get_dom_by_name(perfmon, source->domain);
362 if (!domain)
363 return NULL;
364
365 return etna_perfmon_get_sig_by_name(domain, source->signal);
366 }
367
368 static inline bool
369 etna_pm_cfg_supported(struct etna_perfmon *perfmon,
370 const struct etna_perfmon_config *cfg)
371 {
372 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
373
374 return !!signal;
375 }
376
377 static inline void
378 etna_pm_add_signal(struct etna_pm_query *pq, struct etna_perfmon *perfmon,
379 const struct etna_perfmon_config *cfg)
380 {
381 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
382
383 pq->signal = signal;
384 }
385
386 static bool
387 realloc_query_bo(struct etna_context *ctx, struct etna_pm_query *pq)
388 {
389 if (pq->bo)
390 etna_bo_del(pq->bo);
391
392 pq->bo = etna_bo_new(ctx->screen->dev, 64, DRM_ETNA_GEM_CACHE_WC);
393 if (unlikely(!pq->bo))
394 return false;
395
396 pq->data = etna_bo_map(pq->bo);
397
398 return true;
399 }
400
401 static void
402 etna_pm_query_get(struct etna_cmd_stream *stream, struct etna_query *q,
403 unsigned flags)
404 {
405 struct etna_pm_query *pq = etna_pm_query(q);
406 unsigned offset;
407 assert(flags);
408
409 if (flags == ETNA_PM_PROCESS_PRE)
410 offset = 2;
411 else
412 offset = 3;
413
414 struct etna_perf p = {
415 .flags = flags,
416 .sequence = pq->sequence,
417 .bo = pq->bo,
418 .signal = pq->signal,
419 .offset = offset
420 };
421
422 etna_cmd_stream_perf(stream, &p);
423 }
424
425 static inline void
426 etna_pm_query_update(struct etna_query *q)
427 {
428 struct etna_pm_query *pq = etna_pm_query(q);
429
430 if (pq->data[0] == pq->sequence)
431 pq->ready = true;
432 }
433
434 static void
435 etna_pm_destroy_query(struct etna_context *ctx, struct etna_query *q)
436 {
437 struct etna_pm_query *pq = etna_pm_query(q);
438
439 etna_bo_del(pq->bo);
440 FREE(pq);
441 }
442
443 static boolean
444 etna_pm_begin_query(struct etna_context *ctx, struct etna_query *q)
445 {
446 struct etna_pm_query *pq = etna_pm_query(q);
447
448 pq->ready = false;
449 pq->sequence++;
450
451 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_PRE);
452
453 return true;
454 }
455
456 static void
457 etna_pm_end_query(struct etna_context *ctx, struct etna_query *q)
458 {
459 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_POST);
460 }
461
462 static boolean
463 etna_pm_get_query_result(struct etna_context *ctx, struct etna_query *q,
464 boolean wait, union pipe_query_result *result)
465 {
466 struct etna_pm_query *pq = etna_pm_query(q);
467
468 etna_pm_query_update(q);
469
470 if (!pq->ready) {
471 if (!wait)
472 return false;
473
474 if (!etna_bo_cpu_prep(pq->bo, DRM_ETNA_PREP_READ))
475 return false;
476
477 pq->ready = true;
478 etna_bo_cpu_fini(pq->bo);
479 }
480
481 result->u32 = pq->data[2] - pq->data[1];
482
483 return true;
484 }
485
486 static const struct etna_query_funcs hw_query_funcs = {
487 .destroy_query = etna_pm_destroy_query,
488 .begin_query = etna_pm_begin_query,
489 .end_query = etna_pm_end_query,
490 .get_query_result = etna_pm_get_query_result,
491 };
492
493 struct etna_query *
494 etna_pm_create_query(struct etna_context *ctx, unsigned query_type)
495 {
496 struct etna_perfmon *perfmon = ctx->screen->perfmon;
497 const struct etna_perfmon_config *cfg;
498 struct etna_pm_query *pq;
499 struct etna_query *q;
500
501 cfg = etna_pm_query_config(query_type);
502 if (!cfg)
503 return NULL;
504
505 if (!etna_pm_cfg_supported(perfmon, cfg))
506 return NULL;
507
508 pq = CALLOC_STRUCT(etna_pm_query);
509 if (!pq)
510 return NULL;
511
512 if (!realloc_query_bo(ctx, pq)) {
513 FREE(pq);
514 return NULL;
515 }
516
517 q = &pq->base;
518 q->funcs = &hw_query_funcs;
519 q->type = query_type;
520
521 etna_pm_add_signal(pq, perfmon, cfg);
522
523 return q;
524 }
525
526 void
527 etna_pm_query_setup(struct etna_screen *screen)
528 {
529 screen->perfmon = etna_perfmon_create(screen->pipe);
530
531 if (!screen->perfmon)
532 return;
533
534 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++) {
535 const struct etna_perfmon_config *cfg = &query_config[i];
536
537 if (!etna_pm_cfg_supported(screen->perfmon, cfg))
538 continue;
539
540 util_dynarray_append(&screen->supported_pm_queries, unsigned, i);
541 }
542 }
543
544 int
545 etna_pm_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
546 struct pipe_driver_query_info *info)
547 {
548 const struct etna_screen *screen = etna_screen(pscreen);
549 const unsigned num = screen->supported_pm_queries.size / sizeof(unsigned);
550 unsigned i;
551
552 if (!info)
553 return num;
554
555 if (index >= num)
556 return 0;
557
558 i = *util_dynarray_element(&screen->supported_pm_queries, unsigned, index);
559 assert(i < ARRAY_SIZE(query_config));
560
561 info->name = query_config[i].name;
562 info->query_type = query_config[i].type;
563 info->group_id = 0;
564
565 return 1;
566 }