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