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 */
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 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
70 static struct intel_measure_config *
config_from_screen(struct iris_screen * screen)71 config_from_screen(struct iris_screen *screen)
72 {
73 return screen->measure.config;
74 }
75
76 static struct intel_measure_config *
config_from_context(struct iris_context * ice)77 config_from_context(struct iris_context *ice)
78 {
79 return ((struct iris_screen *) ice->ctx.screen)->measure.config;
80 }
81
82 void
iris_destroy_screen_measure(struct iris_screen * screen)83 iris_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
99 void
iris_init_batch_measure(struct iris_context * ice,struct iris_batch * batch)100 iris_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
129 void
iris_destroy_batch_measure(struct iris_measure_batch * batch)130 iris_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
140 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)141 measure_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
204 static void
measure_end_snapshot(struct iris_batch * batch,uint32_t event_count)205 measure_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
225 static bool
state_changed(const struct iris_context * ice,const struct iris_batch * batch,enum intel_measure_snapshot_type type)226 state_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
247 static void
iris_measure_renderpass(struct iris_context * ice)248 iris_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
271 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)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
336 void
iris_destroy_ctx_measure(struct iris_context * ice)337 iris_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
346 void
iris_measure_batch_end(struct iris_context * ice,struct iris_batch * batch)347 iris_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
391 void
iris_measure_frame_end(struct iris_context * ice)392 iris_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