etnaviv: support MC 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 .name = "mc-total-read-req-8b-from-pipeline",
345 .type = ETNA_QUERY_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE,
346 .source = (const struct etna_perfmon_source[]) {
347 { "MC", "TOTAL_READ_REQ_8B_FROM_PIPELINE" }
348 }
349 },
350 {
351 .name = "mc-total-read-req-8b-from-ip",
352 .type = ETNA_QUERY_MC_TOTAL_READ_REQ_8B_FROM_IP,
353 .source = (const struct etna_perfmon_source[]) {
354 { "MC", "TOTAL_READ_REQ_8B_FROM_IP" }
355 }
356 },
357 {
358 .name = "mc-total-write-req-8b-from-pipeline",
359 .type = ETNA_QUERY_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE,
360 .source = (const struct etna_perfmon_source[]) {
361 { "MC", "TOTAL_WRITE_REQ_8B_FROM_PIPELINE" }
362 }
363 }
364 };
365
366 static const struct etna_perfmon_config *
367 etna_pm_query_config(unsigned type)
368 {
369 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
370 if (query_config[i].type == type)
371 return &query_config[i];
372
373 return NULL;
374 }
375
376 static struct etna_perfmon_signal *
377 etna_pm_query_signal(struct etna_perfmon *perfmon,
378 const struct etna_perfmon_source *source)
379 {
380 struct etna_perfmon_domain *domain;
381
382 domain = etna_perfmon_get_dom_by_name(perfmon, source->domain);
383 if (!domain)
384 return NULL;
385
386 return etna_perfmon_get_sig_by_name(domain, source->signal);
387 }
388
389 static inline bool
390 etna_pm_cfg_supported(struct etna_perfmon *perfmon,
391 const struct etna_perfmon_config *cfg)
392 {
393 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
394
395 return !!signal;
396 }
397
398 static inline void
399 etna_pm_add_signal(struct etna_pm_query *pq, struct etna_perfmon *perfmon,
400 const struct etna_perfmon_config *cfg)
401 {
402 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
403
404 pq->signal = signal;
405 }
406
407 static bool
408 realloc_query_bo(struct etna_context *ctx, struct etna_pm_query *pq)
409 {
410 if (pq->bo)
411 etna_bo_del(pq->bo);
412
413 pq->bo = etna_bo_new(ctx->screen->dev, 64, DRM_ETNA_GEM_CACHE_WC);
414 if (unlikely(!pq->bo))
415 return false;
416
417 pq->data = etna_bo_map(pq->bo);
418
419 return true;
420 }
421
422 static void
423 etna_pm_query_get(struct etna_cmd_stream *stream, struct etna_query *q,
424 unsigned flags)
425 {
426 struct etna_pm_query *pq = etna_pm_query(q);
427 unsigned offset;
428 assert(flags);
429
430 if (flags == ETNA_PM_PROCESS_PRE)
431 offset = 2;
432 else
433 offset = 3;
434
435 struct etna_perf p = {
436 .flags = flags,
437 .sequence = pq->sequence,
438 .bo = pq->bo,
439 .signal = pq->signal,
440 .offset = offset
441 };
442
443 etna_cmd_stream_perf(stream, &p);
444 }
445
446 static inline void
447 etna_pm_query_update(struct etna_query *q)
448 {
449 struct etna_pm_query *pq = etna_pm_query(q);
450
451 if (pq->data[0] == pq->sequence)
452 pq->ready = true;
453 }
454
455 static void
456 etna_pm_destroy_query(struct etna_context *ctx, struct etna_query *q)
457 {
458 struct etna_pm_query *pq = etna_pm_query(q);
459
460 etna_bo_del(pq->bo);
461 FREE(pq);
462 }
463
464 static boolean
465 etna_pm_begin_query(struct etna_context *ctx, struct etna_query *q)
466 {
467 struct etna_pm_query *pq = etna_pm_query(q);
468
469 pq->ready = false;
470 pq->sequence++;
471
472 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_PRE);
473
474 return true;
475 }
476
477 static void
478 etna_pm_end_query(struct etna_context *ctx, struct etna_query *q)
479 {
480 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_POST);
481 }
482
483 static boolean
484 etna_pm_get_query_result(struct etna_context *ctx, struct etna_query *q,
485 boolean wait, union pipe_query_result *result)
486 {
487 struct etna_pm_query *pq = etna_pm_query(q);
488
489 etna_pm_query_update(q);
490
491 if (!pq->ready) {
492 if (!wait)
493 return false;
494
495 if (!etna_bo_cpu_prep(pq->bo, DRM_ETNA_PREP_READ))
496 return false;
497
498 pq->ready = true;
499 etna_bo_cpu_fini(pq->bo);
500 }
501
502 result->u32 = pq->data[2] - pq->data[1];
503
504 return true;
505 }
506
507 static const struct etna_query_funcs hw_query_funcs = {
508 .destroy_query = etna_pm_destroy_query,
509 .begin_query = etna_pm_begin_query,
510 .end_query = etna_pm_end_query,
511 .get_query_result = etna_pm_get_query_result,
512 };
513
514 struct etna_query *
515 etna_pm_create_query(struct etna_context *ctx, unsigned query_type)
516 {
517 struct etna_perfmon *perfmon = ctx->screen->perfmon;
518 const struct etna_perfmon_config *cfg;
519 struct etna_pm_query *pq;
520 struct etna_query *q;
521
522 cfg = etna_pm_query_config(query_type);
523 if (!cfg)
524 return NULL;
525
526 if (!etna_pm_cfg_supported(perfmon, cfg))
527 return NULL;
528
529 pq = CALLOC_STRUCT(etna_pm_query);
530 if (!pq)
531 return NULL;
532
533 if (!realloc_query_bo(ctx, pq)) {
534 FREE(pq);
535 return NULL;
536 }
537
538 q = &pq->base;
539 q->funcs = &hw_query_funcs;
540 q->type = query_type;
541
542 etna_pm_add_signal(pq, perfmon, cfg);
543
544 return q;
545 }
546
547 void
548 etna_pm_query_setup(struct etna_screen *screen)
549 {
550 screen->perfmon = etna_perfmon_create(screen->pipe);
551
552 if (!screen->perfmon)
553 return;
554
555 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++) {
556 const struct etna_perfmon_config *cfg = &query_config[i];
557
558 if (!etna_pm_cfg_supported(screen->perfmon, cfg))
559 continue;
560
561 util_dynarray_append(&screen->supported_pm_queries, unsigned, i);
562 }
563 }
564
565 int
566 etna_pm_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
567 struct pipe_driver_query_info *info)
568 {
569 const struct etna_screen *screen = etna_screen(pscreen);
570 const unsigned num = screen->supported_pm_queries.size / sizeof(unsigned);
571 unsigned i;
572
573 if (!info)
574 return num;
575
576 if (index >= num)
577 return 0;
578
579 i = *util_dynarray_element(&screen->supported_pm_queries, unsigned, index);
580 assert(i < ARRAY_SIZE(query_config));
581
582 info->name = query_config[i].name;
583 info->query_type = query_config[i].type;
584 info->group_id = 0;
585
586 return 1;
587 }