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