1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <assert.h>
7 #include "benchmark.h"
8 #include "idct.h"
10 // Generate random coefficients in the range [-15..15].
11 void gen_random_coeffs(int16_t* dst, size_t len)
12 {
13         // Standard NR LCG (we avoid rand() to get consistent behavior across platforms).
14         static uint32_t seed = 1234;
15         for (unsigned i = 0; i < len; ++i) {
16                 seed = seed * 1664525U + 1013904223U;
17                 if (seed >> 31) {
18                         dst[i] = (uint8_t)(seed >> 27) & 0x7;
19                 } else {
20                         dst[i] = -((uint8_t)(seed >> 27) & 0x7);
21                 }
22         }
23 }
25 // Test that the input is pretty close to the reference for random inputs.
26 // (If the reference funtion is given in, this becomes a simple test of its
27 // determinism.)
28 void test_random_inputs(idct_func_t* idct)
29 {
30         int16_t coeff[DCTSIZE2];
31         uint32_t quant[DCTSIZE2];
32         uint8_t output[DCTSIZE2];
33         uint8_t reference[DCTSIZE2];
35         // Unit quantization (ie., no scaling).
36         for (unsigned i = 0; i < DCTSIZE2; ++i) {
37                 quant[i] = 1;
38         }
40         for (unsigned i = 0; i < 1000; ++i) {
41                 gen_random_coeffs(coeff, DCTSIZE2);
43                 (*idct)(coeff, quant, output);
44                 (idct_reference)(coeff, quant, reference);
46                 // Find the RMS difference.
47                 int diff_squared = 0;
48                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
49                         diff_squared += (output[i] - reference[i]) * (output[i] - reference[i]);
50                 }
52                 assert(diff_squared <= 5);
53         }
54 }
56 // Test that a single DC coefficient becomes spread out to all blocks.
58 {
59         int16_t coeff[DCTSIZE2] = { 0 };
60         uint32_t quant[DCTSIZE2];
61         uint8_t output[DCTSIZE2];
63         // Unit quantization (ie., no scaling).
64         for (unsigned i = 0; i < DCTSIZE2; ++i) {
65                 quant[i] = 1;
66         }
68         for (unsigned i = 0; i < 255*8; ++i) {
69                 uint32_t reference_value = i / 8;
70                 coeff = i;
72                 (*idct)(coeff, quant, output);
74                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
75                         assert(abs(output[i] - reference_value) <= 1);
76                 }
77         }
78 }
80 double timediff(const struct timeval* a, const struct timeval* b)
81 {
82         return (double)(b->tv_sec - a->tv_sec) +
83                 (double)(b->tv_usec - a->tv_usec) * 1e-6;
84 }
86 void test_performance(idct_func_t* idct)
87 {
88         const unsigned num_runs = (idct == idct_reference) ? 5000 : 5000000;
90         int16_t coeff[DCTSIZE2];
91         uint32_t quant[DCTSIZE2];
92         uint8_t output[DCTSIZE2];
94         gen_random_coeffs(coeff, DCTSIZE2);
96         // Unit quantization (ie., no scaling).
97         for (unsigned i = 0; i < DCTSIZE2; ++i) {
98                 quant[i] = 1;
99         }
101         start_benchmark_timer();
103         for (unsigned i = 0; i < num_runs; ++i) {
104                 (*idct)(coeff, quant, output);
105         }
107         double diff = stop_benchmark_timer();
108         printf("%u runs in %.2f CPU seconds = %.2f IDCTs/sec\n",
109                 num_runs, diff, num_runs / diff);
110 }
112 void test_all_idct(idct_func_t* idct)
113 {
117         printf("  test_random_inputs()\n");
118         test_random_inputs(idct);
120         printf("  performance test: ");
121         test_performance(idct);
122 }
124 int main(void)
125 {
126         printf("idct_reference:\n");
127         test_all_idct(idct_reference);
129         printf("idct_float:\n");
130         test_all_idct(idct_float);
132         printf("All tests pass.\n");
133         return 0;
134 }