~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/intel/common/intel_measure.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2020 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 intel_measure.c
25
 
 */
26
 
 
27
 
#include "intel_measure.h"
28
 
 
29
 
#include <errno.h>
30
 
#include <fcntl.h>
31
 
#include <stdlib.h>
32
 
#include <string.h>
33
 
#include <sys/stat.h>
34
 
#include <sys/types.h>
35
 
#include <unistd.h>
36
 
 
37
 
#define __STDC_FORMAT_MACROS 1
38
 
#include <inttypes.h>
39
 
 
40
 
#include "dev/intel_device_info.h"
41
 
#include "util/debug.h"
42
 
#include "util/macros.h"
43
 
#include "util/u_debug.h"
44
 
 
45
 
 
46
 
static const struct debug_control debug_control[] = {
47
 
   { "draw",            INTEL_MEASURE_DRAW       },
48
 
   { "rt",              INTEL_MEASURE_RENDERPASS },
49
 
   { "shader",          INTEL_MEASURE_SHADER     },
50
 
   { "batch",           INTEL_MEASURE_BATCH      },
51
 
   { "frame",           INTEL_MEASURE_FRAME      },
52
 
   { NULL, 0 }
53
 
};
54
 
static struct intel_measure_config config;
55
 
 
56
 
void
57
 
intel_measure_init(struct intel_measure_device *device)
58
 
{
59
 
   static bool once = false;
60
 
   const char *env = getenv("INTEL_MEASURE");
61
 
   if (unlikely(!once)) {
62
 
      once = true;
63
 
      memset(&config, 0, sizeof(struct intel_measure_config));
64
 
      if (!env)
65
 
         return;
66
 
 
67
 
      config.file = stderr;
68
 
      config.flags = parse_debug_string(env, debug_control);
69
 
      if (!config.flags)
70
 
         config.flags = INTEL_MEASURE_DRAW;
71
 
      config.enabled = true;
72
 
      config.event_interval = 1;
73
 
      config.control_fh = -1;
74
 
 
75
 
      /* Overflows of the following defaults will drop data and generate a
76
 
       * warning on the output filehandle.
77
 
       */
78
 
 
79
 
      /* default batch_size allows for 64k renders in a single batch */
80
 
      const int DEFAULT_BATCH_SIZE = 64 * 1024;
81
 
      config.batch_size = DEFAULT_BATCH_SIZE;
82
 
 
83
 
      /* Default buffer_size allows for 64k batches per line of output in the
84
 
       * csv.  Overflow may occur for offscreen workloads or large 'interval'
85
 
       * settings.
86
 
       */
87
 
      const int DEFAULT_BUFFER_SIZE = 64 * 1024;
88
 
      config.buffer_size = DEFAULT_BUFFER_SIZE;
89
 
 
90
 
      const char *filename = strstr(env, "file=");
91
 
      const char *start_frame_s = strstr(env, "start=");
92
 
      const char *count_frame_s = strstr(env, "count=");
93
 
      const char *control_path = strstr(env, "control=");
94
 
      const char *interval_s = strstr(env, "interval=");
95
 
      const char *batch_size_s = strstr(env, "batch_size=");
96
 
      const char *buffer_size_s = strstr(env, "buffer_size=");
97
 
      while (true) {
98
 
         char *sep = strrchr(env, ',');
99
 
         if (sep == NULL)
100
 
            break;
101
 
         *sep = '\0';
102
 
      }
103
 
 
104
 
      if (filename && !__check_suid()) {
105
 
         filename += 5;
106
 
         config.file = fopen(filename, "w");
107
 
         if (!config.file) {
108
 
            fprintf(stderr, "INTEL_MEASURE failed to open output file %s: %s\n",
109
 
                    filename, strerror (errno));
110
 
            abort();
111
 
         }
112
 
      }
113
 
 
114
 
      if (start_frame_s) {
115
 
         start_frame_s += 6;
116
 
         const int start_frame = atoi(start_frame_s);
117
 
         if (start_frame < 0) {
118
 
            fprintf(stderr, "INTEL_MEASURE start frame may "
119
 
                    "not be negative: %d\n", start_frame);
120
 
            abort();
121
 
         }
122
 
 
123
 
         config.start_frame = start_frame;
124
 
         config.enabled = false;
125
 
      }
126
 
 
127
 
      if (count_frame_s) {
128
 
         count_frame_s += 6;
129
 
         const int count_frame = atoi(count_frame_s);
130
 
         if (count_frame <= 0) {
131
 
            fprintf(stderr, "INTEL_MEASURE count frame must be positive: %d\n",
132
 
                    count_frame);
133
 
            abort();
134
 
         }
135
 
 
136
 
         config.end_frame = config.start_frame + count_frame;
137
 
      }
138
 
 
139
 
      if (control_path) {
140
 
         control_path += 8;
141
 
         if (mkfifoat(AT_FDCWD, control_path, O_CREAT | S_IRUSR | S_IWUSR)) {
142
 
            if (errno != EEXIST) {
143
 
               fprintf(stderr, "INTEL_MEASURE failed to create control "
144
 
                       "fifo %s: %s\n", control_path, strerror (errno));
145
 
               abort();
146
 
            }
147
 
         }
148
 
 
149
 
         config.control_fh = openat(AT_FDCWD, control_path,
150
 
                                    O_RDONLY | O_NONBLOCK);
151
 
         if (config.control_fh == -1) {
152
 
            fprintf(stderr, "INTEL_MEASURE failed to open control fifo "
153
 
                    "%s: %s\n", control_path, strerror (errno));
154
 
            abort();
155
 
         }
156
 
 
157
 
         /* when using a control fifo, do not start until the user triggers
158
 
          * capture
159
 
          */
160
 
         config.enabled = false;
161
 
      }
162
 
 
163
 
      if (interval_s) {
164
 
         interval_s += 9;
165
 
         const int event_interval = atoi(interval_s);
166
 
         if (event_interval < 1) {
167
 
            fprintf(stderr, "INTEL_MEASURE event_interval must be positive: "
168
 
                    "%d\n", event_interval);
169
 
            abort();
170
 
         }
171
 
         config.event_interval = event_interval;
172
 
      }
173
 
 
174
 
      if (batch_size_s) {
175
 
         batch_size_s += 11;
176
 
         const int batch_size = atoi(batch_size_s);
177
 
         if (batch_size < DEFAULT_BATCH_SIZE) {
178
 
            fprintf(stderr, "INTEL_MEASURE minimum batch_size is 4k: "
179
 
                    "%d\n", batch_size);
180
 
            abort();
181
 
         }
182
 
         if (batch_size > DEFAULT_BATCH_SIZE * 1024) {
183
 
            fprintf(stderr, "INTEL_MEASURE batch_size limited to 4M: "
184
 
                    "%d\n", batch_size);
185
 
            abort();
186
 
         }
187
 
 
188
 
         config.batch_size = batch_size;
189
 
      }
190
 
 
191
 
      if (buffer_size_s) {
192
 
         buffer_size_s += 12;
193
 
         const int buffer_size = atoi(buffer_size_s);
194
 
         if (buffer_size < DEFAULT_BUFFER_SIZE) {
195
 
            fprintf(stderr, "INTEL_MEASURE minimum buffer_size is 1k: "
196
 
                    "%d\n", DEFAULT_BUFFER_SIZE);
197
 
         }
198
 
         if (buffer_size > DEFAULT_BUFFER_SIZE * 1024) {
199
 
            fprintf(stderr, "INTEL_MEASURE buffer_size limited to 1M: "
200
 
                    "%d\n", buffer_size);
201
 
         }
202
 
 
203
 
         config.buffer_size = buffer_size;
204
 
      }
205
 
 
206
 
      fputs("draw_start,draw_end,frame,batch,"
207
 
            "event_index,event_count,type,count,vs,tcs,tes,"
208
 
            "gs,fs,cs,framebuffer,idle_us,time_us\n",
209
 
            config.file);
210
 
   }
211
 
 
212
 
   device->config = NULL;
213
 
   device->frame = 0;
214
 
   pthread_mutex_init(&device->mutex, NULL);
215
 
   list_inithead(&device->queued_snapshots);
216
 
 
217
 
   if (env)
218
 
      device->config = &config;
219
 
}
220
 
 
221
 
const char *
222
 
intel_measure_snapshot_string(enum intel_measure_snapshot_type type)
223
 
{
224
 
   const char *names[] = {
225
 
      [INTEL_SNAPSHOT_UNDEFINED]           = "undefined",
226
 
      [INTEL_SNAPSHOT_BLIT]                = "blit",
227
 
      [INTEL_SNAPSHOT_CCS_AMBIGUATE]       = "ccs ambiguate",
228
 
      [INTEL_SNAPSHOT_CCS_COLOR_CLEAR]     = "ccs color clear",
229
 
      [INTEL_SNAPSHOT_CCS_PARTIAL_RESOLVE] = "ccs partial resolve",
230
 
      [INTEL_SNAPSHOT_CCS_RESOLVE]         = "ccs resolve",
231
 
      [INTEL_SNAPSHOT_COMPUTE]             = "compute",
232
 
      [INTEL_SNAPSHOT_COPY]                = "copy",
233
 
      [INTEL_SNAPSHOT_DRAW]                = "draw",
234
 
      [INTEL_SNAPSHOT_HIZ_AMBIGUATE]       = "hiz ambiguate",
235
 
      [INTEL_SNAPSHOT_HIZ_CLEAR]           = "hiz clear",
236
 
      [INTEL_SNAPSHOT_HIZ_RESOLVE]         = "hiz resolve",
237
 
      [INTEL_SNAPSHOT_MCS_COLOR_CLEAR]     = "mcs color clear",
238
 
      [INTEL_SNAPSHOT_MCS_PARTIAL_RESOLVE] = "mcs partial resolve",
239
 
      [INTEL_SNAPSHOT_SLOW_COLOR_CLEAR]    = "slow color clear",
240
 
      [INTEL_SNAPSHOT_SLOW_DEPTH_CLEAR]    = "slow depth clear",
241
 
      [INTEL_SNAPSHOT_SECONDARY_BATCH]     = "secondary command buffer",
242
 
      [INTEL_SNAPSHOT_END]                 = "end",
243
 
   };
244
 
   assert(type < ARRAY_SIZE(names));
245
 
   assert(names[type] != NULL);
246
 
   assert(type != INTEL_SNAPSHOT_UNDEFINED);
247
 
   return names[type];
248
 
}
249
 
 
250
 
/**
251
 
 * Indicate to the caller whether a new snapshot should be started.
252
 
 *
253
 
 * Callers provide rendering state to this method to determine whether the
254
 
 * current start event should be skipped. Depending on the configuration
255
 
 * flags, a new snapshot may start:
256
 
 *  - at every event
257
 
 *  - when the program changes
258
 
 *  - after a batch is submitted
259
 
 *  - at frame boundaries
260
 
 *
261
 
 * Returns true if a snapshot should be started.
262
 
 */
263
 
bool
264
 
intel_measure_state_changed(const struct intel_measure_batch *batch,
265
 
                            uintptr_t vs, uintptr_t tcs, uintptr_t tes,
266
 
                            uintptr_t gs, uintptr_t fs, uintptr_t cs)
267
 
{
268
 
   if (batch->index == 0) {
269
 
      /* always record the first event */
270
 
      return true;
271
 
   }
272
 
 
273
 
   const struct intel_measure_snapshot *last_snap =
274
 
      &batch->snapshots[batch->index - 1];
275
 
 
276
 
   if (config.flags & INTEL_MEASURE_DRAW)
277
 
      return true;
278
 
 
279
 
   if (batch->index % 2 == 0) {
280
 
      /* no snapshot is running, but we have a start event */
281
 
      return true;
282
 
   }
283
 
 
284
 
   if (config.flags & (INTEL_MEASURE_FRAME | INTEL_MEASURE_BATCH)) {
285
 
      /* only start collection when index == 0, at the beginning of a batch */
286
 
      return false;
287
 
   }
288
 
 
289
 
   if (config.flags & INTEL_MEASURE_RENDERPASS) {
290
 
      return ((last_snap->framebuffer != batch->framebuffer) ||
291
 
              /* compute workloads are always in their own renderpass */
292
 
              (cs != 0));
293
 
   }
294
 
 
295
 
   /* remaining comparisons check the state of the render pipeline for
296
 
    * INTEL_MEASURE_PROGRAM
297
 
    */
298
 
   assert(config.flags & INTEL_MEASURE_SHADER);
299
 
 
300
 
   if (!vs && !tcs && !tes && !gs && !fs && !cs) {
301
 
      /* blorp always changes program */
302
 
      return true;
303
 
   }
304
 
 
305
 
   return (last_snap->vs  != (uintptr_t) vs ||
306
 
           last_snap->tcs != (uintptr_t) tcs ||
307
 
           last_snap->tes != (uintptr_t) tes ||
308
 
           last_snap->gs  != (uintptr_t) gs ||
309
 
           last_snap->fs  != (uintptr_t) fs ||
310
 
           last_snap->cs  != (uintptr_t) cs);
311
 
}
312
 
 
313
 
/**
314
 
 * Notify intel_measure that a frame is about to begin.
315
 
 *
316
 
 * Configuration values and the control fifo may commence measurement at frame
317
 
 * boundaries.
318
 
 */
319
 
void
320
 
intel_measure_frame_transition(unsigned frame)
321
 
{
322
 
   if (frame == config.start_frame)
323
 
      config.enabled = true;
324
 
   else if (frame == config.end_frame)
325
 
      config.enabled = false;
326
 
 
327
 
   /* user commands to the control fifo will override any start/count
328
 
    * environment settings
329
 
    */
330
 
   if (config.control_fh != -1) {
331
 
      while (true) {
332
 
         const unsigned BUF_SIZE = 128;
333
 
         char buf[BUF_SIZE];
334
 
         ssize_t bytes = read(config.control_fh, buf, BUF_SIZE - 1);
335
 
         if (bytes == 0)
336
 
            break;
337
 
         if (bytes == -1) {
338
 
            fprintf(stderr, "INTEL_MEASURE failed to read control fifo: %s\n",
339
 
                    strerror(errno));
340
 
            abort();
341
 
         }
342
 
 
343
 
         buf[bytes] = '\0';
344
 
         char *nptr = buf, *endptr = buf;
345
 
         while (*nptr != '\0' && *endptr != '\0') {
346
 
            long fcount = strtol(nptr, &endptr, 10);
347
 
            if (nptr == endptr) {
348
 
               config.enabled = false;
349
 
               fprintf(stderr, "INTEL_MEASURE invalid frame count on "
350
 
                       "control fifo.\n");
351
 
               lseek(config.control_fh, 0, SEEK_END);
352
 
               break;
353
 
            } else if (fcount == 0) {
354
 
               config.enabled = false;
355
 
            } else {
356
 
               config.enabled = true;
357
 
               config.end_frame = frame + fcount;
358
 
            }
359
 
 
360
 
            nptr = endptr + 1;
361
 
         }
362
 
      }
363
 
   }
364
 
}
365
 
 
366
 
#define TIMESTAMP_BITS 36
367
 
static uint64_t
368
 
raw_timestamp_delta(uint64_t time0, uint64_t time1)
369
 
{
370
 
   if (time0 > time1) {
371
 
      return (1ULL << TIMESTAMP_BITS) + time1 - time0;
372
 
   } else {
373
 
      return time1 - time0;
374
 
   }
375
 
}
376
 
 
377
 
/**
378
 
 * Verify that rendering has completed for the batch
379
 
 *
380
 
 * Rendering is complete when the last timestamp has been written.
381
 
*/
382
 
bool
383
 
intel_measure_ready(struct intel_measure_batch *batch)
384
 
{
385
 
   assert(batch->timestamps);
386
 
   assert(batch->index > 1);
387
 
   return (batch->timestamps[batch->index - 1] != 0);
388
 
}
389
 
 
390
 
/**
391
 
 * Submit completed snapshots for buffering.
392
 
 *
393
 
 * Snapshot data becomes available when asynchronous rendering completes.
394
 
 * Depending on configuration, snapshot data may need to be collated before
395
 
 * writing to the output file.
396
 
 */
397
 
static void
398
 
intel_measure_push_result(struct intel_measure_device *device,
399
 
                          struct intel_measure_batch *batch)
400
 
{
401
 
   struct intel_measure_ringbuffer *rb = device->ringbuffer;
402
 
 
403
 
   uint64_t *timestamps = batch->timestamps;
404
 
   assert(timestamps != NULL);
405
 
   assert(timestamps[0] != 0);
406
 
 
407
 
   for (int i = 0; i < batch->index; i += 2) {
408
 
      const struct intel_measure_snapshot *begin = &batch->snapshots[i];
409
 
      const struct intel_measure_snapshot *end = &batch->snapshots[i+1];
410
 
 
411
 
      assert (end->type == INTEL_SNAPSHOT_END);
412
 
 
413
 
      if (begin->type == INTEL_SNAPSHOT_SECONDARY_BATCH) {
414
 
         assert(begin->secondary != NULL);
415
 
         begin->secondary->batch_count = batch->batch_count;
416
 
         intel_measure_push_result(device, begin->secondary);
417
 
         continue;
418
 
      }
419
 
 
420
 
      const uint64_t prev_end_ts = rb->results[rb->head].end_ts;
421
 
 
422
 
      /* advance ring buffer */
423
 
      if (++rb->head == config.buffer_size)
424
 
         rb->head = 0;
425
 
      if (rb->head == rb->tail) {
426
 
         static bool warned = false;
427
 
         if (unlikely(!warned)) {
428
 
            fprintf(config.file,
429
 
                    "WARNING: Buffered data exceeds INTEL_MEASURE limit: %d. "
430
 
                    "Data has been dropped. "
431
 
                    "Increase setting with INTEL_MEASURE=buffer_size={count}\n",
432
 
                    config.buffer_size);
433
 
            warned = true;
434
 
         }
435
 
         break;
436
 
      }
437
 
 
438
 
      struct intel_measure_buffered_result *buffered_result =
439
 
         &rb->results[rb->head];
440
 
 
441
 
      memset(buffered_result, 0, sizeof(*buffered_result));
442
 
      memcpy(&buffered_result->snapshot, begin,
443
 
             sizeof(struct intel_measure_snapshot));
444
 
      buffered_result->start_ts = timestamps[i];
445
 
      buffered_result->end_ts = timestamps[i+1];
446
 
      buffered_result->idle_duration =
447
 
         raw_timestamp_delta(prev_end_ts, buffered_result->start_ts);
448
 
      buffered_result->frame = batch->frame;
449
 
      buffered_result->batch_count = batch->batch_count;
450
 
      buffered_result->event_index = i / 2;
451
 
      buffered_result->snapshot.event_count = end->event_count;
452
 
   }
453
 
}
454
 
 
455
 
static unsigned
456
 
ringbuffer_size(const struct intel_measure_ringbuffer *rb)
457
 
{
458
 
   unsigned head = rb->head;
459
 
   if (head < rb->tail)
460
 
      head += config.buffer_size;
461
 
   return head - rb->tail;
462
 
}
463
 
 
464
 
static const struct intel_measure_buffered_result *
465
 
ringbuffer_pop(struct intel_measure_ringbuffer *rb)
466
 
{
467
 
   if (rb->tail == rb->head) {
468
 
      /* encountered ringbuffer overflow while processing events */
469
 
      return NULL;
470
 
   }
471
 
 
472
 
   if (++rb->tail == config.buffer_size)
473
 
      rb->tail = 0;
474
 
   return &rb->results[rb->tail];
475
 
}
476
 
 
477
 
static const struct intel_measure_buffered_result *
478
 
ringbuffer_peek(const struct intel_measure_ringbuffer *rb, unsigned index)
479
 
{
480
 
   int result_offset = rb->tail + index + 1;
481
 
   if (result_offset >= config.buffer_size)
482
 
      result_offset -= config.buffer_size;
483
 
   return &rb->results[result_offset];
484
 
}
485
 
 
486
 
 
487
 
/**
488
 
 * Determine the number of buffered events that must be combined for the next
489
 
 * line of csv output. Returns 0 if more events are needed.
490
 
 */
491
 
static unsigned
492
 
buffered_event_count(struct intel_measure_device *device)
493
 
{
494
 
   const struct intel_measure_ringbuffer *rb = device->ringbuffer;
495
 
   const unsigned buffered_event_count = ringbuffer_size(rb);
496
 
   if (buffered_event_count == 0) {
497
 
      /* no events to collect */
498
 
      return 0;
499
 
   }
500
 
 
501
 
   /* count the number of buffered events required to meet the configuration */
502
 
   if (config.flags & (INTEL_MEASURE_DRAW |
503
 
                       INTEL_MEASURE_RENDERPASS |
504
 
                       INTEL_MEASURE_SHADER)) {
505
 
      /* For these flags, every buffered event represents a line in the
506
 
       * output.  None of these events span batches.  If the event interval
507
 
       * crosses a batch boundary, then the next interval starts with the new
508
 
       * batch.
509
 
       */
510
 
      return 1;
511
 
   }
512
 
 
513
 
   const unsigned start_frame = ringbuffer_peek(rb, 0)->frame;
514
 
   if (config.flags & INTEL_MEASURE_BATCH) {
515
 
      /* each buffered event is a command buffer.  The number of events to
516
 
       * process is the same as the interval, unless the interval crosses a
517
 
       * frame boundary
518
 
       */
519
 
      if (buffered_event_count < config.event_interval) {
520
 
         /* not enough events */
521
 
         return 0;
522
 
      }
523
 
 
524
 
      /* Imperfect frame tracking requires us to allow for *older* frames */
525
 
      if (ringbuffer_peek(rb, config.event_interval - 1)->frame <= start_frame) {
526
 
         /* No frame transition.  The next {interval} events should be combined. */
527
 
         return config.event_interval;
528
 
      }
529
 
 
530
 
      /* Else a frame transition occurs within the interval.  Find the
531
 
       * transition, so the following line of output begins with the batch
532
 
       * that starts the new frame.
533
 
       */
534
 
      for (int event_index = 1;
535
 
           event_index <= config.event_interval;
536
 
           ++event_index) {
537
 
         if (ringbuffer_peek(rb, event_index)->frame > start_frame)
538
 
            return event_index;
539
 
      }
540
 
 
541
 
      assert(false);
542
 
   }
543
 
 
544
 
   /* Else we need to search buffered events to find the matching frame
545
 
    * transition for our interval.
546
 
    */
547
 
   assert(config.flags & INTEL_MEASURE_FRAME);
548
 
   for (int event_index = 1;
549
 
        event_index < buffered_event_count;
550
 
        ++event_index) {
551
 
      const int latest_frame = ringbuffer_peek(rb, event_index)->frame;
552
 
      if (latest_frame - start_frame >= config.event_interval)
553
 
         return event_index;
554
 
   }
555
 
 
556
 
   return 0;
557
 
}
558
 
 
559
 
/**
560
 
 * Take result_count events from the ringbuffer and output them as a single
561
 
 * line.
562
 
 */
563
 
static void
564
 
print_combined_results(struct intel_measure_device *measure_device,
565
 
                       int result_count,
566
 
                       struct intel_device_info *info)
567
 
{
568
 
   if (result_count == 0)
569
 
      return;
570
 
 
571
 
   struct intel_measure_ringbuffer *result_rb = measure_device->ringbuffer;
572
 
   assert(ringbuffer_size(result_rb) >= result_count);
573
 
   const struct intel_measure_buffered_result* start_result =
574
 
      ringbuffer_pop(result_rb);
575
 
   const struct intel_measure_buffered_result* current_result = start_result;
576
 
 
577
 
   if (start_result == NULL)
578
 
      return;
579
 
   --result_count;
580
 
 
581
 
   uint64_t duration_ts = raw_timestamp_delta(start_result->start_ts,
582
 
                                              current_result->end_ts);
583
 
   unsigned event_count = start_result->snapshot.event_count;
584
 
   while (result_count-- > 0) {
585
 
      assert(ringbuffer_size(result_rb) > 0);
586
 
      current_result = ringbuffer_pop(result_rb);
587
 
      if (current_result == NULL)
588
 
         return;
589
 
      duration_ts += raw_timestamp_delta(current_result->start_ts,
590
 
                                         current_result->end_ts);
591
 
      event_count += current_result->snapshot.event_count;
592
 
   }
593
 
 
594
 
   uint64_t duration_idle_ns =
595
 
      intel_device_info_timebase_scale(info, start_result->idle_duration);
596
 
   uint64_t duration_time_ns =
597
 
      intel_device_info_timebase_scale(info, duration_ts);
598
 
   const struct intel_measure_snapshot *begin = &start_result->snapshot;
599
 
   fprintf(config.file, "%"PRIu64",%"PRIu64",%u,%u,%u,%u,%s,%u,"
600
 
           "0x%"PRIxPTR",0x%"PRIxPTR",0x%"PRIxPTR",0x%"PRIxPTR",0x%"PRIxPTR","
601
 
           "0x%"PRIxPTR",0x%"PRIxPTR",%.3lf,%.3lf\n",
602
 
           start_result->start_ts, current_result->end_ts,
603
 
           start_result->frame, start_result->batch_count,
604
 
           start_result->event_index, event_count,
605
 
           begin->event_name, begin->count,
606
 
           begin->vs, begin->tcs, begin->tes, begin->gs, begin->fs, begin->cs,
607
 
           begin->framebuffer,
608
 
           (double)duration_idle_ns / 1000.0,
609
 
           (double)duration_time_ns / 1000.0);
610
 
}
611
 
 
612
 
/**
613
 
 * Empty the ringbuffer of events that can be printed.
614
 
 */
615
 
static void
616
 
intel_measure_print(struct intel_measure_device *device,
617
 
                    struct intel_device_info *info)
618
 
{
619
 
   while (true) {
620
 
      const int events_to_combine = buffered_event_count(device);
621
 
      if (events_to_combine == 0)
622
 
         break;
623
 
      print_combined_results(device, events_to_combine, info);
624
 
   }
625
 
}
626
 
 
627
 
/**
628
 
 * Collect snapshots from completed command buffers and submit them to
629
 
 * intel_measure for printing.
630
 
 */
631
 
void
632
 
intel_measure_gather(struct intel_measure_device *measure_device,
633
 
                     struct intel_device_info *info)
634
 
{
635
 
   pthread_mutex_lock(&measure_device->mutex);
636
 
 
637
 
   /* Iterate snapshots and collect if ready.  Each snapshot queue will be
638
 
    * in-order, but we must determine which queue has the oldest batch.
639
 
    */
640
 
   /* iterate snapshots and collect if ready */
641
 
   while (!list_is_empty(&measure_device->queued_snapshots)) {
642
 
      struct intel_measure_batch *batch =
643
 
         list_first_entry(&measure_device->queued_snapshots,
644
 
                          struct intel_measure_batch, link);
645
 
 
646
 
      if (!intel_measure_ready(batch)) {
647
 
         /* command buffer has begun execution on the gpu, but has not
648
 
          * completed.
649
 
          */
650
 
         break;
651
 
      }
652
 
 
653
 
      list_del(&batch->link);
654
 
      assert(batch->index % 2 == 0);
655
 
 
656
 
      intel_measure_push_result(measure_device, batch);
657
 
 
658
 
      batch->index = 0;
659
 
      batch->frame = 0;
660
 
   }
661
 
 
662
 
   intel_measure_print(measure_device, info);
663
 
   pthread_mutex_unlock(&measure_device->mutex);
664
 
}
665