dct-test: make speed test optional
[ffmpeg.git] / libavcodec / dct-test.c
1 /*
2  * (c) 2001 Fabrice Bellard
3  *     2007 Marc Hoffman <marc.hoffman@analog.com>
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * DCT test (c) 2001 Fabrice Bellard
25  * Started from sample code by Juan J. Sierralta P.
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/time.h>
32 #include <unistd.h>
33 #include <math.h>
34
35 #include "libavutil/cpu.h"
36 #include "libavutil/common.h"
37 #include "libavutil/lfg.h"
38
39 #include "simple_idct.h"
40 #include "aandcttab.h"
41 #include "faandct.h"
42 #include "faanidct.h"
43 #include "x86/idct_xvid.h"
44 #include "dctref.h"
45
46 #undef printf
47
48 void ff_mmx_idct(DCTELEM *data);
49 void ff_mmxext_idct(DCTELEM *data);
50
51 void odivx_idct_c(short *block);
52
53 // BFIN
54 void ff_bfin_idct(DCTELEM *block);
55 void ff_bfin_fdct(DCTELEM *block);
56
57 // ALTIVEC
58 void fdct_altivec(DCTELEM *block);
59 //void idct_altivec(DCTELEM *block);?? no routine
60
61 // ARM
62 void ff_j_rev_dct_arm(DCTELEM *data);
63 void ff_simple_idct_arm(DCTELEM *data);
64 void ff_simple_idct_armv5te(DCTELEM *data);
65 void ff_simple_idct_armv6(DCTELEM *data);
66 void ff_simple_idct_neon(DCTELEM *data);
67
68 void ff_simple_idct_axp(DCTELEM *data);
69
70 struct algo {
71     const char *name;
72     void (*func)(DCTELEM *block);
73     void (*ref) (DCTELEM *block);
74     enum formattag { NO_PERM, MMX_PERM, MMX_SIMPLE_PERM, SCALE_PERM,
75                      SSE2_PERM, PARTTRANS_PERM } format;
76     int mm_support;
77 };
78
79 #ifndef FAAN_POSTSCALE
80 #define FAAN_SCALE SCALE_PERM
81 #else
82 #define FAAN_SCALE NO_PERM
83 #endif
84
85 static int cpu_flags;
86
87 static const struct algo fdct_tab[] = {
88     {"REF-DBL",         ff_ref_fdct,        ff_ref_fdct, NO_PERM},
89     {"FAAN",            ff_faandct,         ff_ref_fdct, FAAN_SCALE},
90     {"IJG-AAN-INT",     fdct_ifast,         ff_ref_fdct, SCALE_PERM},
91     {"IJG-LLM-INT",     ff_jpeg_fdct_islow, ff_ref_fdct, NO_PERM},
92
93 #if HAVE_MMX
94     {"MMX",             ff_fdct_mmx,        ff_ref_fdct, NO_PERM, AV_CPU_FLAG_MMX},
95     {"MMX2",            ff_fdct_mmx2,       ff_ref_fdct, NO_PERM, AV_CPU_FLAG_MMX2},
96     {"SSE2",            ff_fdct_sse2,       ff_ref_fdct, NO_PERM, AV_CPU_FLAG_SSE2},
97 #endif
98
99 #if HAVE_ALTIVEC
100     {"altivecfdct",     fdct_altivec,       ff_ref_fdct, NO_PERM, AV_CPU_FLAG_ALTIVEC},
101 #endif
102
103 #if ARCH_BFIN
104     {"BFINfdct",        ff_bfin_fdct,       ff_ref_fdct, NO_PERM},
105 #endif
106
107     { 0 }
108 };
109
110 static const struct algo idct_tab[] = {
111     {"FAANI",           ff_faanidct,        ff_ref_idct, NO_PERM},
112     {"REF-DBL",         ff_ref_idct,        ff_ref_idct, NO_PERM},
113     {"INT",             j_rev_dct,          ff_ref_idct, MMX_PERM},
114     {"SIMPLE-C",        ff_simple_idct,     ff_ref_idct, NO_PERM},
115
116 #if HAVE_MMX
117 #if CONFIG_GPL
118     {"LIBMPEG2-MMX",    ff_mmx_idct,        ff_ref_idct, MMX_PERM, AV_CPU_FLAG_MMX},
119     {"LIBMPEG2-MMX2",   ff_mmxext_idct,     ff_ref_idct, MMX_PERM, AV_CPU_FLAG_MMX2},
120 #endif
121     {"SIMPLE-MMX",      ff_simple_idct_mmx, ff_ref_idct, MMX_SIMPLE_PERM, AV_CPU_FLAG_MMX},
122     {"XVID-MMX",        ff_idct_xvid_mmx,   ff_ref_idct, NO_PERM, AV_CPU_FLAG_MMX},
123     {"XVID-MMX2",       ff_idct_xvid_mmx2,  ff_ref_idct, NO_PERM, AV_CPU_FLAG_MMX2},
124     {"XVID-SSE2",       ff_idct_xvid_sse2,  ff_ref_idct, SSE2_PERM, AV_CPU_FLAG_SSE2},
125 #endif
126
127 #if ARCH_BFIN
128     {"BFINidct",        ff_bfin_idct,       ff_ref_idct, NO_PERM},
129 #endif
130
131 #if ARCH_ARM
132     {"SIMPLE-ARM",      ff_simple_idct_arm, ff_ref_idct, NO_PERM },
133     {"INT-ARM",         ff_j_rev_dct_arm,   ff_ref_idct, MMX_PERM },
134 #endif
135 #if HAVE_ARMV5TE
136     {"SIMPLE-ARMV5TE",  ff_simple_idct_armv5te, ff_ref_idct, NO_PERM },
137 #endif
138 #if HAVE_ARMV6
139     {"SIMPLE-ARMV6",    ff_simple_idct_armv6, ff_ref_idct, MMX_PERM },
140 #endif
141 #if HAVE_NEON
142     {"SIMPLE-NEON",     ff_simple_idct_neon, ff_ref_idct, PARTTRANS_PERM },
143 #endif
144
145 #if ARCH_ALPHA
146     {"SIMPLE-ALPHA",    ff_simple_idct_axp,  ff_ref_idct, NO_PERM },
147 #endif
148
149     { 0 }
150 };
151
152 #define AANSCALE_BITS 12
153
154 uint8_t cropTbl[256 + 2 * MAX_NEG_CROP];
155
156 static int64_t gettime(void)
157 {
158     struct timeval tv;
159     gettimeofday(&tv, NULL);
160     return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
161 }
162
163 #define NB_ITS 20000
164 #define NB_ITS_SPEED 50000
165
166 static short idct_mmx_perm[64];
167
168 static short idct_simple_mmx_perm[64] = {
169     0x00, 0x08, 0x04, 0x09, 0x01, 0x0C, 0x05, 0x0D,
170     0x10, 0x18, 0x14, 0x19, 0x11, 0x1C, 0x15, 0x1D,
171     0x20, 0x28, 0x24, 0x29, 0x21, 0x2C, 0x25, 0x2D,
172     0x12, 0x1A, 0x16, 0x1B, 0x13, 0x1E, 0x17, 0x1F,
173     0x02, 0x0A, 0x06, 0x0B, 0x03, 0x0E, 0x07, 0x0F,
174     0x30, 0x38, 0x34, 0x39, 0x31, 0x3C, 0x35, 0x3D,
175     0x22, 0x2A, 0x26, 0x2B, 0x23, 0x2E, 0x27, 0x2F,
176     0x32, 0x3A, 0x36, 0x3B, 0x33, 0x3E, 0x37, 0x3F,
177 };
178
179 static const uint8_t idct_sse2_row_perm[8] = { 0, 4, 1, 5, 2, 6, 3, 7 };
180
181 static void idct_mmx_init(void)
182 {
183     int i;
184
185     /* the mmx/mmxext idct uses a reordered input, so we patch scan tables */
186     for (i = 0; i < 64; i++) {
187         idct_mmx_perm[i] = (i & 0x38) | ((i & 6) >> 1) | ((i & 1) << 2);
188     }
189 }
190
191 DECLARE_ALIGNED(16, static DCTELEM, block)[64];
192 DECLARE_ALIGNED(8,  static DCTELEM, block1)[64];
193 DECLARE_ALIGNED(8,  static DCTELEM, block_org)[64];
194
195 static inline void mmx_emms(void)
196 {
197 #if HAVE_MMX
198     if (cpu_flags & AV_CPU_FLAG_MMX)
199         __asm__ volatile ("emms\n\t");
200 #endif
201 }
202
203 static void dct_error(const struct algo *dct, int test, int is_idct, int speed)
204 {
205     int it, i, scale;
206     int err_inf, v;
207     int64_t err2, ti, ti1, it1;
208     int64_t sysErr[64], sysErrMax = 0;
209     int maxout = 0;
210     int blockSumErrMax = 0, blockSumErr;
211     AVLFG prng;
212
213     av_lfg_init(&prng, 1);
214
215     err_inf = 0;
216     err2 = 0;
217     for (i = 0; i < 64; i++)
218         sysErr[i] = 0;
219     for (it = 0; it < NB_ITS; it++) {
220         for (i = 0; i < 64; i++)
221             block1[i] = 0;
222         switch (test) {
223         case 0:
224             for (i = 0; i < 64; i++)
225                 block1[i] = (av_lfg_get(&prng) % 512) - 256;
226             if (is_idct) {
227                 ff_ref_fdct(block1);
228                 for (i = 0; i < 64; i++)
229                     block1[i] >>= 3;
230             }
231             break;
232         case 1: {
233                 int num = av_lfg_get(&prng) % 10 + 1;
234                 for (i = 0; i < num; i++)
235                     block1[av_lfg_get(&prng) % 64] =
236                         av_lfg_get(&prng) % 512 - 256;
237             }
238             break;
239         case 2:
240             block1[0] = av_lfg_get(&prng) % 4096 - 2048;
241             block1[63] = (block1[0] & 1) ^ 1;
242             break;
243         }
244
245         for (i = 0; i < 64; i++)
246             block_org[i] = block1[i];
247
248         if (dct->format == MMX_PERM) {
249             for (i = 0; i < 64; i++)
250                 block[idct_mmx_perm[i]] = block1[i];
251         } else if (dct->format == MMX_SIMPLE_PERM) {
252             for (i = 0; i < 64; i++)
253                 block[idct_simple_mmx_perm[i]] = block1[i];
254         } else if (dct->format == SSE2_PERM) {
255             for (i = 0; i < 64; i++)
256                 block[(i & 0x38) | idct_sse2_row_perm[i & 7]] = block1[i];
257         } else if (dct->format == PARTTRANS_PERM) {
258             for (i = 0; i < 64; i++)
259                 block[(i & 0x24) | ((i & 3) << 3) | ((i >> 3) & 3)] = block1[i];
260         } else {
261             for (i = 0; i < 64; i++)
262                 block[i] = block1[i];
263         }
264
265         dct->func(block);
266         mmx_emms();
267
268         if (dct->format == SCALE_PERM) {
269             for (i = 0; i < 64; i++) {
270                 scale = 8 * (1 << (AANSCALE_BITS + 11)) / ff_aanscales[i];
271                 block[i] = (block[i] * scale) >> AANSCALE_BITS;
272             }
273         }
274
275         dct->ref(block1);
276
277         blockSumErr = 0;
278         for (i = 0; i < 64; i++) {
279             v = abs(block[i] - block1[i]);
280             if (v > err_inf)
281                 err_inf = v;
282             err2 += v * v;
283             sysErr[i] += block[i] - block1[i];
284             blockSumErr += v;
285             if (abs(block[i]) > maxout)
286                 maxout = abs(block[i]);
287         }
288         if (blockSumErrMax < blockSumErr)
289             blockSumErrMax = blockSumErr;
290     }
291     for (i = 0; i < 64; i++)
292         sysErrMax = FFMAX(sysErrMax, FFABS(sysErr[i]));
293
294     for (i = 0; i < 64; i++) {
295         if (i % 8 == 0)
296             printf("\n");
297         printf("%7d ", (int) sysErr[i]);
298     }
299     printf("\n");
300
301     printf("%s %s: err_inf=%d err2=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
302            is_idct ? "IDCT" : "DCT", dct->name, err_inf,
303            (double) err2 / NB_ITS / 64.0, (double) sysErrMax / NB_ITS,
304            maxout, blockSumErrMax);
305
306     if (!speed)
307         return;
308
309     /* speed test */
310     for (i = 0; i < 64; i++)
311         block1[i] = 0;
312
313     switch (test) {
314     case 0:
315         for (i = 0; i < 64; i++)
316             block1[i] = av_lfg_get(&prng) % 512 - 256;
317         if (is_idct) {
318             ff_ref_fdct(block1);
319             for (i = 0; i < 64; i++)
320                 block1[i] >>= 3;
321         }
322         break;
323     case 1:
324     case 2:
325         block1[0] = av_lfg_get(&prng) % 512 - 256;
326         block1[1] = av_lfg_get(&prng) % 512 - 256;
327         block1[2] = av_lfg_get(&prng) % 512 - 256;
328         block1[3] = av_lfg_get(&prng) % 512 - 256;
329         break;
330     }
331
332     if (dct->format == MMX_PERM) {
333         for (i = 0; i < 64; i++)
334             block[idct_mmx_perm[i]] = block1[i];
335     } else if (dct->format == MMX_SIMPLE_PERM) {
336         for (i = 0; i < 64; i++)
337             block[idct_simple_mmx_perm[i]] = block1[i];
338     } else {
339         for (i = 0; i < 64; i++)
340             block[i] = block1[i];
341     }
342
343     ti = gettime();
344     it1 = 0;
345     do {
346         for (it = 0; it < NB_ITS_SPEED; it++) {
347             for (i = 0; i < 64; i++)
348                 block[i] = block1[i];
349             dct->func(block);
350         }
351         it1 += NB_ITS_SPEED;
352         ti1 = gettime() - ti;
353     } while (ti1 < 1000000);
354     mmx_emms();
355
356     printf("%s %s: %0.1f kdct/s\n", is_idct ? "IDCT" : "DCT", dct->name,
357            (double) it1 * 1000.0 / (double) ti1);
358 }
359
360 DECLARE_ALIGNED(8, static uint8_t, img_dest)[64];
361 DECLARE_ALIGNED(8, static uint8_t, img_dest1)[64];
362
363 static void idct248_ref(uint8_t *dest, int linesize, int16_t *block)
364 {
365     static int init;
366     static double c8[8][8];
367     static double c4[4][4];
368     double block1[64], block2[64], block3[64];
369     double s, sum, v;
370     int i, j, k;
371
372     if (!init) {
373         init = 1;
374
375         for (i = 0; i < 8; i++) {
376             sum = 0;
377             for (j = 0; j < 8; j++) {
378                 s = (i == 0) ? sqrt(1.0 / 8.0) : sqrt(1.0 / 4.0);
379                 c8[i][j] = s * cos(M_PI * i * (j + 0.5) / 8.0);
380                 sum += c8[i][j] * c8[i][j];
381             }
382         }
383
384         for (i = 0; i < 4; i++) {
385             sum = 0;
386             for (j = 0; j < 4; j++) {
387                 s = (i == 0) ? sqrt(1.0 / 4.0) : sqrt(1.0 / 2.0);
388                 c4[i][j] = s * cos(M_PI * i * (j + 0.5) / 4.0);
389                 sum += c4[i][j] * c4[i][j];
390             }
391         }
392     }
393
394     /* butterfly */
395     s = 0.5 * sqrt(2.0);
396     for (i = 0; i < 4; i++) {
397         for (j = 0; j < 8; j++) {
398             block1[8 * (2 * i) + j] =
399                 (block[8 * (2 * i) + j] + block[8 * (2 * i + 1) + j]) * s;
400             block1[8 * (2 * i + 1) + j] =
401                 (block[8 * (2 * i) + j] - block[8 * (2 * i + 1) + j]) * s;
402         }
403     }
404
405     /* idct8 on lines */
406     for (i = 0; i < 8; i++) {
407         for (j = 0; j < 8; j++) {
408             sum = 0;
409             for (k = 0; k < 8; k++)
410                 sum += c8[k][j] * block1[8 * i + k];
411             block2[8 * i + j] = sum;
412         }
413     }
414
415     /* idct4 */
416     for (i = 0; i < 8; i++) {
417         for (j = 0; j < 4; j++) {
418             /* top */
419             sum = 0;
420             for (k = 0; k < 4; k++)
421                 sum += c4[k][j] * block2[8 * (2 * k) + i];
422             block3[8 * (2 * j) + i] = sum;
423
424             /* bottom */
425             sum = 0;
426             for (k = 0; k < 4; k++)
427                 sum += c4[k][j] * block2[8 * (2 * k + 1) + i];
428             block3[8 * (2 * j + 1) + i] = sum;
429         }
430     }
431
432     /* clamp and store the result */
433     for (i = 0; i < 8; i++) {
434         for (j = 0; j < 8; j++) {
435             v = block3[8 * i + j];
436             if      (v < 0)   v = 0;
437             else if (v > 255) v = 255;
438             dest[i * linesize + j] = (int) rint(v);
439         }
440     }
441 }
442
443 static void idct248_error(const char *name,
444                           void (*idct248_put)(uint8_t *dest, int line_size,
445                                               int16_t *block),
446                           int speed)
447 {
448     int it, i, it1, ti, ti1, err_max, v;
449     AVLFG prng;
450
451     av_lfg_init(&prng, 1);
452
453     /* just one test to see if code is correct (precision is less
454        important here) */
455     err_max = 0;
456     for (it = 0; it < NB_ITS; it++) {
457         /* XXX: use forward transform to generate values */
458         for (i = 0; i < 64; i++)
459             block1[i] = av_lfg_get(&prng) % 256 - 128;
460         block1[0] += 1024;
461
462         for (i = 0; i < 64; i++)
463             block[i] = block1[i];
464         idct248_ref(img_dest1, 8, block);
465
466         for (i = 0; i < 64; i++)
467             block[i] = block1[i];
468         idct248_put(img_dest, 8, block);
469
470         for (i = 0; i < 64; i++) {
471             v = abs((int) img_dest[i] - (int) img_dest1[i]);
472             if (v == 255)
473                 printf("%d %d\n", img_dest[i], img_dest1[i]);
474             if (v > err_max)
475                 err_max = v;
476         }
477     }
478     printf("%s %s: err_inf=%d\n", 1 ? "IDCT248" : "DCT248", name, err_max);
479
480     if (!speed)
481         return;
482
483     ti = gettime();
484     it1 = 0;
485     do {
486         for (it = 0; it < NB_ITS_SPEED; it++) {
487             for (i = 0; i < 64; i++)
488                 block[i] = block1[i];
489             idct248_put(img_dest, 8, block);
490         }
491         it1 += NB_ITS_SPEED;
492         ti1 = gettime() - ti;
493     } while (ti1 < 1000000);
494     mmx_emms();
495
496     printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
497            (double) it1 * 1000.0 / (double) ti1);
498 }
499
500 static void help(void)
501 {
502     printf("dct-test [-i] [<test-number>]\n"
503            "test-number 0 -> test with random matrixes\n"
504            "            1 -> test with random sparse matrixes\n"
505            "            2 -> do 3. test from mpeg4 std\n"
506            "-i          test IDCT implementations\n"
507            "-4          test IDCT248 implementations\n"
508            "-t          speed test\n");
509 }
510
511 int main(int argc, char **argv)
512 {
513     int test_idct = 0, test_248_dct = 0;
514     int c, i;
515     int test = 1;
516     int speed = 0;
517
518     cpu_flags = av_get_cpu_flags();
519
520     ff_ref_dct_init();
521     idct_mmx_init();
522
523     for (i = 0; i < 256; i++)
524         cropTbl[i + MAX_NEG_CROP] = i;
525     for (i = 0; i < MAX_NEG_CROP; i++) {
526         cropTbl[i] = 0;
527         cropTbl[i + MAX_NEG_CROP + 256] = 255;
528     }
529
530     for (;;) {
531         c = getopt(argc, argv, "ih4t");
532         if (c == -1)
533             break;
534         switch (c) {
535         case 'i':
536             test_idct = 1;
537             break;
538         case '4':
539             test_248_dct = 1;
540             break;
541         case 't':
542             speed = 1;
543             break;
544         default:
545         case 'h':
546             help();
547             return 0;
548         }
549     }
550
551     if (optind < argc)
552         test = atoi(argv[optind]);
553
554     printf("ffmpeg DCT/IDCT test\n");
555
556     if (test_248_dct) {
557         idct248_error("SIMPLE-C", ff_simple_idct248_put, speed);
558     } else {
559         const struct algo *algos = test_idct ? idct_tab : fdct_tab;
560         for (i = 0; algos[i].name; i++)
561             if (!(~cpu_flags & algos[i].mm_support)) {
562                 dct_error(&algos[i], test, test_idct, speed);
563             }
564     }
565     return 0;
566 }