1 /*
2  * Copyright (C) 2015 - Tobias Jakobi
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation, either version 2 of the License,
7  * or (at your option) any later version.
8  *
9  * It is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with it. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <time.h>
20 #include <getopt.h>
21 #include <errno.h>
22 
23 #include <xf86drm.h>
24 
25 #include "exynos_drm.h"
26 #include "exynos_drmif.h"
27 #include "exynos_fimg2d.h"
28 
29 static int output_mathematica = 0;
30 
fimg2d_perf_simple(struct exynos_bo * bo,struct g2d_context * ctx,unsigned buf_width,unsigned buf_height,unsigned iterations)31 static int fimg2d_perf_simple(struct exynos_bo *bo, struct g2d_context *ctx,
32 			unsigned buf_width, unsigned buf_height, unsigned iterations)
33 {
34 	struct timespec tspec = { 0 };
35 	struct g2d_image img = { 0 };
36 
37 	unsigned long long g2d_time;
38 	unsigned i;
39 	int ret = 0;
40 
41 	img.width = buf_width;
42 	img.height = buf_height;
43 	img.stride = buf_width * 4;
44 	img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
45 	img.buf_type = G2D_IMGBUF_GEM;
46 	img.bo[0] = bo->handle;
47 
48 	srand(time(NULL));
49 
50 	printf("starting simple G2D performance test\n");
51 	printf("buffer width = %u, buffer height = %u, iterations = %u\n",
52 		buf_width, buf_height, iterations);
53 
54 	if (output_mathematica)
55 		putchar('{');
56 
57 	for (i = 0; i < iterations; ++i) {
58 		unsigned x, y, w, h;
59 
60 		x = rand() % buf_width;
61 		y = rand() % buf_height;
62 
63 		if (x == (buf_width - 1))
64 			x -= 1;
65 		if (y == (buf_height - 1))
66 			y -= 1;
67 
68 		w = rand() % (buf_width - x);
69 		h = rand() % (buf_height - y);
70 
71 		if (w == 0) w = 1;
72 		if (h == 0) h = 1;
73 
74 		img.color = rand();
75 
76 		ret = g2d_solid_fill(ctx, &img, x, y, w, h);
77 
78 		clock_gettime(CLOCK_MONOTONIC, &tspec);
79 
80 		if (ret == 0)
81 			ret = g2d_exec(ctx);
82 
83 		if (ret != 0) {
84 			fprintf(stderr, "error: iteration %u failed (x = %u, y = %u, w = %u, h = %u)\n",
85 				i, x, y, w, h);
86 			break;
87 		} else {
88 			struct timespec end = { 0 };
89 			clock_gettime(CLOCK_MONOTONIC, &end);
90 
91 			g2d_time = (end.tv_sec - tspec.tv_sec) * 1000000000ULL;
92 			g2d_time += (end.tv_nsec - tspec.tv_nsec);
93 
94 			if (output_mathematica) {
95 				if (i != 0) putchar(',');
96 				printf("{%u,%llu}", w * h, g2d_time);
97 			} else {
98 				printf("num_pixels = %u, usecs = %llu\n", w * h, g2d_time);
99 			}
100 		}
101 	}
102 
103 	if (output_mathematica)
104 		printf("}\n");
105 
106 	return ret;
107 }
108 
fimg2d_perf_multi(struct exynos_bo * bo,struct g2d_context * ctx,unsigned buf_width,unsigned buf_height,unsigned iterations,unsigned batch)109 static int fimg2d_perf_multi(struct exynos_bo *bo, struct g2d_context *ctx,
110 			unsigned buf_width, unsigned buf_height, unsigned iterations, unsigned batch)
111 {
112 	struct timespec tspec = { 0 };
113 	struct g2d_image *images;
114 
115 	unsigned long long g2d_time;
116 	unsigned i, j;
117 	int ret = 0;
118 
119 	images = calloc(batch, sizeof(struct g2d_image));
120 	if (images == NULL) {
121 		fprintf(stderr, "error: failed to allocate G2D images.\n");
122 		return -ENOMEM;
123 	}
124 
125 	for (i = 0; i < batch; ++i) {
126 		images[i].width = buf_width;
127 		images[i].height = buf_height;
128 		images[i].stride = buf_width * 4;
129 		images[i].color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
130 		images[i].buf_type = G2D_IMGBUF_GEM;
131 		images[i].bo[0] = bo->handle;
132 	}
133 
134 	srand(time(NULL));
135 
136 	printf("starting multi G2D performance test (batch size = %u)\n", batch);
137 	printf("buffer width = %u, buffer height = %u, iterations = %u\n",
138 		buf_width, buf_height, iterations);
139 
140 	if (output_mathematica)
141 		putchar('{');
142 
143 	for (i = 0; i < iterations; ++i) {
144 		unsigned num_pixels = 0;
145 
146 		for (j = 0; j < batch; ++j) {
147 			unsigned x, y, w, h;
148 
149 			x = rand() % buf_width;
150 			y = rand() % buf_height;
151 
152 			if (x == (buf_width - 1))
153 				x -= 1;
154 			if (y == (buf_height - 1))
155 				y -= 1;
156 
157 			w = rand() % (buf_width - x);
158 			h = rand() % (buf_height - y);
159 
160 			if (w == 0) w = 1;
161 			if (h == 0) h = 1;
162 
163 			images[j].color = rand();
164 
165 			num_pixels += w * h;
166 
167 			ret = g2d_solid_fill(ctx, &images[j], x, y, w, h);
168 			if (ret != 0)
169 				break;
170 		}
171 
172 		clock_gettime(CLOCK_MONOTONIC, &tspec);
173 
174 		if (ret == 0)
175 			ret = g2d_exec(ctx);
176 
177 		if (ret != 0) {
178 			fprintf(stderr, "error: iteration %u failed (num_pixels = %u)\n", i, num_pixels);
179 			break;
180 		} else {
181 			struct timespec end = { 0 };
182 			clock_gettime(CLOCK_MONOTONIC, &end);
183 
184 			g2d_time = (end.tv_sec - tspec.tv_sec) * 1000000000ULL;
185 			g2d_time += (end.tv_nsec - tspec.tv_nsec);
186 
187 			if (output_mathematica) {
188 				if (i != 0) putchar(',');
189 				printf("{%u,%llu}", num_pixels, g2d_time);
190 			} else {
191 				printf("num_pixels = %u, usecs = %llu\n", num_pixels, g2d_time);
192 			}
193 		}
194 	}
195 
196 	if (output_mathematica)
197 		printf("}\n");
198 
199 	free(images);
200 
201 	return ret;
202 }
203 
usage(const char * name)204 static void usage(const char *name)
205 {
206 	fprintf(stderr, "usage: %s [-ibwh]\n\n", name);
207 
208 	fprintf(stderr, "\t-i <number of iterations>\n");
209 	fprintf(stderr, "\t-b <size of a batch> (default = 3)\n\n");
210 
211 	fprintf(stderr, "\t-w <buffer width> (default = 4096)\n");
212 	fprintf(stderr, "\t-h <buffer height> (default = 4096)\n\n");
213 
214 	fprintf(stderr, "\t-M <enable Mathematica styled output>\n");
215 
216 	exit(0);
217 }
218 
main(int argc,char ** argv)219 int main(int argc, char **argv)
220 {
221 	int fd, ret, c, parsefail;
222 
223 	struct exynos_device *dev;
224 	struct g2d_context *ctx;
225 	struct exynos_bo *bo;
226 
227 	unsigned int iters = 0, batch = 3;
228 	unsigned int bufw = 4096, bufh = 4096;
229 
230 	ret = 0;
231 	parsefail = 0;
232 
233 	while ((c = getopt(argc, argv, "i:b:w:h:M")) != -1) {
234 		switch (c) {
235 		case 'i':
236 			if (sscanf(optarg, "%u", &iters) != 1)
237 				parsefail = 1;
238 			break;
239 		case 'b':
240 			if (sscanf(optarg, "%u", &batch) != 1)
241 				parsefail = 1;
242 			break;
243 		case 'w':
244 			if (sscanf(optarg, "%u", &bufw) != 1)
245 				parsefail = 1;
246 			break;
247 		case 'h':
248 			if (sscanf(optarg, "%u", &bufh) != 1)
249 				parsefail = 1;
250 			break;
251 		case 'M':
252 			output_mathematica = 1;
253 			break;
254 		default:
255 			parsefail = 1;
256 			break;
257 		}
258 	}
259 
260 	if (parsefail || (argc == 1) || (iters == 0))
261 		usage(argv[0]);
262 
263 	if (bufw < 2 || bufw > 4096 || bufh < 2 || bufh > 4096) {
264 		fprintf(stderr, "error: buffer width/height should be in the range 2 to 4096.\n");
265 		ret = -1;
266 
267 		goto out;
268 	}
269 
270 	if (bufw == 0 || bufh == 0) {
271 		fprintf(stderr, "error: buffer width/height should be non-zero.\n");
272 		ret = -1;
273 
274 		goto out;
275 	}
276 
277 	fd = drmOpen("exynos", NULL);
278 	if (fd < 0) {
279 		fprintf(stderr, "error: failed to open drm\n");
280 		ret = -1;
281 
282 		goto out;
283 	}
284 
285 	dev = exynos_device_create(fd);
286 	if (dev == NULL) {
287 		fprintf(stderr, "error: failed to create device\n");
288 		ret = -2;
289 
290 		goto fail;
291 	}
292 
293 	ctx = g2d_init(fd);
294 	if (ctx == NULL) {
295 		fprintf(stderr, "error: failed to init G2D\n");
296 		ret = -3;
297 
298 		goto g2d_fail;
299 	}
300 
301 	bo = exynos_bo_create(dev, bufw * bufh * 4, 0);
302 	if (bo == NULL) {
303 		fprintf(stderr, "error: failed to create bo\n");
304 		ret = -4;
305 
306 		goto bo_fail;
307 	}
308 
309 	ret = fimg2d_perf_simple(bo, ctx, bufw, bufh, iters);
310 
311 	if (ret == 0)
312 		ret = fimg2d_perf_multi(bo, ctx, bufw, bufh, iters, batch);
313 
314 	exynos_bo_destroy(bo);
315 
316 bo_fail:
317 	g2d_fini(ctx);
318 
319 g2d_fail:
320 	exynos_device_destroy(dev);
321 
322 fail:
323 	drmClose(fd);
324 
325 out:
326 	return ret;
327 }
328