ci: Add CIFuzz action
[openjpeg.git] / src / lib / openjp2 / bench_dwt.c
1 /*
2  * The copyright in this software is being made available under the 2-clauses
3  * BSD License, included below. This software may be subject to other third
4  * party and contributor rights, including patent rights, and no such rights
5  * are granted under this license.
6  *
7  * Copyright (c) 2017, IntoPix SA <contact@intopix.com>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "opj_includes.h"
33
34 #ifdef _WIN32
35 #include <windows.h>
36 #else
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <sys/times.h>
40 #endif /* _WIN32 */
41
42 OPJ_INT32 getValue(OPJ_UINT32 i)
43 {
44     return ((OPJ_INT32)i % 511) - 256;
45 }
46
47 void init_tilec(opj_tcd_tilecomp_t * l_tilec,
48                 OPJ_INT32 x0,
49                 OPJ_INT32 y0,
50                 OPJ_INT32 x1,
51                 OPJ_INT32 y1,
52                 OPJ_UINT32 numresolutions,
53                 OPJ_BOOL irreversible)
54 {
55     opj_tcd_resolution_t* l_res;
56     OPJ_UINT32 resno, l_level_no;
57     size_t i, nValues;
58
59     memset(l_tilec, 0, sizeof(*l_tilec));
60     l_tilec->x0 = x0;
61     l_tilec->y0 = y0;
62     l_tilec->x1 = x1;
63     l_tilec->y1 = y1;
64     nValues = (size_t)(l_tilec->x1 - l_tilec->x0) *
65               (size_t)(l_tilec->y1 - l_tilec->y0);
66     l_tilec->data = (OPJ_INT32*) opj_malloc(sizeof(OPJ_INT32) * nValues);
67     for (i = 0; i < nValues; i++) {
68         OPJ_INT32 val = getValue((OPJ_UINT32)i);
69         if (irreversible) {
70             OPJ_FLOAT32 fVal = (OPJ_FLOAT32)val;
71             memcpy(&l_tilec->data[i], &fVal, sizeof(OPJ_FLOAT32));
72         } else {
73             l_tilec->data[i] = val;
74         }
75     }
76     l_tilec->numresolutions = numresolutions;
77     l_tilec->minimum_num_resolutions = numresolutions;
78     l_tilec->resolutions = (opj_tcd_resolution_t*) opj_calloc(
79                                l_tilec->numresolutions,
80                                sizeof(opj_tcd_resolution_t));
81
82     l_level_no = l_tilec->numresolutions;
83     l_res = l_tilec->resolutions;
84
85     /* Adapted from opj_tcd_init_tile() */
86     for (resno = 0; resno < l_tilec->numresolutions; ++resno) {
87
88         --l_level_no;
89
90         /* border for each resolution level (global) */
91         l_res->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no);
92         l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no);
93         l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no);
94         l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no);
95
96         ++l_res;
97     }
98 }
99
100 void free_tilec(opj_tcd_tilecomp_t * l_tilec)
101 {
102     opj_free(l_tilec->data);
103     opj_free(l_tilec->resolutions);
104 }
105
106 void usage(void)
107 {
108     printf(
109         "bench_dwt [-decode|encode] [-I] [-size value] [-check] [-display]\n");
110     printf(
111         "          [-num_resolutions val] [-offset x y] [-num_threads val]\n");
112     exit(1);
113 }
114
115
116 OPJ_FLOAT64 opj_clock(void)
117 {
118 #ifdef _WIN32
119     /* _WIN32: use QueryPerformance (very accurate) */
120     LARGE_INTEGER freq, t ;
121     /* freq is the clock speed of the CPU */
122     QueryPerformanceFrequency(&freq) ;
123     /* cout << "freq = " << ((double) freq.QuadPart) << endl; */
124     /* t is the high resolution performance counter (see MSDN) */
125     QueryPerformanceCounter(& t) ;
126     return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64) freq.QuadPart) : 0 ;
127 #else
128     /* Unix or Linux: use resource usage */
129     struct rusage t;
130     OPJ_FLOAT64 procTime;
131     /* (1) Get the rusage data structure at this moment (man getrusage) */
132     getrusage(0, &t);
133     /* (2) What is the elapsed time ? - CPU time = User time + System time */
134     /* (2a) Get the seconds */
135     procTime = (OPJ_FLOAT64)(t.ru_utime.tv_sec + t.ru_stime.tv_sec);
136     /* (2b) More precisely! Get the microseconds part ! */
137     return (procTime + (OPJ_FLOAT64)(t.ru_utime.tv_usec + t.ru_stime.tv_usec) *
138             1e-6) ;
139 #endif
140 }
141
142 static OPJ_FLOAT64 opj_wallclock(void)
143 {
144 #ifdef _WIN32
145     return opj_clock();
146 #else
147     struct timeval tv;
148     gettimeofday(&tv, NULL);
149     return (OPJ_FLOAT64)tv.tv_sec + 1e-6 * (OPJ_FLOAT64)tv.tv_usec;
150 #endif
151 }
152
153 int main(int argc, char** argv)
154 {
155     int num_threads = 0;
156     opj_tcd_t tcd;
157     opj_tcd_image_t tcd_image;
158     opj_tcd_tile_t tcd_tile;
159     opj_tcd_tilecomp_t tilec;
160     opj_image_t image;
161     opj_image_comp_t image_comp;
162     opj_thread_pool_t* tp;
163     OPJ_INT32 i, j, k;
164     OPJ_BOOL display = OPJ_FALSE;
165     OPJ_BOOL check = OPJ_FALSE;
166     OPJ_INT32 size = 16384 - 1;
167     OPJ_FLOAT64 start, stop;
168     OPJ_FLOAT64 start_wc, stop_wc;
169     OPJ_UINT32 offset_x = ((OPJ_UINT32)size + 1) / 2 - 1;
170     OPJ_UINT32 offset_y = ((OPJ_UINT32)size + 1) / 2 - 1;
171     OPJ_UINT32 num_resolutions = 6;
172     OPJ_BOOL bench_decode = OPJ_TRUE;
173     OPJ_BOOL irreversible = OPJ_FALSE;
174
175     for (i = 1; i < argc; i++) {
176         if (strcmp(argv[i], "-encode") == 0) {
177             bench_decode = OPJ_FALSE;
178         } else if (strcmp(argv[i], "-decode") == 0) {
179             bench_decode = OPJ_TRUE;
180         } else if (strcmp(argv[i], "-display") == 0) {
181             display = OPJ_TRUE;
182         } else if (strcmp(argv[i], "-check") == 0) {
183             check = OPJ_TRUE;
184         } else if (strcmp(argv[i], "-I") == 0) {
185             irreversible = OPJ_TRUE;
186         } else if (strcmp(argv[i], "-size") == 0 && i + 1 < argc) {
187             size = atoi(argv[i + 1]);
188             i ++;
189         } else if (strcmp(argv[i], "-num_threads") == 0 && i + 1 < argc) {
190             num_threads = atoi(argv[i + 1]);
191             i ++;
192         } else if (strcmp(argv[i], "-num_resolutions") == 0 && i + 1 < argc) {
193             num_resolutions = (OPJ_UINT32)atoi(argv[i + 1]);
194             if (num_resolutions == 0 || num_resolutions > 32) {
195                 fprintf(stderr,
196                         "Invalid value for num_resolutions. Should be >= 1 and <= 32\n");
197                 exit(1);
198             }
199             i ++;
200         } else if (strcmp(argv[i], "-offset") == 0 && i + 2 < argc) {
201             offset_x = (OPJ_UINT32)atoi(argv[i + 1]);
202             offset_y = (OPJ_UINT32)atoi(argv[i + 2]);
203             i += 2;
204         } else {
205             usage();
206         }
207     }
208
209     if (irreversible && check) {
210         /* Due to irreversible inverse DWT not being symetric of forward */
211         /* See BUG_WEIRD_TWO_INVK in dwt.c */
212         printf("-I and -check aren't compatible\n");
213         exit(1);
214     }
215
216     tp = opj_thread_pool_create(num_threads);
217
218     init_tilec(&tilec, (OPJ_INT32)offset_x, (OPJ_INT32)offset_y,
219                (OPJ_INT32)offset_x + size, (OPJ_INT32)offset_y + size,
220                num_resolutions, irreversible);
221
222     if (display) {
223         printf("Before\n");
224         k = 0;
225         for (j = 0; j < tilec.y1 - tilec.y0; j++) {
226             for (i = 0; i < tilec.x1 - tilec.x0; i++) {
227                 if (irreversible) {
228                     printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
229                 } else {
230                     printf("%d ", tilec.data[k]);
231                 }
232                 k ++;
233             }
234             printf("\n");
235         }
236     }
237
238     memset(&tcd, 0, sizeof(tcd));
239     tcd.thread_pool = tp;
240     tcd.whole_tile_decoding = OPJ_TRUE;
241     tcd.win_x0 = (OPJ_UINT32)tilec.x0;
242     tcd.win_y0 = (OPJ_UINT32)tilec.y0;
243     tcd.win_x1 = (OPJ_UINT32)tilec.x1;
244     tcd.win_y1 = (OPJ_UINT32)tilec.y1;
245     tcd.tcd_image = &tcd_image;
246     memset(&tcd_image, 0, sizeof(tcd_image));
247     tcd_image.tiles = &tcd_tile;
248     memset(&tcd_tile, 0, sizeof(tcd_tile));
249     tcd_tile.x0 = tilec.x0;
250     tcd_tile.y0 = tilec.y0;
251     tcd_tile.x1 = tilec.x1;
252     tcd_tile.y1 = tilec.y1;
253     tcd_tile.numcomps = 1;
254     tcd_tile.comps = &tilec;
255     tcd.image = &image;
256     memset(&image, 0, sizeof(image));
257     image.numcomps = 1;
258     image.comps = &image_comp;
259     memset(&image_comp, 0, sizeof(image_comp));
260     image_comp.dx = 1;
261     image_comp.dy = 1;
262
263     start = opj_clock();
264     start_wc = opj_wallclock();
265     if (bench_decode) {
266         if (irreversible)  {
267             opj_dwt_decode_real(&tcd, &tilec, tilec.numresolutions);
268         } else {
269             opj_dwt_decode(&tcd, &tilec, tilec.numresolutions);
270         }
271     } else {
272         if (irreversible)  {
273             opj_dwt_encode_real(&tcd, &tilec);
274         } else {
275             opj_dwt_encode(&tcd, &tilec);
276         }
277     }
278     stop = opj_clock();
279     stop_wc = opj_wallclock();
280     printf("time for %s: total = %.03f s, wallclock = %.03f s\n",
281            bench_decode ? "dwt_decode" : "dwt_encode",
282            stop - start,
283            stop_wc - start_wc);
284
285     if (display) {
286         if (bench_decode) {
287             printf("After IDWT\n");
288         } else {
289             printf("After FDWT\n");
290         }
291         k = 0;
292         for (j = 0; j < tilec.y1 - tilec.y0; j++) {
293             for (i = 0; i < tilec.x1 - tilec.x0; i++) {
294                 if (irreversible) {
295                     printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
296                 } else {
297                     printf("%d ", tilec.data[k]);
298                 }
299                 k ++;
300             }
301             printf("\n");
302         }
303     }
304
305     if ((display || check) && !irreversible) {
306
307         if (bench_decode) {
308             opj_dwt_encode(&tcd, &tilec);
309         } else {
310             opj_dwt_decode(&tcd, &tilec, tilec.numresolutions);
311         }
312
313
314         if (display && !irreversible) {
315             if (bench_decode) {
316                 printf("After FDWT\n");
317             } else {
318                 printf("After IDWT\n");
319             }
320             k = 0;
321             for (j = 0; j < tilec.y1 - tilec.y0; j++) {
322                 for (i = 0; i < tilec.x1 - tilec.x0; i++) {
323                     if (irreversible) {
324                         printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
325                     } else {
326                         printf("%d ", tilec.data[k]);
327                     }
328                     k ++;
329                 }
330                 printf("\n");
331             }
332         }
333
334     }
335
336     if (check) {
337
338         size_t idx;
339         size_t nValues = (size_t)(tilec.x1 - tilec.x0) *
340                          (size_t)(tilec.y1 - tilec.y0);
341         for (idx = 0; idx < nValues; idx++) {
342             if (tilec.data[idx] != getValue((OPJ_UINT32)idx)) {
343                 printf("Difference found at idx = %u\n", (OPJ_UINT32)idx);
344                 exit(1);
345             }
346         }
347     }
348
349     free_tilec(&tilec);
350
351     opj_thread_pool_destroy(tp);
352     return 0;
353 }