bench_dwt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. #include "opj_includes.h"
  32. #ifdef _WIN32
  33. #include <windows.h>
  34. #else
  35. #include <sys/time.h>
  36. #include <sys/resource.h>
  37. #include <sys/times.h>
  38. #endif /* _WIN32 */
  39. OPJ_INT32 getValue(OPJ_UINT32 i)
  40. {
  41. return ((OPJ_INT32)i % 511) - 256;
  42. }
  43. void init_tilec(opj_tcd_tilecomp_t * l_tilec,
  44. OPJ_INT32 x0,
  45. OPJ_INT32 y0,
  46. OPJ_INT32 x1,
  47. OPJ_INT32 y1,
  48. OPJ_UINT32 numresolutions,
  49. OPJ_BOOL irreversible)
  50. {
  51. opj_tcd_resolution_t* l_res;
  52. OPJ_UINT32 resno, l_level_no;
  53. size_t i, nValues;
  54. memset(l_tilec, 0, sizeof(*l_tilec));
  55. l_tilec->x0 = x0;
  56. l_tilec->y0 = y0;
  57. l_tilec->x1 = x1;
  58. l_tilec->y1 = y1;
  59. nValues = (size_t)(l_tilec->x1 - l_tilec->x0) *
  60. (size_t)(l_tilec->y1 - l_tilec->y0);
  61. l_tilec->data = (OPJ_INT32*) opj_malloc(sizeof(OPJ_INT32) * nValues);
  62. assert(l_tilec->data != NULL);
  63. for (i = 0; i < nValues; i++) {
  64. OPJ_INT32 val = getValue((OPJ_UINT32)i);
  65. if (irreversible) {
  66. OPJ_FLOAT32 fVal = (OPJ_FLOAT32)val;
  67. memcpy(&l_tilec->data[i], &fVal, sizeof(OPJ_FLOAT32));
  68. } else {
  69. l_tilec->data[i] = val;
  70. }
  71. }
  72. l_tilec->numresolutions = numresolutions;
  73. l_tilec->minimum_num_resolutions = numresolutions;
  74. l_tilec->resolutions = (opj_tcd_resolution_t*) opj_calloc(
  75. l_tilec->numresolutions,
  76. sizeof(opj_tcd_resolution_t));
  77. l_level_no = l_tilec->numresolutions;
  78. l_res = l_tilec->resolutions;
  79. /* Adapted from opj_tcd_init_tile() */
  80. for (resno = 0; resno < l_tilec->numresolutions; ++resno) {
  81. --l_level_no;
  82. /* border for each resolution level (global) */
  83. l_res->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no);
  84. l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no);
  85. l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no);
  86. l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no);
  87. ++l_res;
  88. }
  89. }
  90. void free_tilec(opj_tcd_tilecomp_t * l_tilec)
  91. {
  92. opj_free(l_tilec->data);
  93. opj_free(l_tilec->resolutions);
  94. }
  95. void usage(void)
  96. {
  97. printf(
  98. "bench_dwt [-decode|encode] [-I] [-size value] [-check] [-display]\n");
  99. printf(
  100. " [-num_resolutions val] [-offset x y] [-num_threads val]\n");
  101. exit(1);
  102. }
  103. OPJ_FLOAT64 opj_clock(void)
  104. {
  105. #ifdef _WIN32
  106. /* _WIN32: use QueryPerformance (very accurate) */
  107. LARGE_INTEGER freq, t ;
  108. /* freq is the clock speed of the CPU */
  109. QueryPerformanceFrequency(&freq) ;
  110. /* cout << "freq = " << ((double) freq.QuadPart) << endl; */
  111. /* t is the high resolution performance counter (see MSDN) */
  112. QueryPerformanceCounter(& t) ;
  113. return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64) freq.QuadPart) : 0 ;
  114. #else
  115. /* Unix or Linux: use resource usage */
  116. struct rusage t;
  117. OPJ_FLOAT64 procTime;
  118. /* (1) Get the rusage data structure at this moment (man getrusage) */
  119. getrusage(0, &t);
  120. /* (2) What is the elapsed time ? - CPU time = User time + System time */
  121. /* (2a) Get the seconds */
  122. procTime = (OPJ_FLOAT64)(t.ru_utime.tv_sec + t.ru_stime.tv_sec);
  123. /* (2b) More precisely! Get the microseconds part ! */
  124. return (procTime + (OPJ_FLOAT64)(t.ru_utime.tv_usec + t.ru_stime.tv_usec) *
  125. 1e-6) ;
  126. #endif
  127. }
  128. static OPJ_FLOAT64 opj_wallclock(void)
  129. {
  130. #ifdef _WIN32
  131. return opj_clock();
  132. #else
  133. struct timeval tv;
  134. gettimeofday(&tv, NULL);
  135. return (OPJ_FLOAT64)tv.tv_sec + 1e-6 * (OPJ_FLOAT64)tv.tv_usec;
  136. #endif
  137. }
  138. int main(int argc, char** argv)
  139. {
  140. int num_threads = 0;
  141. opj_tcd_t tcd;
  142. opj_tcd_image_t tcd_image;
  143. opj_tcd_tile_t tcd_tile;
  144. opj_tcd_tilecomp_t tilec;
  145. opj_image_t image;
  146. opj_image_comp_t image_comp;
  147. opj_thread_pool_t* tp;
  148. OPJ_INT32 i, j, k;
  149. OPJ_BOOL display = OPJ_FALSE;
  150. OPJ_BOOL check = OPJ_FALSE;
  151. OPJ_INT32 size = 16384 - 1;
  152. OPJ_FLOAT64 start, stop;
  153. OPJ_FLOAT64 start_wc, stop_wc;
  154. OPJ_UINT32 offset_x = ((OPJ_UINT32)size + 1) / 2 - 1;
  155. OPJ_UINT32 offset_y = ((OPJ_UINT32)size + 1) / 2 - 1;
  156. OPJ_UINT32 num_resolutions = 6;
  157. OPJ_BOOL bench_decode = OPJ_TRUE;
  158. OPJ_BOOL irreversible = OPJ_FALSE;
  159. for (i = 1; i < argc; i++) {
  160. if (strcmp(argv[i], "-encode") == 0) {
  161. bench_decode = OPJ_FALSE;
  162. } else if (strcmp(argv[i], "-decode") == 0) {
  163. bench_decode = OPJ_TRUE;
  164. } else if (strcmp(argv[i], "-display") == 0) {
  165. display = OPJ_TRUE;
  166. } else if (strcmp(argv[i], "-check") == 0) {
  167. check = OPJ_TRUE;
  168. } else if (strcmp(argv[i], "-I") == 0) {
  169. irreversible = OPJ_TRUE;
  170. } else if (strcmp(argv[i], "-size") == 0 && i + 1 < argc) {
  171. size = atoi(argv[i + 1]);
  172. i ++;
  173. } else if (strcmp(argv[i], "-num_threads") == 0 && i + 1 < argc) {
  174. num_threads = atoi(argv[i + 1]);
  175. i ++;
  176. } else if (strcmp(argv[i], "-num_resolutions") == 0 && i + 1 < argc) {
  177. num_resolutions = (OPJ_UINT32)atoi(argv[i + 1]);
  178. if (num_resolutions == 0 || num_resolutions > 32) {
  179. fprintf(stderr,
  180. "Invalid value for num_resolutions. Should be >= 1 and <= 32\n");
  181. exit(1);
  182. }
  183. i ++;
  184. } else if (strcmp(argv[i], "-offset") == 0 && i + 2 < argc) {
  185. offset_x = (OPJ_UINT32)atoi(argv[i + 1]);
  186. offset_y = (OPJ_UINT32)atoi(argv[i + 2]);
  187. i += 2;
  188. } else {
  189. usage();
  190. }
  191. }
  192. if (irreversible && check) {
  193. /* Due to irreversible inverse DWT not being symmetric of forward */
  194. /* See BUG_WEIRD_TWO_INVK in dwt.c */
  195. printf("-I and -check aren't compatible\n");
  196. exit(1);
  197. }
  198. tp = opj_thread_pool_create(num_threads);
  199. init_tilec(&tilec, (OPJ_INT32)offset_x, (OPJ_INT32)offset_y,
  200. (OPJ_INT32)offset_x + size, (OPJ_INT32)offset_y + size,
  201. num_resolutions, irreversible);
  202. if (display) {
  203. printf("Before\n");
  204. k = 0;
  205. for (j = 0; j < tilec.y1 - tilec.y0; j++) {
  206. for (i = 0; i < tilec.x1 - tilec.x0; i++) {
  207. if (irreversible) {
  208. printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
  209. } else {
  210. printf("%d ", tilec.data[k]);
  211. }
  212. k ++;
  213. }
  214. printf("\n");
  215. }
  216. }
  217. memset(&tcd, 0, sizeof(tcd));
  218. tcd.thread_pool = tp;
  219. tcd.whole_tile_decoding = OPJ_TRUE;
  220. tcd.win_x0 = (OPJ_UINT32)tilec.x0;
  221. tcd.win_y0 = (OPJ_UINT32)tilec.y0;
  222. tcd.win_x1 = (OPJ_UINT32)tilec.x1;
  223. tcd.win_y1 = (OPJ_UINT32)tilec.y1;
  224. tcd.tcd_image = &tcd_image;
  225. memset(&tcd_image, 0, sizeof(tcd_image));
  226. tcd_image.tiles = &tcd_tile;
  227. memset(&tcd_tile, 0, sizeof(tcd_tile));
  228. tcd_tile.x0 = tilec.x0;
  229. tcd_tile.y0 = tilec.y0;
  230. tcd_tile.x1 = tilec.x1;
  231. tcd_tile.y1 = tilec.y1;
  232. tcd_tile.numcomps = 1;
  233. tcd_tile.comps = &tilec;
  234. tcd.image = &image;
  235. memset(&image, 0, sizeof(image));
  236. image.numcomps = 1;
  237. image.comps = &image_comp;
  238. memset(&image_comp, 0, sizeof(image_comp));
  239. image_comp.dx = 1;
  240. image_comp.dy = 1;
  241. start = opj_clock();
  242. start_wc = opj_wallclock();
  243. if (bench_decode) {
  244. if (irreversible) {
  245. opj_dwt_decode_real(&tcd, &tilec, tilec.numresolutions);
  246. } else {
  247. opj_dwt_decode(&tcd, &tilec, tilec.numresolutions);
  248. }
  249. } else {
  250. if (irreversible) {
  251. opj_dwt_encode_real(&tcd, &tilec);
  252. } else {
  253. opj_dwt_encode(&tcd, &tilec);
  254. }
  255. }
  256. stop = opj_clock();
  257. stop_wc = opj_wallclock();
  258. printf("time for %s: total = %.03f s, wallclock = %.03f s\n",
  259. bench_decode ? "dwt_decode" : "dwt_encode",
  260. stop - start,
  261. stop_wc - start_wc);
  262. if (display) {
  263. if (bench_decode) {
  264. printf("After IDWT\n");
  265. } else {
  266. printf("After FDWT\n");
  267. }
  268. k = 0;
  269. for (j = 0; j < tilec.y1 - tilec.y0; j++) {
  270. for (i = 0; i < tilec.x1 - tilec.x0; i++) {
  271. if (irreversible) {
  272. printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
  273. } else {
  274. printf("%d ", tilec.data[k]);
  275. }
  276. k ++;
  277. }
  278. printf("\n");
  279. }
  280. }
  281. if ((display || check) && !irreversible) {
  282. if (bench_decode) {
  283. opj_dwt_encode(&tcd, &tilec);
  284. } else {
  285. opj_dwt_decode(&tcd, &tilec, tilec.numresolutions);
  286. }
  287. if (display && !irreversible) {
  288. if (bench_decode) {
  289. printf("After FDWT\n");
  290. } else {
  291. printf("After IDWT\n");
  292. }
  293. k = 0;
  294. for (j = 0; j < tilec.y1 - tilec.y0; j++) {
  295. for (i = 0; i < tilec.x1 - tilec.x0; i++) {
  296. if (irreversible) {
  297. printf("%f ", ((OPJ_FLOAT32*)tilec.data)[k]);
  298. } else {
  299. printf("%d ", tilec.data[k]);
  300. }
  301. k ++;
  302. }
  303. printf("\n");
  304. }
  305. }
  306. }
  307. if (check) {
  308. size_t idx;
  309. size_t nValues = (size_t)(tilec.x1 - tilec.x0) *
  310. (size_t)(tilec.y1 - tilec.y0);
  311. for (idx = 0; idx < nValues; idx++) {
  312. if (tilec.data[idx] != getValue((OPJ_UINT32)idx)) {
  313. printf("Difference found at idx = %u\n", (OPJ_UINT32)idx);
  314. exit(1);
  315. }
  316. }
  317. }
  318. free_tilec(&tilec);
  319. opj_thread_pool_destroy(tp);
  320. return 0;
  321. }