1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci#include "crocus_monitor.h"
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include <xf86drm.h>
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "crocus_screen.h"
28bf215546Sopenharmony_ci#include "crocus_context.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "perf/intel_perf.h"
31bf215546Sopenharmony_ci#include "perf/intel_perf_query.h"
32bf215546Sopenharmony_ci#include "perf/intel_perf_regs.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_cistruct crocus_monitor_object {
35bf215546Sopenharmony_ci   int num_active_counters;
36bf215546Sopenharmony_ci   int *active_counters;
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci   size_t result_size;
39bf215546Sopenharmony_ci   unsigned char *result_buffer;
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci   struct intel_perf_query_object *query;
42bf215546Sopenharmony_ci};
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ciint
45bf215546Sopenharmony_cicrocus_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
46bf215546Sopenharmony_ci                        struct pipe_driver_query_info *info)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   const struct crocus_screen *screen = (struct crocus_screen *)pscreen;
49bf215546Sopenharmony_ci   assert(screen->monitor_cfg);
50bf215546Sopenharmony_ci   if (!screen->monitor_cfg)
51bf215546Sopenharmony_ci      return 0;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   const struct crocus_monitor_config *monitor_cfg = screen->monitor_cfg;
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci   if (!info) {
56bf215546Sopenharmony_ci      /* return the number of metrics */
57bf215546Sopenharmony_ci      return monitor_cfg->num_counters;
58bf215546Sopenharmony_ci   }
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   const struct intel_perf_config *perf_cfg = monitor_cfg->perf_cfg;
61bf215546Sopenharmony_ci   const int group = monitor_cfg->counters[index].group;
62bf215546Sopenharmony_ci   const int counter_index = monitor_cfg->counters[index].counter;
63bf215546Sopenharmony_ci   struct intel_perf_query_counter *counter =
64bf215546Sopenharmony_ci      &perf_cfg->queries[group].counters[counter_index];
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   info->group_id = group;
67bf215546Sopenharmony_ci   info->name = counter->name;
68bf215546Sopenharmony_ci   info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   if (counter->type == INTEL_PERF_COUNTER_TYPE_THROUGHPUT)
71bf215546Sopenharmony_ci      info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE;
72bf215546Sopenharmony_ci   else
73bf215546Sopenharmony_ci      info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
74bf215546Sopenharmony_ci   switch (counter->data_type) {
75bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
76bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
77bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_UINT;
78bf215546Sopenharmony_ci      info->max_value.u32 = 0;
79bf215546Sopenharmony_ci      break;
80bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
81bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
82bf215546Sopenharmony_ci      info->max_value.u64 = 0;
83bf215546Sopenharmony_ci      break;
84bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
85bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE:
86bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_FLOAT;
87bf215546Sopenharmony_ci      info->max_value.u64 = -1;
88bf215546Sopenharmony_ci      break;
89bf215546Sopenharmony_ci   default:
90bf215546Sopenharmony_ci      assert(false);
91bf215546Sopenharmony_ci      break;
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   /* indicates that this is an OA query, not a pipeline statistics query */
95bf215546Sopenharmony_ci   info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
96bf215546Sopenharmony_ci   return 1;
97bf215546Sopenharmony_ci}
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_citypedef void (*bo_unreference_t)(void *);
100bf215546Sopenharmony_citypedef void *(*bo_map_t)(void *, void *, unsigned flags);
101bf215546Sopenharmony_citypedef void (*bo_unmap_t)(void *);
102bf215546Sopenharmony_citypedef void (*emit_mi_report_t)(void *, void *, uint32_t, uint32_t);
103bf215546Sopenharmony_citypedef void (*emit_mi_flush_t)(void *);
104bf215546Sopenharmony_citypedef void (*capture_frequency_stat_register_t)(void *, void *,
105bf215546Sopenharmony_ci                                                  uint32_t );
106bf215546Sopenharmony_citypedef void (*store_register_mem64_t)(void *ctx, void *bo,
107bf215546Sopenharmony_ci                                       uint32_t reg, uint32_t offset);
108bf215546Sopenharmony_citypedef bool (*batch_references_t)(void *batch, void *bo);
109bf215546Sopenharmony_citypedef void (*bo_wait_rendering_t)(void *bo);
110bf215546Sopenharmony_citypedef int (*bo_busy_t)(void *bo);
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_cistatic void *
113bf215546Sopenharmony_cicrocus_oa_bo_alloc(void *bufmgr, const char *name, uint64_t size)
114bf215546Sopenharmony_ci{
115bf215546Sopenharmony_ci   return crocus_bo_alloc(bufmgr, name, size);
116bf215546Sopenharmony_ci}
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci#if 0
119bf215546Sopenharmony_cistatic void
120bf215546Sopenharmony_cicrocus_monitor_emit_mi_flush(struct crocus_context *ice)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci   const int flags = PIPE_CONTROL_RENDER_TARGET_FLUSH |
123bf215546Sopenharmony_ci                     PIPE_CONTROL_INSTRUCTION_INVALIDATE |
124bf215546Sopenharmony_ci                     PIPE_CONTROL_CONST_CACHE_INVALIDATE |
125bf215546Sopenharmony_ci                     PIPE_CONTROL_DATA_CACHE_FLUSH |
126bf215546Sopenharmony_ci                     PIPE_CONTROL_DEPTH_CACHE_FLUSH |
127bf215546Sopenharmony_ci                     PIPE_CONTROL_VF_CACHE_INVALIDATE |
128bf215546Sopenharmony_ci                     PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
129bf215546Sopenharmony_ci                     PIPE_CONTROL_CS_STALL;
130bf215546Sopenharmony_ci   crocus_emit_pipe_control_flush(&ice->batches[CROCUS_BATCH_RENDER],
131bf215546Sopenharmony_ci                                  "OA metrics", flags);
132bf215546Sopenharmony_ci}
133bf215546Sopenharmony_ci#endif
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_cistatic void
136bf215546Sopenharmony_cicrocus_monitor_emit_mi_report_perf_count(void *c,
137bf215546Sopenharmony_ci                                         void *bo,
138bf215546Sopenharmony_ci                                         uint32_t offset_in_bytes,
139bf215546Sopenharmony_ci                                         uint32_t report_id)
140bf215546Sopenharmony_ci{
141bf215546Sopenharmony_ci   struct crocus_context *ice = c;
142bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
143bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
144bf215546Sopenharmony_ci   screen->vtbl.emit_mi_report_perf_count(batch, bo, offset_in_bytes, report_id);
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic void
148bf215546Sopenharmony_cicrocus_monitor_batchbuffer_flush(void *c, const char *file, int line)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   struct crocus_context *ice = c;
151bf215546Sopenharmony_ci   _crocus_batch_flush(&ice->batches[CROCUS_BATCH_RENDER], __FILE__, __LINE__);
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci#if 0
155bf215546Sopenharmony_cistatic void
156bf215546Sopenharmony_cicrocus_monitor_capture_frequency_stat_register(void *ctx,
157bf215546Sopenharmony_ci                                               void *bo,
158bf215546Sopenharmony_ci                                               uint32_t bo_offset)
159bf215546Sopenharmony_ci{
160bf215546Sopenharmony_ci   struct crocus_context *ice = ctx;
161bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
162bf215546Sopenharmony_ci   ice->vtbl.store_register_mem32(batch, GEN9_RPSTAT0, bo, bo_offset, false);
163bf215546Sopenharmony_ci}
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_cistatic void
166bf215546Sopenharmony_cicrocus_monitor_store_register_mem64(void *ctx, void *bo,
167bf215546Sopenharmony_ci                                    uint32_t reg, uint32_t offset)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   struct crocus_context *ice = ctx;
170bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
171bf215546Sopenharmony_ci   ice->vtbl.store_register_mem64(batch, reg, bo, offset, false);
172bf215546Sopenharmony_ci}
173bf215546Sopenharmony_ci#endif
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_cistatic bool
176bf215546Sopenharmony_cicrocus_monitor_init_metrics(struct crocus_screen *screen)
177bf215546Sopenharmony_ci{
178bf215546Sopenharmony_ci   struct crocus_monitor_config *monitor_cfg =
179bf215546Sopenharmony_ci      rzalloc(screen, struct crocus_monitor_config);
180bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = NULL;
181bf215546Sopenharmony_ci   if (unlikely(!monitor_cfg))
182bf215546Sopenharmony_ci      goto allocation_error;
183bf215546Sopenharmony_ci   perf_cfg = intel_perf_new(monitor_cfg);
184bf215546Sopenharmony_ci   if (unlikely(!perf_cfg))
185bf215546Sopenharmony_ci      goto allocation_error;
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   monitor_cfg->perf_cfg = perf_cfg;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_alloc = crocus_oa_bo_alloc;
190bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_unreference = (bo_unreference_t)crocus_bo_unreference;
191bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_map = (bo_map_t)crocus_bo_map;
192bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_unmap = (bo_unmap_t)crocus_bo_unmap;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   perf_cfg->vtbl.emit_mi_report_perf_count =
195bf215546Sopenharmony_ci      (emit_mi_report_t)crocus_monitor_emit_mi_report_perf_count;
196bf215546Sopenharmony_ci   perf_cfg->vtbl.batchbuffer_flush = crocus_monitor_batchbuffer_flush;
197bf215546Sopenharmony_ci   perf_cfg->vtbl.batch_references = (batch_references_t)crocus_batch_references;
198bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_wait_rendering =
199bf215546Sopenharmony_ci      (bo_wait_rendering_t)crocus_bo_wait_rendering;
200bf215546Sopenharmony_ci   perf_cfg->vtbl.bo_busy = (bo_busy_t)crocus_bo_busy;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   intel_perf_init_metrics(perf_cfg, &screen->devinfo, screen->fd, false, false);
203bf215546Sopenharmony_ci   screen->monitor_cfg = monitor_cfg;
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   /* a gallium "group" is equivalent to a gen "query"
206bf215546Sopenharmony_ci    * a gallium "query" is equivalent to a gen "query_counter"
207bf215546Sopenharmony_ci    *
208bf215546Sopenharmony_ci    * Each gen_query supports a specific number of query_counters.  To
209bf215546Sopenharmony_ci    * allocate the array of crocus_monitor_counter, we need an upper bound
210bf215546Sopenharmony_ci    * (ignoring duplicate query_counters).
211bf215546Sopenharmony_ci    */
212bf215546Sopenharmony_ci   int gen_query_counters_count = 0;
213bf215546Sopenharmony_ci   for (int gen_query_id = 0;
214bf215546Sopenharmony_ci        gen_query_id < perf_cfg->n_queries;
215bf215546Sopenharmony_ci        ++gen_query_id) {
216bf215546Sopenharmony_ci      gen_query_counters_count += perf_cfg->queries[gen_query_id].n_counters;
217bf215546Sopenharmony_ci   }
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   monitor_cfg->counters = rzalloc_size(monitor_cfg,
220bf215546Sopenharmony_ci                                        sizeof(struct crocus_monitor_counter) *
221bf215546Sopenharmony_ci                                        gen_query_counters_count);
222bf215546Sopenharmony_ci   if (unlikely(!monitor_cfg->counters))
223bf215546Sopenharmony_ci      goto allocation_error;
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   int crocus_monitor_id = 0;
226bf215546Sopenharmony_ci   for (int group = 0; group < perf_cfg->n_queries; ++group) {
227bf215546Sopenharmony_ci      for (int counter = 0;
228bf215546Sopenharmony_ci           counter < perf_cfg->queries[group].n_counters;
229bf215546Sopenharmony_ci           ++counter) {
230bf215546Sopenharmony_ci         /* Check previously identified metrics to filter out duplicates. The
231bf215546Sopenharmony_ci          * user is not helped by having the same metric available in several
232bf215546Sopenharmony_ci          * groups. (n^2 algorithm).
233bf215546Sopenharmony_ci          */
234bf215546Sopenharmony_ci         bool duplicate = false;
235bf215546Sopenharmony_ci         for (int existing_group = 0;
236bf215546Sopenharmony_ci              existing_group < group && !duplicate;
237bf215546Sopenharmony_ci              ++existing_group) {
238bf215546Sopenharmony_ci            for (int existing_counter = 0;
239bf215546Sopenharmony_ci                 existing_counter < perf_cfg->queries[existing_group].n_counters && !duplicate;
240bf215546Sopenharmony_ci                 ++existing_counter) {
241bf215546Sopenharmony_ci               const char *current_name =
242bf215546Sopenharmony_ci                  perf_cfg->queries[group].counters[counter].name;
243bf215546Sopenharmony_ci               const char *existing_name =
244bf215546Sopenharmony_ci                  perf_cfg->queries[existing_group].counters[existing_counter].name;
245bf215546Sopenharmony_ci               if (strcmp(current_name, existing_name) == 0) {
246bf215546Sopenharmony_ci                  duplicate = true;
247bf215546Sopenharmony_ci               }
248bf215546Sopenharmony_ci            }
249bf215546Sopenharmony_ci         }
250bf215546Sopenharmony_ci         if (duplicate)
251bf215546Sopenharmony_ci            continue;
252bf215546Sopenharmony_ci         monitor_cfg->counters[crocus_monitor_id].group = group;
253bf215546Sopenharmony_ci         monitor_cfg->counters[crocus_monitor_id].counter = counter;
254bf215546Sopenharmony_ci         ++crocus_monitor_id;
255bf215546Sopenharmony_ci      }
256bf215546Sopenharmony_ci   }
257bf215546Sopenharmony_ci   monitor_cfg->num_counters = crocus_monitor_id;
258bf215546Sopenharmony_ci   return monitor_cfg->num_counters;
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ciallocation_error:
261bf215546Sopenharmony_ci   if (monitor_cfg)
262bf215546Sopenharmony_ci      free(monitor_cfg->counters);
263bf215546Sopenharmony_ci   free(perf_cfg);
264bf215546Sopenharmony_ci   free(monitor_cfg);
265bf215546Sopenharmony_ci   return false;
266bf215546Sopenharmony_ci}
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ciint
269bf215546Sopenharmony_cicrocus_get_monitor_group_info(struct pipe_screen *pscreen,
270bf215546Sopenharmony_ci                              unsigned group_index,
271bf215546Sopenharmony_ci                              struct pipe_driver_query_group_info *info)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen *)pscreen;
274bf215546Sopenharmony_ci   if (!screen->monitor_cfg) {
275bf215546Sopenharmony_ci      if (!crocus_monitor_init_metrics(screen))
276bf215546Sopenharmony_ci         return 0;
277bf215546Sopenharmony_ci   }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   const struct crocus_monitor_config *monitor_cfg = screen->monitor_cfg;
280bf215546Sopenharmony_ci   const struct intel_perf_config *perf_cfg = monitor_cfg->perf_cfg;
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci   if (!info) {
283bf215546Sopenharmony_ci      /* return the count that can be queried */
284bf215546Sopenharmony_ci      return perf_cfg->n_queries;
285bf215546Sopenharmony_ci   }
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   if (group_index >= perf_cfg->n_queries) {
288bf215546Sopenharmony_ci      /* out of range */
289bf215546Sopenharmony_ci      return 0;
290bf215546Sopenharmony_ci   }
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   struct intel_perf_query_info *query = &perf_cfg->queries[group_index];
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   info->name = query->name;
295bf215546Sopenharmony_ci   info->max_active_queries = query->n_counters;
296bf215546Sopenharmony_ci   info->num_queries = query->n_counters;
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   return 1;
299bf215546Sopenharmony_ci}
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_cistatic void
302bf215546Sopenharmony_cicrocus_init_monitor_ctx(struct crocus_context *ice)
303bf215546Sopenharmony_ci{
304bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen *) ice->ctx.screen;
305bf215546Sopenharmony_ci   struct crocus_monitor_config *monitor_cfg = screen->monitor_cfg;
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   ice->perf_ctx = intel_perf_new_context(ice);
308bf215546Sopenharmony_ci   if (unlikely(!ice->perf_ctx))
309bf215546Sopenharmony_ci      return;
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
312bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = monitor_cfg->perf_cfg;
313bf215546Sopenharmony_ci   intel_perf_init_context(perf_ctx,
314bf215546Sopenharmony_ci                           perf_cfg,
315bf215546Sopenharmony_ci                           ice,
316bf215546Sopenharmony_ci                           ice,
317bf215546Sopenharmony_ci                           screen->bufmgr,
318bf215546Sopenharmony_ci                           &screen->devinfo,
319bf215546Sopenharmony_ci                           ice->batches[CROCUS_BATCH_RENDER].hw_ctx_id,
320bf215546Sopenharmony_ci                           screen->fd);
321bf215546Sopenharmony_ci}
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci/* entry point for GenPerfMonitorsAMD */
324bf215546Sopenharmony_cistruct crocus_monitor_object *
325bf215546Sopenharmony_cicrocus_create_monitor_object(struct crocus_context *ice,
326bf215546Sopenharmony_ci                             unsigned num_queries,
327bf215546Sopenharmony_ci                             unsigned *query_types)
328bf215546Sopenharmony_ci{
329bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen *) ice->ctx.screen;
330bf215546Sopenharmony_ci   struct crocus_monitor_config *monitor_cfg = screen->monitor_cfg;
331bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = monitor_cfg->perf_cfg;
332bf215546Sopenharmony_ci   struct intel_perf_query_object *query_obj = NULL;
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   /* initialize perf context if this has not already been done.  This
335bf215546Sopenharmony_ci    * function is the first entry point that carries the gl context.
336bf215546Sopenharmony_ci    */
337bf215546Sopenharmony_ci   if (ice->perf_ctx == NULL) {
338bf215546Sopenharmony_ci      crocus_init_monitor_ctx(ice);
339bf215546Sopenharmony_ci   }
340bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   assert(num_queries > 0);
343bf215546Sopenharmony_ci   int query_index = query_types[0] - PIPE_QUERY_DRIVER_SPECIFIC;
344bf215546Sopenharmony_ci   assert(query_index <= monitor_cfg->num_counters);
345bf215546Sopenharmony_ci   const int group = monitor_cfg->counters[query_index].group;
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   struct crocus_monitor_object *monitor =
348bf215546Sopenharmony_ci      calloc(1, sizeof(struct crocus_monitor_object));
349bf215546Sopenharmony_ci   if (unlikely(!monitor))
350bf215546Sopenharmony_ci      goto allocation_failure;
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   monitor->num_active_counters = num_queries;
353bf215546Sopenharmony_ci   monitor->active_counters = calloc(num_queries, sizeof(int));
354bf215546Sopenharmony_ci   if (unlikely(!monitor->active_counters))
355bf215546Sopenharmony_ci      goto allocation_failure;
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   for (int i = 0; i < num_queries; ++i) {
358bf215546Sopenharmony_ci      unsigned current_query = query_types[i];
359bf215546Sopenharmony_ci      unsigned current_query_index = current_query - PIPE_QUERY_DRIVER_SPECIFIC;
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci      /* all queries must be in the same group */
362bf215546Sopenharmony_ci      assert(current_query_index <= monitor_cfg->num_counters);
363bf215546Sopenharmony_ci      assert(monitor_cfg->counters[current_query_index].group == group);
364bf215546Sopenharmony_ci      monitor->active_counters[i] =
365bf215546Sopenharmony_ci         monitor_cfg->counters[current_query_index].counter;
366bf215546Sopenharmony_ci   }
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   /* create the intel_perf_query */
369bf215546Sopenharmony_ci   query_obj = intel_perf_new_query(perf_ctx, group);
370bf215546Sopenharmony_ci   if (unlikely(!query_obj))
371bf215546Sopenharmony_ci      goto allocation_failure;
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   monitor->query = query_obj;
374bf215546Sopenharmony_ci   monitor->result_size = perf_cfg->queries[group].data_size;
375bf215546Sopenharmony_ci   monitor->result_buffer = calloc(1, monitor->result_size);
376bf215546Sopenharmony_ci   if (unlikely(!monitor->result_buffer))
377bf215546Sopenharmony_ci      goto allocation_failure;
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   return monitor;
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ciallocation_failure:
382bf215546Sopenharmony_ci   if (monitor) {
383bf215546Sopenharmony_ci      free(monitor->active_counters);
384bf215546Sopenharmony_ci      free(monitor->result_buffer);
385bf215546Sopenharmony_ci   }
386bf215546Sopenharmony_ci   free(query_obj);
387bf215546Sopenharmony_ci   free(monitor);
388bf215546Sopenharmony_ci   return NULL;
389bf215546Sopenharmony_ci}
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_civoid
392bf215546Sopenharmony_cicrocus_destroy_monitor_object(struct pipe_context *ctx,
393bf215546Sopenharmony_ci                              struct crocus_monitor_object *monitor)
394bf215546Sopenharmony_ci{
395bf215546Sopenharmony_ci   struct crocus_context *ice = (struct crocus_context *)ctx;
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci   intel_perf_delete_query(ice->perf_ctx, monitor->query);
398bf215546Sopenharmony_ci   free(monitor->result_buffer);
399bf215546Sopenharmony_ci   monitor->result_buffer = NULL;
400bf215546Sopenharmony_ci   free(monitor->active_counters);
401bf215546Sopenharmony_ci   monitor->active_counters = NULL;
402bf215546Sopenharmony_ci   free(monitor);
403bf215546Sopenharmony_ci}
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_cibool
406bf215546Sopenharmony_cicrocus_begin_monitor(struct pipe_context *ctx,
407bf215546Sopenharmony_ci                     struct crocus_monitor_object *monitor)
408bf215546Sopenharmony_ci{
409bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
410bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   return intel_perf_begin_query(perf_ctx, monitor->query);
413bf215546Sopenharmony_ci}
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_cibool
416bf215546Sopenharmony_cicrocus_end_monitor(struct pipe_context *ctx,
417bf215546Sopenharmony_ci                   struct crocus_monitor_object *monitor)
418bf215546Sopenharmony_ci{
419bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
420bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci   intel_perf_end_query(perf_ctx, monitor->query);
423bf215546Sopenharmony_ci   return true;
424bf215546Sopenharmony_ci}
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_cibool
427bf215546Sopenharmony_cicrocus_get_monitor_result(struct pipe_context *ctx,
428bf215546Sopenharmony_ci                          struct crocus_monitor_object *monitor,
429bf215546Sopenharmony_ci                          bool wait,
430bf215546Sopenharmony_ci                          union pipe_numeric_type_union *result)
431bf215546Sopenharmony_ci{
432bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
433bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
434bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   bool monitor_ready =
437bf215546Sopenharmony_ci      intel_perf_is_query_ready(perf_ctx, monitor->query, batch);
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci   if (!monitor_ready) {
440bf215546Sopenharmony_ci      if (!wait)
441bf215546Sopenharmony_ci         return false;
442bf215546Sopenharmony_ci      intel_perf_wait_query(perf_ctx, monitor->query, batch);
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   assert(intel_perf_is_query_ready(perf_ctx, monitor->query, batch));
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   unsigned bytes_written;
448bf215546Sopenharmony_ci   intel_perf_get_query_data(perf_ctx, monitor->query, batch,
449bf215546Sopenharmony_ci                             monitor->result_size,
450bf215546Sopenharmony_ci                             (unsigned*) monitor->result_buffer,
451bf215546Sopenharmony_ci                             &bytes_written);
452bf215546Sopenharmony_ci   if (bytes_written != monitor->result_size)
453bf215546Sopenharmony_ci      return false;
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   /* copy metrics into the batch result */
456bf215546Sopenharmony_ci   for (int i = 0; i < monitor->num_active_counters; ++i) {
457bf215546Sopenharmony_ci      int current_counter = monitor->active_counters[i];
458bf215546Sopenharmony_ci      const struct intel_perf_query_info *info =
459bf215546Sopenharmony_ci         intel_perf_query_info(monitor->query);
460bf215546Sopenharmony_ci      const struct intel_perf_query_counter *counter =
461bf215546Sopenharmony_ci         &info->counters[current_counter];
462bf215546Sopenharmony_ci      assert(intel_perf_query_counter_get_size(counter));
463bf215546Sopenharmony_ci      switch (counter->data_type) {
464bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
465bf215546Sopenharmony_ci         result[i].u64 = *(uint64_t*)(monitor->result_buffer + counter->offset);
466bf215546Sopenharmony_ci         break;
467bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
468bf215546Sopenharmony_ci         result[i].f = *(float*)(monitor->result_buffer + counter->offset);
469bf215546Sopenharmony_ci         break;
470bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
471bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
472bf215546Sopenharmony_ci         result[i].u64 = *(uint32_t*)(monitor->result_buffer + counter->offset);
473bf215546Sopenharmony_ci         break;
474bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE: {
475bf215546Sopenharmony_ci         double v = *(double*)(monitor->result_buffer + counter->offset);
476bf215546Sopenharmony_ci         result[i].f = v;
477bf215546Sopenharmony_ci         break;
478bf215546Sopenharmony_ci      }
479bf215546Sopenharmony_ci      default:
480bf215546Sopenharmony_ci         unreachable("unexpected counter data type");
481bf215546Sopenharmony_ci      }
482bf215546Sopenharmony_ci   }
483bf215546Sopenharmony_ci   return true;
484bf215546Sopenharmony_ci}
485