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 "iris_monitor.h"
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include <xf86drm.h>
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "iris_screen.h"
28bf215546Sopenharmony_ci#include "iris_context.h"
29bf215546Sopenharmony_ci#include "iris_perf.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_cistruct iris_monitor_object {
32bf215546Sopenharmony_ci   int num_active_counters;
33bf215546Sopenharmony_ci   int *active_counters;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci   size_t result_size;
36bf215546Sopenharmony_ci   unsigned char *result_buffer;
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci   struct intel_perf_query_object *query;
39bf215546Sopenharmony_ci};
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ciint
42bf215546Sopenharmony_ciiris_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
43bf215546Sopenharmony_ci                      struct pipe_driver_query_info *info)
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci   struct iris_screen *screen = (struct iris_screen *)pscreen;
46bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = screen->perf_cfg;
47bf215546Sopenharmony_ci   assert(perf_cfg);
48bf215546Sopenharmony_ci   if (!perf_cfg)
49bf215546Sopenharmony_ci      return 0;
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   if (!info) {
52bf215546Sopenharmony_ci      /* return the number of metrics */
53bf215546Sopenharmony_ci      return perf_cfg->n_counters;
54bf215546Sopenharmony_ci   }
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   struct intel_perf_query_counter_info *counter_info = &perf_cfg->counter_infos[index];
57bf215546Sopenharmony_ci   struct intel_perf_query_info *query_info =
58bf215546Sopenharmony_ci      &perf_cfg->queries[intel_perf_query_counter_info_first_query(counter_info)];
59bf215546Sopenharmony_ci   struct intel_perf_query_counter *counter = counter_info->counter;
60bf215546Sopenharmony_ci   struct intel_perf_query_result results;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   intel_perf_query_result_clear(&results);
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   info->group_id = counter_info->location.group_idx;
65bf215546Sopenharmony_ci   info->name = counter->name;
66bf215546Sopenharmony_ci   info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   if (counter->type == INTEL_PERF_COUNTER_TYPE_THROUGHPUT)
69bf215546Sopenharmony_ci      info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE;
70bf215546Sopenharmony_ci   else
71bf215546Sopenharmony_ci      info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
72bf215546Sopenharmony_ci   switch (counter->data_type) {
73bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
74bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_UINT32: {
75bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_UINT;
76bf215546Sopenharmony_ci      uint64_t val =
77bf215546Sopenharmony_ci         counter->oa_counter_max_uint64 ?
78bf215546Sopenharmony_ci         counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
79bf215546Sopenharmony_ci      assert(val <= UINT32_MAX);
80bf215546Sopenharmony_ci      info->max_value.u32 = (uint32_t)val;
81bf215546Sopenharmony_ci      break;
82bf215546Sopenharmony_ci   }
83bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
84bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
85bf215546Sopenharmony_ci      info->max_value.u64 =
86bf215546Sopenharmony_ci         counter->oa_counter_max_uint64 ?
87bf215546Sopenharmony_ci         counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
88bf215546Sopenharmony_ci      break;
89bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
90bf215546Sopenharmony_ci   case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE:
91bf215546Sopenharmony_ci      info->type = PIPE_DRIVER_QUERY_TYPE_FLOAT;
92bf215546Sopenharmony_ci      info->max_value.f =
93bf215546Sopenharmony_ci         counter->oa_counter_max_float ?
94bf215546Sopenharmony_ci         counter->oa_counter_max_float(perf_cfg, query_info, &results) : 0.0f;
95bf215546Sopenharmony_ci      break;
96bf215546Sopenharmony_ci   default:
97bf215546Sopenharmony_ci      assert(false);
98bf215546Sopenharmony_ci      break;
99bf215546Sopenharmony_ci   }
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   /* indicates that this is an OA query, not a pipeline statistics query */
102bf215546Sopenharmony_ci   info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
103bf215546Sopenharmony_ci   return 1;
104bf215546Sopenharmony_ci}
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_cistatic bool
107bf215546Sopenharmony_ciiris_monitor_init_metrics(struct iris_screen *screen)
108bf215546Sopenharmony_ci{
109bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = intel_perf_new(screen);
110bf215546Sopenharmony_ci   if (unlikely(!perf_cfg))
111bf215546Sopenharmony_ci      return false;
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   screen->perf_cfg = perf_cfg;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   iris_perf_init_vtbl(perf_cfg);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   intel_perf_init_metrics(perf_cfg, &screen->devinfo, screen->fd,
118bf215546Sopenharmony_ci                           true /* pipeline stats*/,
119bf215546Sopenharmony_ci                           true /* register snapshots */);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   return perf_cfg->n_counters > 0;
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ciint
125bf215546Sopenharmony_ciiris_get_monitor_group_info(struct pipe_screen *pscreen,
126bf215546Sopenharmony_ci                            unsigned group_index,
127bf215546Sopenharmony_ci                            struct pipe_driver_query_group_info *info)
128bf215546Sopenharmony_ci{
129bf215546Sopenharmony_ci   struct iris_screen *screen = (struct iris_screen *)pscreen;
130bf215546Sopenharmony_ci   if (!screen->perf_cfg) {
131bf215546Sopenharmony_ci      if (!iris_monitor_init_metrics(screen))
132bf215546Sopenharmony_ci         return 0;
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   const struct intel_perf_config *perf_cfg = screen->perf_cfg;
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   if (!info) {
138bf215546Sopenharmony_ci      /* return the count that can be queried */
139bf215546Sopenharmony_ci      return perf_cfg->n_queries;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   if (group_index >= perf_cfg->n_queries) {
143bf215546Sopenharmony_ci      /* out of range */
144bf215546Sopenharmony_ci      return 0;
145bf215546Sopenharmony_ci   }
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   struct intel_perf_query_info *query = &perf_cfg->queries[group_index];
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   info->name = query->name;
150bf215546Sopenharmony_ci   info->max_active_queries = query->n_counters;
151bf215546Sopenharmony_ci   info->num_queries = query->n_counters;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   return 1;
154bf215546Sopenharmony_ci}
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_cistatic void
157bf215546Sopenharmony_ciiris_init_monitor_ctx(struct iris_context *ice)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci   struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   ice->perf_ctx = intel_perf_new_context(ice);
162bf215546Sopenharmony_ci   if (unlikely(!ice->perf_ctx))
163bf215546Sopenharmony_ci      return;
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
166bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = screen->perf_cfg;
167bf215546Sopenharmony_ci   intel_perf_init_context(perf_ctx,
168bf215546Sopenharmony_ci                         perf_cfg,
169bf215546Sopenharmony_ci                         ice,
170bf215546Sopenharmony_ci                         ice,
171bf215546Sopenharmony_ci                         screen->bufmgr,
172bf215546Sopenharmony_ci                         &screen->devinfo,
173bf215546Sopenharmony_ci                         ice->batches[IRIS_BATCH_RENDER].ctx_id,
174bf215546Sopenharmony_ci                         screen->fd);
175bf215546Sopenharmony_ci}
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci/* entry point for GenPerfMonitorsAMD */
178bf215546Sopenharmony_cistruct iris_monitor_object *
179bf215546Sopenharmony_ciiris_create_monitor_object(struct iris_context *ice,
180bf215546Sopenharmony_ci                           unsigned num_queries,
181bf215546Sopenharmony_ci                           unsigned *query_types)
182bf215546Sopenharmony_ci{
183bf215546Sopenharmony_ci   struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
184bf215546Sopenharmony_ci   struct intel_perf_config *perf_cfg = screen->perf_cfg;
185bf215546Sopenharmony_ci   struct intel_perf_query_object *query_obj = NULL;
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   /* initialize perf context if this has not already been done.  This
188bf215546Sopenharmony_ci    * function is the first entry point that carries the gl context.
189bf215546Sopenharmony_ci    */
190bf215546Sopenharmony_ci   if (ice->perf_ctx == NULL) {
191bf215546Sopenharmony_ci      iris_init_monitor_ctx(ice);
192bf215546Sopenharmony_ci   }
193bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   assert(num_queries > 0);
196bf215546Sopenharmony_ci   int query_index = query_types[0] - PIPE_QUERY_DRIVER_SPECIFIC;
197bf215546Sopenharmony_ci   assert(query_index <= perf_cfg->n_counters);
198bf215546Sopenharmony_ci   const int group = perf_cfg->counter_infos[query_index].location.group_idx;
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   struct iris_monitor_object *monitor =
201bf215546Sopenharmony_ci      calloc(1, sizeof(struct iris_monitor_object));
202bf215546Sopenharmony_ci   if (unlikely(!monitor))
203bf215546Sopenharmony_ci      goto allocation_failure;
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   monitor->num_active_counters = num_queries;
206bf215546Sopenharmony_ci   monitor->active_counters = calloc(num_queries, sizeof(int));
207bf215546Sopenharmony_ci   if (unlikely(!monitor->active_counters))
208bf215546Sopenharmony_ci      goto allocation_failure;
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   for (int i = 0; i < num_queries; ++i) {
211bf215546Sopenharmony_ci      unsigned current_query = query_types[i];
212bf215546Sopenharmony_ci      unsigned current_query_index = current_query - PIPE_QUERY_DRIVER_SPECIFIC;
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci      /* all queries must be in the same group */
215bf215546Sopenharmony_ci      assert(current_query_index <= perf_cfg->n_counters);
216bf215546Sopenharmony_ci      assert(perf_cfg->counter_infos[current_query_index].location.group_idx == group);
217bf215546Sopenharmony_ci      monitor->active_counters[i] =
218bf215546Sopenharmony_ci         perf_cfg->counter_infos[current_query_index].location.counter_idx;
219bf215546Sopenharmony_ci   }
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   /* create the intel_perf_query */
222bf215546Sopenharmony_ci   query_obj = intel_perf_new_query(perf_ctx, group);
223bf215546Sopenharmony_ci   if (unlikely(!query_obj))
224bf215546Sopenharmony_ci      goto allocation_failure;
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   monitor->query = query_obj;
227bf215546Sopenharmony_ci   monitor->result_size = perf_cfg->queries[group].data_size;
228bf215546Sopenharmony_ci   monitor->result_buffer = calloc(1, monitor->result_size);
229bf215546Sopenharmony_ci   if (unlikely(!monitor->result_buffer))
230bf215546Sopenharmony_ci      goto allocation_failure;
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   return monitor;
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ciallocation_failure:
235bf215546Sopenharmony_ci   if (monitor) {
236bf215546Sopenharmony_ci      free(monitor->active_counters);
237bf215546Sopenharmony_ci      free(monitor->result_buffer);
238bf215546Sopenharmony_ci   }
239bf215546Sopenharmony_ci   free(query_obj);
240bf215546Sopenharmony_ci   free(monitor);
241bf215546Sopenharmony_ci   return NULL;
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_civoid
245bf215546Sopenharmony_ciiris_destroy_monitor_object(struct pipe_context *ctx,
246bf215546Sopenharmony_ci                            struct iris_monitor_object *monitor)
247bf215546Sopenharmony_ci{
248bf215546Sopenharmony_ci   struct iris_context *ice = (struct iris_context *)ctx;
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   intel_perf_delete_query(ice->perf_ctx, monitor->query);
251bf215546Sopenharmony_ci   free(monitor->result_buffer);
252bf215546Sopenharmony_ci   monitor->result_buffer = NULL;
253bf215546Sopenharmony_ci   free(monitor->active_counters);
254bf215546Sopenharmony_ci   monitor->active_counters = NULL;
255bf215546Sopenharmony_ci   free(monitor);
256bf215546Sopenharmony_ci}
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_cibool
259bf215546Sopenharmony_ciiris_begin_monitor(struct pipe_context *ctx,
260bf215546Sopenharmony_ci                   struct iris_monitor_object *monitor)
261bf215546Sopenharmony_ci{
262bf215546Sopenharmony_ci   struct iris_context *ice = (void *) ctx;
263bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   return intel_perf_begin_query(perf_ctx, monitor->query);
266bf215546Sopenharmony_ci}
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_cibool
269bf215546Sopenharmony_ciiris_end_monitor(struct pipe_context *ctx,
270bf215546Sopenharmony_ci                 struct iris_monitor_object *monitor)
271bf215546Sopenharmony_ci{
272bf215546Sopenharmony_ci   struct iris_context *ice = (void *) ctx;
273bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   intel_perf_end_query(perf_ctx, monitor->query);
276bf215546Sopenharmony_ci   return true;
277bf215546Sopenharmony_ci}
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_cibool
280bf215546Sopenharmony_ciiris_get_monitor_result(struct pipe_context *ctx,
281bf215546Sopenharmony_ci                        struct iris_monitor_object *monitor,
282bf215546Sopenharmony_ci                        bool wait,
283bf215546Sopenharmony_ci                        union pipe_numeric_type_union *result)
284bf215546Sopenharmony_ci{
285bf215546Sopenharmony_ci   struct iris_context *ice = (void *) ctx;
286bf215546Sopenharmony_ci   struct intel_perf_context *perf_ctx = ice->perf_ctx;
287bf215546Sopenharmony_ci   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   bool monitor_ready =
290bf215546Sopenharmony_ci      intel_perf_is_query_ready(perf_ctx, monitor->query, batch);
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   if (!monitor_ready) {
293bf215546Sopenharmony_ci      if (!wait)
294bf215546Sopenharmony_ci         return false;
295bf215546Sopenharmony_ci      intel_perf_wait_query(perf_ctx, monitor->query, batch);
296bf215546Sopenharmony_ci   }
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   assert(intel_perf_is_query_ready(perf_ctx, monitor->query, batch));
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   unsigned bytes_written;
301bf215546Sopenharmony_ci   intel_perf_get_query_data(perf_ctx, monitor->query, batch,
302bf215546Sopenharmony_ci                           monitor->result_size,
303bf215546Sopenharmony_ci                           (unsigned*) monitor->result_buffer,
304bf215546Sopenharmony_ci                           &bytes_written);
305bf215546Sopenharmony_ci   if (bytes_written != monitor->result_size)
306bf215546Sopenharmony_ci      return false;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   /* copy metrics into the batch result */
309bf215546Sopenharmony_ci   for (int i = 0; i < monitor->num_active_counters; ++i) {
310bf215546Sopenharmony_ci      int current_counter = monitor->active_counters[i];
311bf215546Sopenharmony_ci      const struct intel_perf_query_info *info =
312bf215546Sopenharmony_ci         intel_perf_query_info(monitor->query);
313bf215546Sopenharmony_ci      const struct intel_perf_query_counter *counter =
314bf215546Sopenharmony_ci         &info->counters[current_counter];
315bf215546Sopenharmony_ci      assert(intel_perf_query_counter_get_size(counter));
316bf215546Sopenharmony_ci      switch (counter->data_type) {
317bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
318bf215546Sopenharmony_ci         result[i].u64 = *(uint64_t*)(monitor->result_buffer + counter->offset);
319bf215546Sopenharmony_ci         break;
320bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
321bf215546Sopenharmony_ci         result[i].f = *(float*)(monitor->result_buffer + counter->offset);
322bf215546Sopenharmony_ci         break;
323bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
324bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
325bf215546Sopenharmony_ci         result[i].u64 = *(uint32_t*)(monitor->result_buffer + counter->offset);
326bf215546Sopenharmony_ci         break;
327bf215546Sopenharmony_ci      case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE: {
328bf215546Sopenharmony_ci         double v = *(double*)(monitor->result_buffer + counter->offset);
329bf215546Sopenharmony_ci         result[i].f = v;
330bf215546Sopenharmony_ci         break;
331bf215546Sopenharmony_ci      }
332bf215546Sopenharmony_ci      default:
333bf215546Sopenharmony_ci         unreachable("unexpected counter data type");
334bf215546Sopenharmony_ci      }
335bf215546Sopenharmony_ci   }
336bf215546Sopenharmony_ci   return true;
337bf215546Sopenharmony_ci}
338