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