Path: blob/21.2-virgl/src/freedreno/computerator/main.c
4564 views
/*1* Copyright © 2020 Google, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*/2223#include <getopt.h>24#include <inttypes.h>25#include <locale.h>26#include <stdlib.h>27#include <xf86drm.h>2829#include "util/u_math.h"3031#include "perfcntrs/freedreno_perfcntr.h"3233#include "main.h"3435static void36dump_float(void *buf, int sz)37{38uint8_t *ptr = (uint8_t *)buf;39uint8_t *end = ptr + sz - 3;40int i = 0;4142while (ptr < end) {43uint32_t d = 0;4445printf((i % 8) ? " " : "\t");4647d |= *(ptr++) << 0;48d |= *(ptr++) << 8;49d |= *(ptr++) << 16;50d |= *(ptr++) << 24;5152printf("%8f", uif(d));5354if ((i % 8) == 7) {55printf("\n");56}5758i++;59}6061if (i % 8) {62printf("\n");63}64}6566static void67dump_hex(void *buf, int sz)68{69uint8_t *ptr = (uint8_t *)buf;70uint8_t *end = ptr + sz;71int i = 0;7273while (ptr < end) {74uint32_t d = 0;7576printf((i % 8) ? " " : "\t");7778d |= *(ptr++) << 0;79d |= *(ptr++) << 8;80d |= *(ptr++) << 16;81d |= *(ptr++) << 24;8283printf("%08x", d);8485if ((i % 8) == 7) {86printf("\n");87}8889i++;90}9192if (i % 8) {93printf("\n");94}95}9697static const char *shortopts = "df:g:hp:";9899static const struct option longopts[] = {100{"disasm", no_argument, 0, 'd'}, {"file", required_argument, 0, 'f'},101{"groups", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'},102{"perfcntr", required_argument, 0, 'p'}, {0, 0, 0, 0}};103104static void105usage(const char *name)106{107printf(108"Usage: %s [-dfgh]\n"109"\n"110"options:\n"111" -d, --disasm print disassembled shader\n"112" -f, --file=FILE read shader from file (instead of stdin)\n"113" -g, --groups=X,Y,Z use specified group size\n"114" -h, --help show this message\n"115" -p, --perfcntr=LIST sample specified performance counters "116"(comma\n"117" separated list)\n",118name);119}120121/* performance counter description: */122static unsigned num_groups;123static const struct fd_perfcntr_group *groups;124125/* Track enabled counters per group: */126static unsigned *enabled_counters;127128static void129setup_counter(const char *name, struct perfcntr *c)130{131for (int i = 0; i < num_groups; i++) {132const struct fd_perfcntr_group *group = &groups[i];133134for (int j = 0; j < group->num_countables; j++) {135const struct fd_perfcntr_countable *countable = &group->countables[j];136137if (strcmp(name, countable->name) != 0)138continue;139140/*141* Allocate a counter to use to monitor the requested countable:142*/143if (enabled_counters[i] >= group->num_counters) {144errx(-1, "Too many counters selected in group: %s", group->name);145}146147unsigned idx = enabled_counters[i]++;148const struct fd_perfcntr_counter *counter = &group->counters[idx];149150/*151* And initialize the perfcntr struct, pulling together the info152* about selected counter and countable, to simplify life for the153* backend:154*/155c->name = name;156c->select_reg = counter->select_reg;157c->counter_reg_lo = counter->counter_reg_lo;158c->counter_reg_hi = counter->counter_reg_hi;159c->selector = countable->selector;160161return;162}163}164165errx(-1, "could not find countable: %s", name);166}167168static struct perfcntr *169parse_perfcntrs(uint32_t gpu_id, const char *perfcntrstr,170unsigned *num_perfcntrs)171{172struct perfcntr *counters = NULL;173char *cnames, *s;174unsigned cnt = 0;175176groups = fd_perfcntrs(gpu_id, &num_groups);177enabled_counters = calloc(num_groups, sizeof(enabled_counters[0]));178179cnames = strdup(perfcntrstr);180while ((s = strstr(cnames, ","))) {181char *name = cnames;182s[0] = '\0';183cnames = &s[1];184185counters = realloc(counters, ++cnt * sizeof(counters[0]));186setup_counter(name, &counters[cnt - 1]);187}188189char *name = cnames;190counters = realloc(counters, ++cnt * sizeof(counters[0]));191setup_counter(name, &counters[cnt - 1]);192193*num_perfcntrs = cnt;194195return counters;196}197198int199main(int argc, char **argv)200{201FILE *in = stdin;202const char *perfcntrstr = NULL;203struct perfcntr *perfcntrs = NULL;204unsigned num_perfcntrs = 0;205bool disasm = false;206uint32_t grid[3] = {0};207int opt, ret;208209setlocale(LC_NUMERIC, "en_US.UTF-8");210211while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) !=212-1) {213switch (opt) {214case 'd':215disasm = true;216break;217case 'f':218in = fopen(optarg, "r");219if (!in)220err(1, "could not open '%s'", optarg);221break;222case 'g':223ret = sscanf(optarg, "%u,%u,%u", &grid[0], &grid[1], &grid[2]);224if (ret != 3)225goto usage;226break;227case 'h':228goto usage;229case 'p':230perfcntrstr = optarg;231break;232default:233printf("unrecognized arg: %c\n", opt);234goto usage;235}236}237238int fd = drmOpenWithType("msm", NULL, DRM_NODE_RENDER);239if (fd < 0)240err(1, "could not open drm device");241242struct fd_device *dev = fd_device_new(fd);243struct fd_pipe *pipe = fd_pipe_new(dev, FD_PIPE_3D);244245uint64_t val;246fd_pipe_get_param(pipe, FD_GPU_ID, &val);247uint32_t gpu_id = val;248249printf("got gpu_id: %u\n", gpu_id);250251struct backend *backend;252switch (gpu_id) {253case 600 ... 699:254backend = a6xx_init(dev, gpu_id);255break;256default:257err(1, "unsupported gpu: a%u", gpu_id);258}259260struct kernel *kernel = backend->assemble(backend, in);261printf("localsize: %dx%dx%d\n", kernel->local_size[0], kernel->local_size[1],262kernel->local_size[2]);263for (int i = 0; i < kernel->num_bufs; i++) {264printf("buf[%d]: size=%u\n", i, kernel->buf_sizes[i]);265kernel->bufs[i] = fd_bo_new(dev, kernel->buf_sizes[i] * 4, 0, "buf[%d]", i);266}267268if (disasm)269backend->disassemble(kernel, stdout);270271if (grid[0] == 0)272return 0;273274struct fd_submit *submit = fd_submit_new(pipe);275276if (perfcntrstr) {277if (!backend->set_perfcntrs) {278err(1, "performance counters not supported");279}280perfcntrs = parse_perfcntrs(gpu_id, perfcntrstr, &num_perfcntrs);281backend->set_perfcntrs(backend, perfcntrs, num_perfcntrs);282}283284backend->emit_grid(kernel, grid, submit);285286struct fd_submit_fence fence = {};287util_queue_fence_init(&fence.ready);288289fd_submit_flush(submit, -1, &fence);290291util_queue_fence_wait(&fence.ready);292293for (int i = 0; i < kernel->num_bufs; i++) {294fd_bo_cpu_prep(kernel->bufs[i], pipe, FD_BO_PREP_READ);295void *map = fd_bo_map(kernel->bufs[i]);296297printf("buf[%d]:\n", i);298dump_hex(map, kernel->buf_sizes[i] * 4);299dump_float(map, kernel->buf_sizes[i] * 4);300}301302if (perfcntrstr) {303uint64_t results[num_perfcntrs];304backend->read_perfcntrs(backend, results);305306for (unsigned i = 0; i < num_perfcntrs; i++) {307printf("%s:\t%'" PRIu64 "\n", perfcntrs[i].name, results[i]);308}309}310311return 0;312313usage:314usage(argv[0]);315return -1;316}317318319