1/*
2 * Copyright © 2019 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23/**
24 * @file iris_measure.c
25 */
26
27#include <stdio.h>
28#include "util/debug.h"
29#include "util/list.h"
30#include "util/crc32.h"
31#include "iris_context.h"
32#include "iris_defines.h"
33#include "compiler/shader_info.h"
34
35/**
36 * This callback is registered with intel_measure.  It will be called when
37 * snapshot data has been fully collected, so iris can release the associated
38 * resources.
39 */
40static void
41measure_batch_free(struct intel_measure_batch *base)
42{
43   struct iris_measure_batch *batch =
44      container_of(base, struct iris_measure_batch, base);
45   iris_destroy_batch_measure(batch);
46}
47
48void
49iris_init_screen_measure(struct iris_screen *screen)
50{
51   struct intel_measure_device *measure_device = &screen->measure;
52
53   memset(measure_device, 0, sizeof(*measure_device));
54   intel_measure_init(measure_device);
55   measure_device->release_batch = &measure_batch_free;
56   struct intel_measure_config *config = measure_device->config;
57   if (config == NULL)
58      return;
59
60   /* the final member of intel_measure_ringbuffer is a zero-length array of
61    * intel_measure_buffered_result objects.  Allocate additional space for
62    * the buffered objects based on the run-time configurable buffer_size
63    */
64   const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) +
65      config->buffer_size * sizeof(struct intel_measure_buffered_result);
66   struct intel_measure_ringbuffer *rb = rzalloc_size(screen, rb_bytes);
67   measure_device->ringbuffer = rb;
68}
69
70static struct intel_measure_config *
71config_from_screen(struct iris_screen *screen)
72{
73   return screen->measure.config;
74}
75
76static struct intel_measure_config *
77config_from_context(struct iris_context *ice)
78{
79   return ((struct iris_screen *) ice->ctx.screen)->measure.config;
80}
81
82void
83iris_destroy_screen_measure(struct iris_screen *screen)
84{
85   if (!config_from_screen(screen))
86      return;
87
88   struct intel_measure_device *measure_device = &screen->measure;
89
90   if (measure_device->config->file &&
91       measure_device->config->file != stderr)
92      fclose(screen->measure.config->file);
93
94   ralloc_free(measure_device->ringbuffer);
95   measure_device->ringbuffer = NULL;
96}
97
98
99void
100iris_init_batch_measure(struct iris_context *ice, struct iris_batch *batch)
101{
102   const struct intel_measure_config *config = config_from_context(ice);
103   struct iris_screen *screen = batch->screen;
104   struct iris_bufmgr *bufmgr = screen->bufmgr;
105
106   if (!config)
107      return;
108
109   /* the final member of iris_measure_batch is a zero-length array of
110    * intel_measure_snapshot objects.  Create additional space for the
111    * snapshot objects based on the run-time configurable batch_size
112    */
113   const size_t batch_bytes = sizeof(struct iris_measure_batch) +
114      config->batch_size * sizeof(struct intel_measure_snapshot);
115   assert(batch->measure == NULL);
116   batch->measure = malloc(batch_bytes);
117   memset(batch->measure, 0, batch_bytes);
118   struct iris_measure_batch *measure = batch->measure;
119
120   measure->bo = iris_bo_alloc(bufmgr, "measure",
121                               config->batch_size * sizeof(uint64_t), 8,
122                               IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED);
123   measure->base.timestamps = iris_bo_map(NULL, measure->bo, MAP_READ);
124   measure->base.framebuffer =
125      (uintptr_t)util_hash_crc32(&ice->state.framebuffer,
126                                 sizeof(ice->state.framebuffer));
127}
128
129void
130iris_destroy_batch_measure(struct iris_measure_batch *batch)
131{
132   if (!batch)
133      return;
134   iris_bo_unmap(batch->bo);
135   iris_bo_unreference(batch->bo);
136   batch->bo = NULL;
137   free(batch);
138}
139
140static void
141measure_start_snapshot(struct iris_context *ice,
142                       struct iris_batch *batch,
143                       enum intel_measure_snapshot_type type,
144                       const char *event_name,
145                       uint32_t count)
146{
147   struct intel_measure_batch *measure_batch = &batch->measure->base;
148   const struct intel_measure_config *config = config_from_context(ice);
149   const struct iris_screen *screen = (void *) ice->ctx.screen;
150   const unsigned screen_frame = screen->measure.frame;
151
152   /* if the command buffer is not associated with a frame, associate it with
153    * the most recent acquired frame
154    */
155   if (measure_batch->frame == 0)
156      measure_batch->frame = screen_frame;
157
158   uintptr_t framebuffer = measure_batch->framebuffer;
159
160   if (measure_batch->index == config->batch_size) {
161      /* Snapshot buffer is full.  The batch must be flushed before additional
162       * snapshots can be taken.
163       */
164      static bool warned = false;
165      if (unlikely(!warned)) {
166         fprintf(config->file,
167                 "WARNING: batch size exceeds INTEL_MEASURE limit: %d. "
168                 "Data has been dropped. "
169                 "Increase setting with INTEL_MEASURE=batch_size={count}\n",
170                 config->batch_size);
171         warned = true;
172      }
173      return;
174   }
175
176   unsigned index = measure_batch->index++;
177   assert(index < config->batch_size);
178   iris_emit_pipe_control_write(batch, "measurement snapshot",
179                                PIPE_CONTROL_WRITE_TIMESTAMP |
180                                PIPE_CONTROL_CS_STALL,
181                                batch->measure->bo, index * sizeof(uint64_t), 0ull);
182   if (event_name == NULL)
183      event_name = intel_measure_snapshot_string(type);
184
185   struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]);
186   memset(snapshot, 0, sizeof(*snapshot));
187   snapshot->type = type;
188   snapshot->count = (unsigned) count;
189   snapshot->event_count = measure_batch->event_count;
190   snapshot->event_name = event_name;
191   snapshot->framebuffer = framebuffer;
192
193   if (type == INTEL_SNAPSHOT_COMPUTE) {
194      snapshot->cs = (uintptr_t) ice->shaders.prog[MESA_SHADER_COMPUTE];
195   } else {
196      snapshot->vs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_VERTEX];
197      snapshot->tcs = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_CTRL];
198      snapshot->tes = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_EVAL];
199      snapshot->gs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_GEOMETRY];
200      snapshot->fs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_FRAGMENT];
201   }
202}
203
204static void
205measure_end_snapshot(struct iris_batch *batch,
206                     uint32_t event_count)
207{
208   struct intel_measure_batch *measure_batch = &batch->measure->base;
209
210   unsigned index = measure_batch->index++;
211   assert(index % 2 == 1);
212
213   iris_emit_pipe_control_write(batch, "measurement snapshot",
214                                PIPE_CONTROL_WRITE_TIMESTAMP |
215                                PIPE_CONTROL_CS_STALL,
216                                batch->measure->bo,
217                                index * sizeof(uint64_t), 0ull);
218
219   struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]);
220   memset(snapshot, 0, sizeof(*snapshot));
221   snapshot->type = INTEL_SNAPSHOT_END;
222   snapshot->event_count = event_count;
223}
224
225static bool
226state_changed(const struct iris_context *ice,
227              const struct iris_batch *batch,
228              enum intel_measure_snapshot_type type)
229{
230   uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0;
231
232   if (type == INTEL_SNAPSHOT_COMPUTE) {
233      cs = (uintptr_t) ice->shaders.prog[MESA_SHADER_COMPUTE];
234   } else if (type == INTEL_SNAPSHOT_DRAW) {
235      vs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_VERTEX];
236      tcs = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_CTRL];
237      tes = (uintptr_t) ice->shaders.prog[MESA_SHADER_TESS_EVAL];
238      gs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_GEOMETRY];
239      fs  = (uintptr_t) ice->shaders.prog[MESA_SHADER_FRAGMENT];
240   }
241   /* else blorp, all programs NULL */
242
243   return intel_measure_state_changed(&batch->measure->base,
244                                      vs, tcs, tes, gs, fs, cs);
245}
246
247static void
248iris_measure_renderpass(struct iris_context *ice)
249{
250   const struct intel_measure_config *config = config_from_context(ice);
251   struct intel_measure_batch *batch =
252      &ice->batches[IRIS_BATCH_RENDER].measure->base;
253
254   if (!config)
255      return;
256   uint32_t framebuffer_crc = util_hash_crc32(&ice->state.framebuffer,
257                                              sizeof(ice->state.framebuffer));
258   if (framebuffer_crc == batch->framebuffer)
259      return;
260   bool filtering = config->flags & INTEL_MEASURE_RENDERPASS;
261   if (filtering && batch->index % 2 == 1) {
262      /* snapshot for previous renderpass was not ended */
263      measure_end_snapshot(&ice->batches[IRIS_BATCH_RENDER],
264                           batch->event_count);
265      batch->event_count = 0;
266   }
267
268   batch->framebuffer = framebuffer_crc;
269}
270
271void
272_iris_measure_snapshot(struct iris_context *ice,
273                       struct iris_batch *batch,
274                       enum intel_measure_snapshot_type type,
275                       const struct pipe_draw_info *draw,
276                       const struct pipe_draw_indirect_info *indirect,
277                       const struct pipe_draw_start_count_bias *sc)
278{
279
280   const struct intel_measure_config *config = config_from_context(ice);
281   struct intel_measure_batch* measure_batch = &batch->measure->base;
282
283   assert(config);
284   if (!config->enabled)
285      return;
286   if (measure_batch == NULL)
287      return;
288
289   assert(type != INTEL_SNAPSHOT_END);
290   iris_measure_renderpass(ice);
291
292   if (!state_changed(ice, batch, type)) {
293      /* filter out this event */
294      return;
295   }
296
297   /* increment event count */
298   ++measure_batch->event_count;
299   if (measure_batch->event_count == 1 ||
300       measure_batch->event_count == config->event_interval + 1) {
301      /* the first event of an interval */
302      if (measure_batch->index % 2) {
303         /* end the previous event */
304         measure_end_snapshot(batch, measure_batch->event_count - 1);
305      }
306      measure_batch->event_count = 1;
307
308      const char *event_name = NULL;
309      int count = 0;
310      if (sc)
311         count = sc->count;
312
313      if (draw != NULL) {
314         const struct shader_info *fs_info =
315            iris_get_shader_info(ice, MESA_SHADER_FRAGMENT);
316         if (fs_info && fs_info->name && strncmp(fs_info->name, "st/", 2) == 0) {
317            event_name = fs_info->name;
318         } else if (indirect) {
319            event_name = "DrawIndirect";
320            if (indirect->count_from_stream_output) {
321               event_name = "DrawTransformFeedback";
322            }
323         }
324         else if (draw->index_size)
325            event_name = "DrawElements";
326         else
327            event_name = "DrawArrays";
328         count = count * (draw->instance_count ? draw->instance_count : 1);
329      }
330
331      measure_start_snapshot(ice, batch, type, event_name, count);
332      return;
333   }
334}
335
336void
337iris_destroy_ctx_measure(struct iris_context *ice)
338{
339   /* All outstanding snapshots must be collected before the context is
340    * destroyed.
341    */
342   struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
343   intel_measure_gather(&screen->measure, &screen->devinfo);
344}
345
346void
347iris_measure_batch_end(struct iris_context *ice, struct iris_batch *batch)
348{
349   const struct intel_measure_config *config = config_from_context(ice);
350   struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
351   struct iris_measure_batch *iris_measure_batch = batch->measure;
352   struct intel_measure_batch *measure_batch = &iris_measure_batch->base;
353   struct intel_measure_device *measure_device = &screen->measure;
354
355   if (!config)
356      return;
357   if (!config->enabled)
358      return;
359
360   assert(measure_batch);
361   assert(measure_device);
362
363   static unsigned batch_count = 0;
364   measure_batch->batch_count = p_atomic_inc_return(&batch_count);
365
366   if (measure_batch->index % 2) {
367      /* We hit the end of the batch, but never terminated our section of
368       * drawing with the same render target or shaders.  End it now.
369       */
370      measure_end_snapshot(batch, measure_batch->event_count);
371   }
372
373   if (measure_batch->index == 0)
374      return;
375
376   /* enqueue snapshot for gathering */
377   pthread_mutex_lock(&measure_device->mutex);
378   list_addtail(&iris_measure_batch->base.link, &measure_device->queued_snapshots);
379   batch->measure = NULL;
380   pthread_mutex_unlock(&measure_device->mutex);
381   /* init new measure_batch */
382   iris_init_batch_measure(ice, batch);
383
384   static int interval = 0;
385   if (++interval > 10) {
386      intel_measure_gather(measure_device, &screen->devinfo);
387      interval = 0;
388   }
389}
390
391void
392iris_measure_frame_end(struct iris_context *ice)
393{
394   struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
395   struct intel_measure_device *measure_device = &screen->measure;
396   const struct intel_measure_config *config = measure_device->config;
397
398   if (!config)
399      return;
400
401   /* increment frame counter */
402   intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));
403
404   intel_measure_gather(measure_device, &screen->devinfo);
405}
406