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/u_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 */
40 static void
measure_batch_free(struct intel_measure_batch * base)41 measure_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
48 void
iris_init_screen_measure(struct iris_screen * screen)49 iris_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 measure_device->type = INTEL_MEASURE_DEVICE_OGL;
55 intel_measure_init(measure_device);
56 measure_device->release_batch = &measure_batch_free;
57 struct intel_measure_config *config = measure_device->config;
58 if (config == NULL)
59 return;
60
61 /* the final member of intel_measure_ringbuffer is a zero-length array of
62 * intel_measure_buffered_result objects. Allocate additional space for
63 * the buffered objects based on the run-time configurable buffer_size
64 */
65 const size_t rb_bytes = sizeof(struct intel_measure_ringbuffer) +
66 config->buffer_size * sizeof(struct intel_measure_buffered_result);
67 struct intel_measure_ringbuffer *rb = rzalloc_size(screen, rb_bytes);
68 measure_device->ringbuffer = rb;
69 }
70
71 static struct intel_measure_config *
config_from_screen(struct iris_screen * screen)72 config_from_screen(struct iris_screen *screen)
73 {
74 return screen->measure.config;
75 }
76
77 static struct intel_measure_config *
config_from_context(struct iris_context * ice)78 config_from_context(struct iris_context *ice)
79 {
80 return ((struct iris_screen *) ice->ctx.screen)->measure.config;
81 }
82
83 void
iris_destroy_screen_measure(struct iris_screen * screen)84 iris_destroy_screen_measure(struct iris_screen *screen)
85 {
86 if (!config_from_screen(screen))
87 return;
88
89 struct intel_measure_device *measure_device = &screen->measure;
90
91 if (measure_device->config->file &&
92 measure_device->config->file != stderr)
93 fclose(screen->measure.config->file);
94
95 ralloc_free(measure_device->ringbuffer);
96 measure_device->ringbuffer = NULL;
97 }
98
99
100 void
iris_init_batch_measure(struct iris_context * ice,struct iris_batch * batch)101 iris_init_batch_measure(struct iris_context *ice, struct iris_batch *batch)
102 {
103 const struct intel_measure_config *config = config_from_context(ice);
104 struct iris_screen *screen = batch->screen;
105 struct iris_bufmgr *bufmgr = screen->bufmgr;
106
107 if (!config)
108 return;
109
110 /* the final member of iris_measure_batch is a zero-length array of
111 * intel_measure_snapshot objects. Create additional space for the
112 * snapshot objects based on the run-time configurable batch_size
113 */
114 const size_t batch_bytes = sizeof(struct iris_measure_batch) +
115 config->batch_size * sizeof(struct intel_measure_snapshot);
116 assert(batch->measure == NULL);
117 batch->measure = malloc(batch_bytes);
118 memset(batch->measure, 0, batch_bytes);
119 struct iris_measure_batch *measure = batch->measure;
120
121 measure->bo = iris_bo_alloc(bufmgr, "measure",
122 config->batch_size * sizeof(uint64_t), 8,
123 IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED);
124 measure->base.timestamps = iris_bo_map(NULL, measure->bo, MAP_READ);
125 measure->base.renderpass =
126 (uintptr_t)util_hash_crc32(&ice->state.framebuffer,
127 sizeof(ice->state.framebuffer));
128 }
129
130 void
iris_destroy_batch_measure(struct iris_measure_batch * batch)131 iris_destroy_batch_measure(struct iris_measure_batch *batch)
132 {
133 if (!batch)
134 return;
135 iris_bo_unmap(batch->bo);
136 iris_bo_unreference(batch->bo);
137 batch->bo = NULL;
138 free(batch);
139 }
140
141 static uint32_t
fetch_hash(const struct iris_uncompiled_shader * uncompiled)142 fetch_hash(const struct iris_uncompiled_shader *uncompiled)
143 {
144 return (uncompiled) ? uncompiled->source_hash : 0;
145 }
146
147 static void
measure_start_snapshot(struct iris_context * ice,struct iris_batch * batch,enum intel_measure_snapshot_type type,const char * event_name,uint32_t count)148 measure_start_snapshot(struct iris_context *ice,
149 struct iris_batch *batch,
150 enum intel_measure_snapshot_type type,
151 const char *event_name,
152 uint32_t count)
153 {
154 struct intel_measure_batch *measure_batch = &batch->measure->base;
155 const struct intel_measure_config *config = config_from_context(ice);
156 const struct iris_screen *screen = (void *) ice->ctx.screen;
157 const unsigned screen_frame = screen->measure.frame;
158
159 /* if the command buffer is not associated with a frame, associate it with
160 * the most recent acquired frame
161 */
162 if (measure_batch->frame == 0)
163 measure_batch->frame = screen_frame;
164
165 uintptr_t renderpass = measure_batch->renderpass;
166
167 if (measure_batch->index == config->batch_size) {
168 /* Snapshot buffer is full. The batch must be flushed before additional
169 * snapshots can be taken.
170 */
171 static bool warned = false;
172 if (unlikely(!warned)) {
173 fprintf(config->file,
174 "WARNING: batch size exceeds INTEL_MEASURE limit: %d. "
175 "Data has been dropped. "
176 "Increase setting with INTEL_MEASURE=batch_size={count}\n",
177 config->batch_size);
178 warned = true;
179 }
180 return;
181 }
182
183 unsigned index = measure_batch->index++;
184 assert(index < config->batch_size);
185 if (event_name == NULL)
186 event_name = intel_measure_snapshot_string(type);
187
188 if(config->cpu_measure) {
189 intel_measure_print_cpu_result(measure_batch->frame,
190 measure_batch->batch_count,
191 measure_batch->batch_size,
192 index/2,
193 measure_batch->event_count,
194 count,
195 event_name);
196 return;
197 }
198
199 iris_emit_pipe_control_write(batch, "measurement snapshot",
200 PIPE_CONTROL_WRITE_TIMESTAMP |
201 PIPE_CONTROL_CS_STALL,
202 batch->measure->bo, index * sizeof(uint64_t), 0ull);
203
204 struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]);
205 memset(snapshot, 0, sizeof(*snapshot));
206 snapshot->type = type;
207 snapshot->count = (unsigned) count;
208 snapshot->event_count = measure_batch->event_count;
209 snapshot->event_name = event_name;
210 snapshot->renderpass = renderpass;
211
212 if (type == INTEL_SNAPSHOT_COMPUTE) {
213 snapshot->cs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_COMPUTE]);
214 } else if (type == INTEL_SNAPSHOT_DRAW) {
215 snapshot->vs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_VERTEX]);
216 snapshot->tcs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL]);
217 snapshot->tes = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL]);
218 snapshot->gs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_GEOMETRY]);
219 snapshot->fs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_FRAGMENT]);
220 }
221 }
222
223 static void
measure_end_snapshot(struct iris_batch * batch,uint32_t event_count)224 measure_end_snapshot(struct iris_batch *batch,
225 uint32_t event_count)
226 {
227 struct intel_measure_batch *measure_batch = &batch->measure->base;
228 const struct intel_measure_config *config = config_from_context(batch->ice);
229
230 unsigned index = measure_batch->index++;
231 assert(index % 2 == 1);
232 if(config->cpu_measure)
233 return;
234
235 iris_emit_pipe_control_write(batch, "measurement snapshot",
236 PIPE_CONTROL_WRITE_TIMESTAMP |
237 PIPE_CONTROL_CS_STALL,
238 batch->measure->bo,
239 index * sizeof(uint64_t), 0ull);
240
241 struct intel_measure_snapshot *snapshot = &(measure_batch->snapshots[index]);
242 memset(snapshot, 0, sizeof(*snapshot));
243 snapshot->type = INTEL_SNAPSHOT_END;
244 snapshot->event_count = event_count;
245 }
246
247 static bool
state_changed(const struct iris_context * ice,const struct iris_batch * batch,enum intel_measure_snapshot_type type)248 state_changed(const struct iris_context *ice,
249 const struct iris_batch *batch,
250 enum intel_measure_snapshot_type type)
251 {
252 uintptr_t vs=0, tcs=0, tes=0, gs=0, fs=0, cs=0;
253
254 if (type == INTEL_SNAPSHOT_COMPUTE) {
255 cs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_COMPUTE]);
256 } else if (type == INTEL_SNAPSHOT_DRAW) {
257 vs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_VERTEX]);
258 tcs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL]);
259 tes = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL]);
260 gs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_GEOMETRY]);
261 fs = fetch_hash(ice->shaders.uncompiled[MESA_SHADER_FRAGMENT]);
262 }
263 /* else blorp, all programs NULL */
264
265 return intel_measure_state_changed(&batch->measure->base,
266 vs, tcs, tes, gs, fs, cs, 0, 0);
267 }
268
269 static void
iris_measure_renderpass(struct iris_context * ice)270 iris_measure_renderpass(struct iris_context *ice)
271 {
272 const struct intel_measure_config *config = config_from_context(ice);
273 struct intel_measure_batch *batch =
274 &ice->batches[IRIS_BATCH_RENDER].measure->base;
275
276 if (!config)
277 return;
278 uint32_t framebuffer_crc = util_hash_crc32(&ice->state.framebuffer,
279 sizeof(ice->state.framebuffer));
280 if (framebuffer_crc == batch->renderpass)
281 return;
282 bool filtering = config->flags & INTEL_MEASURE_RENDERPASS;
283 if (filtering && batch->index % 2 == 1) {
284 /* snapshot for previous renderpass was not ended */
285 measure_end_snapshot(&ice->batches[IRIS_BATCH_RENDER],
286 batch->event_count);
287 batch->event_count = 0;
288 }
289
290 batch->renderpass = framebuffer_crc;
291 }
292
293 void
_iris_measure_snapshot(struct iris_context * ice,struct iris_batch * batch,enum intel_measure_snapshot_type type,const struct pipe_draw_info * draw,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * sc)294 _iris_measure_snapshot(struct iris_context *ice,
295 struct iris_batch *batch,
296 enum intel_measure_snapshot_type type,
297 const struct pipe_draw_info *draw,
298 const struct pipe_draw_indirect_info *indirect,
299 const struct pipe_draw_start_count_bias *sc)
300 {
301
302 const struct intel_measure_config *config = config_from_context(ice);
303 struct intel_measure_batch* measure_batch = &batch->measure->base;
304
305 assert(config);
306 if (!config->enabled)
307 return;
308 if (measure_batch == NULL)
309 return;
310
311 assert(type != INTEL_SNAPSHOT_END);
312 iris_measure_renderpass(ice);
313
314 static unsigned batch_count = 0;
315 if (measure_batch->event_count == 0)
316 measure_batch->batch_count = p_atomic_inc_return(&batch_count);
317
318 if (!state_changed(ice, batch, type)) {
319 /* filter out this event */
320 return;
321 }
322
323 /* increment event count */
324 ++measure_batch->event_count;
325 if (measure_batch->event_count == 1 ||
326 measure_batch->event_count == config->event_interval + 1) {
327 /* the first event of an interval */
328 if (measure_batch->index % 2) {
329 /* end the previous event */
330 measure_end_snapshot(batch, measure_batch->event_count - 1);
331 }
332 measure_batch->event_count = 1;
333
334 const char *event_name = NULL;
335 int count = 0;
336 if (sc)
337 count = sc->count;
338
339 if (draw != NULL) {
340 const struct shader_info *fs_info =
341 iris_get_shader_info(ice, MESA_SHADER_FRAGMENT);
342 if (fs_info && fs_info->name && strncmp(fs_info->name, "st/", 2) == 0) {
343 event_name = fs_info->name;
344 } else if (indirect) {
345 event_name = "DrawIndirect";
346 if (indirect->count_from_stream_output) {
347 event_name = "DrawTransformFeedback";
348 }
349 }
350 else if (draw->index_size)
351 event_name = "DrawElements";
352 else
353 event_name = "DrawArrays";
354 count = count * (draw->instance_count ? draw->instance_count : 1);
355 }
356
357 measure_start_snapshot(ice, batch, type, event_name, count);
358 return;
359 }
360 }
361
362 void
iris_destroy_ctx_measure(struct iris_context * ice)363 iris_destroy_ctx_measure(struct iris_context *ice)
364 {
365 /* All outstanding snapshots must be collected before the context is
366 * destroyed.
367 */
368 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
369 intel_measure_gather(&screen->measure, screen->devinfo);
370 }
371
372 void
iris_measure_batch_end(struct iris_context * ice,struct iris_batch * batch)373 iris_measure_batch_end(struct iris_context *ice, struct iris_batch *batch)
374 {
375 const struct intel_measure_config *config = config_from_context(ice);
376 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
377 struct iris_measure_batch *iris_measure_batch = batch->measure;
378 struct intel_measure_batch *measure_batch = &iris_measure_batch->base;
379 struct intel_measure_device *measure_device = &screen->measure;
380
381 if (!config)
382 return;
383 if (!config->enabled)
384 return;
385
386 assert(measure_batch);
387 assert(measure_device);
388
389 if (measure_batch->index % 2) {
390 /* We hit the end of the batch, but never terminated our section of
391 * drawing with the same render target or shaders. End it now.
392 */
393 measure_end_snapshot(batch, measure_batch->event_count);
394 }
395
396 if (measure_batch->index == 0)
397 return;
398
399 /* At this point, total_chained_batch_size is not yet updated because the
400 * batch_end measurement is within the batch and the batch is not quite
401 * ended yet (it'll be just after this function call). So combined the
402 * already summed total_chained_batch_size with whatever was written in the
403 * current batch BO.
404 */
405 measure_batch->batch_size = batch->total_chained_batch_size +
406 iris_batch_bytes_used(batch);
407
408 /* enqueue snapshot for gathering */
409 pthread_mutex_lock(&measure_device->mutex);
410 list_addtail(&iris_measure_batch->base.link, &measure_device->queued_snapshots);
411 batch->measure = NULL;
412 pthread_mutex_unlock(&measure_device->mutex);
413 /* init new measure_batch */
414 iris_init_batch_measure(ice, batch);
415
416 static int interval = 0;
417 if (++interval > 10) {
418 intel_measure_gather(measure_device, screen->devinfo);
419 interval = 0;
420 }
421 }
422
423 void
iris_measure_frame_end(struct iris_context * ice)424 iris_measure_frame_end(struct iris_context *ice)
425 {
426 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
427 struct intel_measure_device *measure_device = &screen->measure;
428 const struct intel_measure_config *config = measure_device->config;
429
430 if (!config)
431 return;
432
433 /* increment frame counter */
434 intel_measure_frame_transition(p_atomic_inc_return(&measure_device->frame));
435
436 intel_measure_gather(measure_device, screen->devinfo);
437 }
438