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