1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc. 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 (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <getopt.h> 25bf215546Sopenharmony_ci#include <inttypes.h> 26bf215546Sopenharmony_ci#include <locale.h> 27bf215546Sopenharmony_ci#include <stdlib.h> 28bf215546Sopenharmony_ci#include <xf86drm.h> 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "util/u_math.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "perfcntrs/freedreno_perfcntr.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "main.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cistatic void 37bf215546Sopenharmony_cidump_float(void *buf, int sz) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci uint8_t *ptr = (uint8_t *)buf; 40bf215546Sopenharmony_ci uint8_t *end = ptr + sz - 3; 41bf215546Sopenharmony_ci int i = 0; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci while (ptr < end) { 44bf215546Sopenharmony_ci uint32_t d = 0; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci printf((i % 8) ? " " : "\t"); 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci d |= *(ptr++) << 0; 49bf215546Sopenharmony_ci d |= *(ptr++) << 8; 50bf215546Sopenharmony_ci d |= *(ptr++) << 16; 51bf215546Sopenharmony_ci d |= *(ptr++) << 24; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci printf("%8f", uif(d)); 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci if ((i % 8) == 7) { 56bf215546Sopenharmony_ci printf("\n"); 57bf215546Sopenharmony_ci } 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci i++; 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if (i % 8) { 63bf215546Sopenharmony_ci printf("\n"); 64bf215546Sopenharmony_ci } 65bf215546Sopenharmony_ci} 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_cistatic void 68bf215546Sopenharmony_cidump_hex(void *buf, int sz) 69bf215546Sopenharmony_ci{ 70bf215546Sopenharmony_ci uint8_t *ptr = (uint8_t *)buf; 71bf215546Sopenharmony_ci uint8_t *end = ptr + sz; 72bf215546Sopenharmony_ci int i = 0; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci while (ptr < end) { 75bf215546Sopenharmony_ci uint32_t d = 0; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci printf((i % 8) ? " " : "\t"); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci d |= *(ptr++) << 0; 80bf215546Sopenharmony_ci d |= *(ptr++) << 8; 81bf215546Sopenharmony_ci d |= *(ptr++) << 16; 82bf215546Sopenharmony_ci d |= *(ptr++) << 24; 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci printf("%08x", d); 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci if ((i % 8) == 7) { 87bf215546Sopenharmony_ci printf("\n"); 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci i++; 91bf215546Sopenharmony_ci } 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci if (i % 8) { 94bf215546Sopenharmony_ci printf("\n"); 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic const char *shortopts = "df:g:hp:"; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_cistatic const struct option longopts[] = { 101bf215546Sopenharmony_ci {"disasm", no_argument, 0, 'd'}, {"file", required_argument, 0, 'f'}, 102bf215546Sopenharmony_ci {"groups", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, 103bf215546Sopenharmony_ci {"perfcntr", required_argument, 0, 'p'}, {0, 0, 0, 0}}; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_cistatic void 106bf215546Sopenharmony_ciusage(const char *name) 107bf215546Sopenharmony_ci{ 108bf215546Sopenharmony_ci printf( 109bf215546Sopenharmony_ci "Usage: %s [-dfgh]\n" 110bf215546Sopenharmony_ci "\n" 111bf215546Sopenharmony_ci "options:\n" 112bf215546Sopenharmony_ci " -d, --disasm print disassembled shader\n" 113bf215546Sopenharmony_ci " -f, --file=FILE read shader from file (instead of stdin)\n" 114bf215546Sopenharmony_ci " -g, --groups=X,Y,Z use specified group size\n" 115bf215546Sopenharmony_ci " -h, --help show this message\n" 116bf215546Sopenharmony_ci " -p, --perfcntr=LIST sample specified performance counters " 117bf215546Sopenharmony_ci "(comma\n" 118bf215546Sopenharmony_ci " separated list)\n", 119bf215546Sopenharmony_ci name); 120bf215546Sopenharmony_ci} 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci/* performance counter description: */ 123bf215546Sopenharmony_cistatic unsigned num_groups; 124bf215546Sopenharmony_cistatic const struct fd_perfcntr_group *groups; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci/* Track enabled counters per group: */ 127bf215546Sopenharmony_cistatic unsigned *enabled_counters; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_cistatic void 130bf215546Sopenharmony_cisetup_counter(const char *name, struct perfcntr *c) 131bf215546Sopenharmony_ci{ 132bf215546Sopenharmony_ci for (int i = 0; i < num_groups; i++) { 133bf215546Sopenharmony_ci const struct fd_perfcntr_group *group = &groups[i]; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci for (int j = 0; j < group->num_countables; j++) { 136bf215546Sopenharmony_ci const struct fd_perfcntr_countable *countable = &group->countables[j]; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci if (strcmp(name, countable->name) != 0) 139bf215546Sopenharmony_ci continue; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* 142bf215546Sopenharmony_ci * Allocate a counter to use to monitor the requested countable: 143bf215546Sopenharmony_ci */ 144bf215546Sopenharmony_ci if (enabled_counters[i] >= group->num_counters) { 145bf215546Sopenharmony_ci errx(-1, "Too many counters selected in group: %s", group->name); 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci unsigned idx = enabled_counters[i]++; 149bf215546Sopenharmony_ci const struct fd_perfcntr_counter *counter = &group->counters[idx]; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci /* 152bf215546Sopenharmony_ci * And initialize the perfcntr struct, pulling together the info 153bf215546Sopenharmony_ci * about selected counter and countable, to simplify life for the 154bf215546Sopenharmony_ci * backend: 155bf215546Sopenharmony_ci */ 156bf215546Sopenharmony_ci c->name = name; 157bf215546Sopenharmony_ci c->select_reg = counter->select_reg; 158bf215546Sopenharmony_ci c->counter_reg_lo = counter->counter_reg_lo; 159bf215546Sopenharmony_ci c->counter_reg_hi = counter->counter_reg_hi; 160bf215546Sopenharmony_ci c->selector = countable->selector; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci return; 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci errx(-1, "could not find countable: %s", name); 167bf215546Sopenharmony_ci} 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_cistatic struct perfcntr * 170bf215546Sopenharmony_ciparse_perfcntrs(const struct fd_dev_id *dev_id, const char *perfcntrstr, 171bf215546Sopenharmony_ci unsigned *num_perfcntrs) 172bf215546Sopenharmony_ci{ 173bf215546Sopenharmony_ci struct perfcntr *counters = NULL; 174bf215546Sopenharmony_ci char *cnames, *s; 175bf215546Sopenharmony_ci unsigned cnt = 0; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci groups = fd_perfcntrs(dev_id, &num_groups); 178bf215546Sopenharmony_ci enabled_counters = calloc(num_groups, sizeof(enabled_counters[0])); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci cnames = strdup(perfcntrstr); 181bf215546Sopenharmony_ci while ((s = strstr(cnames, ","))) { 182bf215546Sopenharmony_ci char *name = cnames; 183bf215546Sopenharmony_ci s[0] = '\0'; 184bf215546Sopenharmony_ci cnames = &s[1]; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci counters = realloc(counters, ++cnt * sizeof(counters[0])); 187bf215546Sopenharmony_ci setup_counter(name, &counters[cnt - 1]); 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci char *name = cnames; 191bf215546Sopenharmony_ci counters = realloc(counters, ++cnt * sizeof(counters[0])); 192bf215546Sopenharmony_ci setup_counter(name, &counters[cnt - 1]); 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci *num_perfcntrs = cnt; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci return counters; 197bf215546Sopenharmony_ci} 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ciint 200bf215546Sopenharmony_cimain(int argc, char **argv) 201bf215546Sopenharmony_ci{ 202bf215546Sopenharmony_ci FILE *in = stdin; 203bf215546Sopenharmony_ci const char *perfcntrstr = NULL; 204bf215546Sopenharmony_ci struct perfcntr *perfcntrs = NULL; 205bf215546Sopenharmony_ci unsigned num_perfcntrs = 0; 206bf215546Sopenharmony_ci bool disasm = false; 207bf215546Sopenharmony_ci uint32_t grid[3] = {0}; 208bf215546Sopenharmony_ci int opt, ret; 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci setlocale(LC_NUMERIC, "en_US.UTF-8"); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != 213bf215546Sopenharmony_ci -1) { 214bf215546Sopenharmony_ci switch (opt) { 215bf215546Sopenharmony_ci case 'd': 216bf215546Sopenharmony_ci disasm = true; 217bf215546Sopenharmony_ci break; 218bf215546Sopenharmony_ci case 'f': 219bf215546Sopenharmony_ci in = fopen(optarg, "r"); 220bf215546Sopenharmony_ci if (!in) 221bf215546Sopenharmony_ci err(1, "could not open '%s'", optarg); 222bf215546Sopenharmony_ci break; 223bf215546Sopenharmony_ci case 'g': 224bf215546Sopenharmony_ci ret = sscanf(optarg, "%u,%u,%u", &grid[0], &grid[1], &grid[2]); 225bf215546Sopenharmony_ci if (ret != 3) 226bf215546Sopenharmony_ci goto usage; 227bf215546Sopenharmony_ci break; 228bf215546Sopenharmony_ci case 'h': 229bf215546Sopenharmony_ci goto usage; 230bf215546Sopenharmony_ci case 'p': 231bf215546Sopenharmony_ci perfcntrstr = optarg; 232bf215546Sopenharmony_ci break; 233bf215546Sopenharmony_ci default: 234bf215546Sopenharmony_ci printf("unrecognized arg: %c\n", opt); 235bf215546Sopenharmony_ci goto usage; 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci struct fd_device *dev = fd_device_open(); 240bf215546Sopenharmony_ci struct fd_pipe *pipe = fd_pipe_new(dev, FD_PIPE_3D); 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci const struct fd_dev_id *dev_id = fd_pipe_dev_id(pipe); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci printf("got gpu: %s\n", fd_dev_name(dev_id)); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci struct backend *backend; 247bf215546Sopenharmony_ci switch (fd_dev_gen(dev_id)) { 248bf215546Sopenharmony_ci case 4: 249bf215546Sopenharmony_ci backend = a4xx_init(dev, dev_id); 250bf215546Sopenharmony_ci break; 251bf215546Sopenharmony_ci case 6: 252bf215546Sopenharmony_ci backend = a6xx_init(dev, dev_id); 253bf215546Sopenharmony_ci break; 254bf215546Sopenharmony_ci default: 255bf215546Sopenharmony_ci err(1, "unsupported gpu generation: a%uxx", fd_dev_gen(dev_id)); 256bf215546Sopenharmony_ci } 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci struct kernel *kernel = backend->assemble(backend, in); 259bf215546Sopenharmony_ci printf("localsize: %dx%dx%d\n", kernel->local_size[0], kernel->local_size[1], 260bf215546Sopenharmony_ci kernel->local_size[2]); 261bf215546Sopenharmony_ci for (int i = 0; i < kernel->num_bufs; i++) { 262bf215546Sopenharmony_ci printf("buf[%d]: size=%u\n", i, kernel->buf_sizes[i]); 263bf215546Sopenharmony_ci kernel->bufs[i] = fd_bo_new(dev, kernel->buf_sizes[i] * 4, 0, "buf[%d]", i); 264bf215546Sopenharmony_ci } 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci if (disasm) 267bf215546Sopenharmony_ci backend->disassemble(kernel, stdout); 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if (grid[0] == 0) 270bf215546Sopenharmony_ci return 0; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci struct fd_submit *submit = fd_submit_new(pipe); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci if (perfcntrstr) { 275bf215546Sopenharmony_ci if (!backend->set_perfcntrs) { 276bf215546Sopenharmony_ci err(1, "performance counters not supported"); 277bf215546Sopenharmony_ci } 278bf215546Sopenharmony_ci perfcntrs = parse_perfcntrs(dev_id, perfcntrstr, &num_perfcntrs); 279bf215546Sopenharmony_ci backend->set_perfcntrs(backend, perfcntrs, num_perfcntrs); 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci backend->emit_grid(kernel, grid, submit); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci struct fd_submit_fence fence = {}; 285bf215546Sopenharmony_ci util_queue_fence_init(&fence.ready); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci fd_submit_flush(submit, -1, &fence); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci util_queue_fence_wait(&fence.ready); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci for (int i = 0; i < kernel->num_bufs; i++) { 292bf215546Sopenharmony_ci fd_bo_cpu_prep(kernel->bufs[i], pipe, FD_BO_PREP_READ); 293bf215546Sopenharmony_ci void *map = fd_bo_map(kernel->bufs[i]); 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci printf("buf[%d]:\n", i); 296bf215546Sopenharmony_ci dump_hex(map, kernel->buf_sizes[i] * 4); 297bf215546Sopenharmony_ci dump_float(map, kernel->buf_sizes[i] * 4); 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci if (perfcntrstr) { 301bf215546Sopenharmony_ci uint64_t results[num_perfcntrs]; 302bf215546Sopenharmony_ci backend->read_perfcntrs(backend, results); 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci for (unsigned i = 0; i < num_perfcntrs; i++) { 305bf215546Sopenharmony_ci printf("%s:\t%'" PRIu64 "\n", perfcntrs[i].name, results[i]); 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci return 0; 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ciusage: 312bf215546Sopenharmony_ci usage(argv[0]); 313bf215546Sopenharmony_ci return -1; 314bf215546Sopenharmony_ci} 315