• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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