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 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 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 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 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