]> git.sesse.net Git - fjl/blob - idct_test.c
Split the two IDCTs into different files.
[fjl] / idct_test.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <assert.h>
6
7 #include "benchmark.h"
8 #include "idct.h"
9 #include "idct_reference.h"
10 #include "idct_float.h"
11
12 // Generate random coefficients in the range [-15..15].
13 void gen_random_coeffs(int16_t* dst, size_t len)
14 {
15         // Standard NR LCG (we avoid rand() to get consistent behavior across platforms).
16         static uint32_t seed = 1234;
17         for (unsigned i = 0; i < len; ++i) {
18                 seed = seed * 1664525U + 1013904223U;
19                 if (seed >> 31) {
20                         dst[i] = (uint8_t)(seed >> 27) & 0x7;
21                 } else {
22                         dst[i] = -((uint8_t)(seed >> 27) & 0x7);
23                 }
24         }
25 }
26
27 // Test that the input is pretty close to the reference for random inputs. 
28 // (If the reference funtion is given in, this becomes a simple test of its
29 // determinism.)
30 void test_random_inputs(idct_alloc_t* idct_alloc, idct_free_t* idct_free, idct_func_t* idct)
31 {
32         int16_t coeff[DCTSIZE2]; 
33         uint32_t quant[DCTSIZE2];
34         uint8_t output[DCTSIZE2];
35         uint8_t reference[DCTSIZE2];
36
37         // Unit quantization (ie., no scaling).
38         for (unsigned i = 0; i < DCTSIZE2; ++i) {
39                 quant[i] = 1;
40         }
41         
42         void* userdata_reference = idct_reference_alloc(quant);
43         void* userdata = idct_alloc(quant);
44
45         for (unsigned i = 0; i < 1000; ++i) {   
46                 gen_random_coeffs(coeff, DCTSIZE2);
47
48                 (*idct)(coeff, userdata, output);
49                 (idct_reference)(coeff, userdata_reference, reference);
50
51                 // Find the RMS difference.
52                 int diff_squared = 0;
53                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
54                         diff_squared += (output[i] - reference[i]) * (output[i] - reference[i]);
55                 }
56
57                 assert(diff_squared <= 5);
58         }
59
60         idct_reference_free(userdata_reference);
61         idct_free(userdata);
62 }
63
64 // Test that a single DC coefficient becomes spread out to all blocks.
65 void test_dc_becomes_spread_out(idct_alloc_t* idct_alloc, idct_free_t* idct_free, idct_func_t* idct)
66 {
67         int16_t coeff[DCTSIZE2] = { 0 }; 
68         uint32_t quant[DCTSIZE2];
69         uint8_t output[DCTSIZE2];
70         
71         // Unit quantization (ie., no scaling).
72         for (unsigned i = 0; i < DCTSIZE2; ++i) {
73                 quant[i] = 1;
74         }
75
76         void* userdata = idct_alloc(quant);
77
78         for (unsigned i = 0; i < 255*8; ++i) {  
79                 uint32_t reference_value = i / 8;
80                 coeff[0] = i;
81
82                 (*idct)(coeff, userdata, output);
83
84                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
85                         assert(abs(output[i] - reference_value) <= 1);
86                 }
87         }
88         
89         idct_free(userdata);
90 }
91
92 double timediff(const struct timeval* a, const struct timeval* b)
93 {
94         return (double)(b->tv_sec - a->tv_sec) +
95                 (double)(b->tv_usec - a->tv_usec) * 1e-6;
96 }
97
98 void test_performance(idct_alloc_t* idct_alloc, idct_free_t* idct_free, idct_func_t* idct)
99 {
100         const unsigned num_runs = (idct == idct_reference) ? 5000 : 5000000;
101
102         int16_t coeff[DCTSIZE2]; 
103         uint32_t quant[DCTSIZE2];
104         uint8_t output[DCTSIZE2];
105                 
106         gen_random_coeffs(coeff, DCTSIZE2);
107         
108         // Unit quantization (ie., no scaling).
109         for (unsigned i = 0; i < DCTSIZE2; ++i) {
110                 quant[i] = 1;
111         }
112
113         void* userdata = idct_alloc(quant);
114
115         start_benchmark_timer();
116
117         for (unsigned i = 0; i < num_runs; ++i) {
118                 (*idct)(coeff, userdata, output);
119         }
120         
121         double diff = stop_benchmark_timer();
122         printf("%u runs in %.2f CPU seconds = %.2f IDCTs/sec\n",
123                 num_runs, diff, num_runs / diff);
124
125         idct_free(userdata);
126 }
127
128 void test_all_idct(idct_alloc_t* idct_alloc, idct_free_t* idct_free, idct_func_t* idct)
129 {
130         printf("  test_dc_becomes_spread_out()\n");
131         test_dc_becomes_spread_out(idct_alloc, idct_free, idct);        
132
133         printf("  test_random_inputs()\n");
134         test_random_inputs(idct_alloc, idct_free, idct);        
135
136         printf("  performance test: ");
137         test_performance(idct_alloc, idct_free, idct);
138 }
139
140 int main(void)
141 {
142         printf("idct_reference:\n");
143         test_all_idct(idct_reference_alloc, idct_reference_free, idct_reference);
144
145         printf("idct_float:\n");
146         test_all_idct(idct_float_alloc, idct_float_free, idct_float);
147
148         printf("All tests pass.\n");
149         return 0;
150 }