basex.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Tests for basex.h
  3. *
  4. * Copyright (C) 2008 iptelorg GmbH
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*#define NO_BASE64_LOOKUP_TABLE
  19. #define SINGLE_REG */
  20. #include "../basex.h"
  21. #include "profile.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <errno.h>
  29. #include <string.h>
  30. #include <time.h>
  31. #include <ctype.h>
  32. #ifndef MIN
  33. #define MIN(a,b) (((a)<(b))?(a):(b))
  34. #endif
  35. #define BASE64 64
  36. #define Q_BASE64 640
  37. #define BASE16 16
  38. #ifndef BASEX
  39. #define BASEX BASE16
  40. #endif
  41. #if BASEX == Q_BASE64
  42. #warning Q_BASE64
  43. #define B_ENC q_base64_enc
  44. #define B_DEC q_base64_dec
  45. #define B_ENC_LEN(l) (((l)+2)/3*4)
  46. #elif BASEX == BASE16
  47. #warning BASE16
  48. #define B_ENC base16_enc
  49. #define B_DEC base16_dec
  50. #define B_ENC_LEN(l) ((l)*2)
  51. #else
  52. #warning BASE64
  53. #define B_ENC base64_enc
  54. #define B_DEC base64_dec
  55. #define B_ENC_LEN(l) (((l)+2)/3*4)
  56. #endif
  57. #define QUOTE_MACRO(x) QUOTEME(x)
  58. #define QUOTEME(x) #x
  59. static char* id="$Id$";
  60. static char* version="basex test 0.1 "
  61. "BASE" QUOTE_MACRO(BASEX) ": " QUOTE_MACRO(B_ENC) ", " QUOTE_MACRO(B_DEC) ""
  62. #if defined BASE64_LOOKUP_TABLE
  63. #ifdef BASE64_LOOKUP_LARGE
  64. " (large b64 lookup table)"
  65. #else
  66. " (lookup b64 table)"
  67. #endif
  68. #else
  69. " (no b64 lookup table)"
  70. #endif
  71. #if defined BASE16_LOOKUP_TABLE
  72. #ifdef BASE16_LOOKUP_LARGE
  73. " (large b16 lookup table)"
  74. #else
  75. " (lookup b16 table)"
  76. #endif
  77. #else
  78. " (no b16 lookup table)"
  79. #endif
  80. #if defined BASE64_READ_WHOLE_INTS || defined BASE16_READ_WHOLE_INTS
  81. " (read 4 bytes at a time)"
  82. #else
  83. " (read 1 byte at a time)"
  84. #endif
  85. ;
  86. static char* help_msg="\
  87. Usage: basex [-hv] ... [options]\n\
  88. Options:\n\
  89. -m min minimum length\n\
  90. -M max maximum length\n\
  91. -o offset offset from the start of the buffer (alignment tests)\n\
  92. -e offset offset from the start of the dst. buf. (alignment tests)\n\
  93. -n no. number of test loops\n\
  94. -v increase verbosity\n\
  95. -V version number\n\
  96. -h this help message\n\
  97. ";
  98. /* profiling */
  99. struct profile_data pf1, pf2, pf3, pf4, pf5, pf6;
  100. void dump_profile_info(struct profile_data* pd)
  101. {
  102. printf("profiling for %s (%ld/%ld): %lld/%lld/%lld (max/avg/last),"
  103. " total %lld\n",
  104. pd->name, pd->entries, pd->exits, pd->max_cycles,
  105. pd->entries?pd->total_cycles/pd->entries:0, pd->cycles,
  106. pd->total_cycles);
  107. }
  108. int seed_prng()
  109. {
  110. int seed, rfd;
  111. if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
  112. try_again:
  113. if (read(rfd, (void*)&seed, sizeof(seed))==-1){
  114. if (errno==EINTR) goto try_again; /* interrupted by signal */
  115. fprintf(stderr, "WARNING: could not read from /dev/urandom: "
  116. " %s (%d)\n", strerror(errno), errno);
  117. }
  118. close(rfd);
  119. }else{
  120. fprintf(stderr, "WARNING: could not open /dev/urandom: %s (%d)\n",
  121. strerror(errno), errno);
  122. }
  123. seed+=getpid()+time(0);
  124. srand(seed);
  125. return 0;
  126. }
  127. /* fill buf with random data*/
  128. void fill_rand(unsigned char* buf, int len)
  129. {
  130. unsigned char* end;
  131. int v;
  132. /* find out how many random bytes we can get from rand() */
  133. #if RAND_MAX >= 0xffffffff
  134. #define RAND_BYTES 4
  135. #warning RAND_BYTES is 4
  136. #elif RAND_MAX >= 0xffffff
  137. #define RAND_BYTES 3
  138. #warning RAND_BYTES is 3
  139. #elif RAND_MAX >= 0xffff
  140. #define RAND_BYTES 2
  141. #warning RAND_BYTES is 2
  142. #else
  143. #define RAND_BYTES 1
  144. #endif
  145. end=buf+len/RAND_BYTES*RAND_BYTES;
  146. for(;buf<end;buf+=RAND_BYTES){
  147. v=rand();
  148. buf[0]=v;
  149. #if RAND_BYTES > 1
  150. buf[1]=v>>8;
  151. #endif
  152. #if RAND_BYTES > 2
  153. buf[2]=v>>16;
  154. #endif
  155. #if RAND_BYTES > 4
  156. buf[3]=v>>24;
  157. #endif
  158. }
  159. v=rand();
  160. switch(end-buf){
  161. case 3:
  162. #if RAND_BYTES > 2
  163. buf[2]=v>>16;
  164. #else
  165. buf[2]=rand();
  166. #endif
  167. case 2:
  168. #if RAND_BYTES > 1
  169. buf[1]=v>>8;
  170. #else
  171. buf[1]=rand();
  172. #endif
  173. case 1:
  174. buf[0]=v;
  175. case 0:
  176. break;
  177. }
  178. }
  179. int main(int argc, char** argv)
  180. {
  181. int loops, min_len, max_len, offset, e_offset;
  182. unsigned char* ibuf;
  183. unsigned char* enc_buf;
  184. unsigned char* dec_buf;
  185. int ibuf_len, enc_buf_len, dec_buf_len;
  186. int offs, c_len, e_len, l;
  187. int r;
  188. int verbose;
  189. int c;
  190. char* tmp;
  191. verbose=0;
  192. min_len=max_len=offset=-1;
  193. e_offset=0;
  194. loops=1024;
  195. opterr=0;
  196. while ((c=getopt(argc, argv, "n:m:M:o:e:vhV"))!=-1){
  197. switch(c){
  198. case 'n':
  199. loops=strtol(optarg, &tmp, 0);
  200. if ((tmp==0)||(*tmp)||(loops<0)){
  201. fprintf(stderr, "bad number: -%c %s\n", c, optarg);
  202. goto error;
  203. }
  204. break;
  205. case 'm':
  206. min_len=strtol(optarg, &tmp, 0);
  207. if ((tmp==0)||(*tmp)||(min_len<0)){
  208. fprintf(stderr, "bad number: -%c %s\n", c, optarg);
  209. goto error;
  210. }
  211. break;
  212. case 'M':
  213. max_len=strtol(optarg, &tmp, 0);
  214. if ((tmp==0)||(*tmp)||(max_len<0)){
  215. fprintf(stderr, "bad number: -%c %s\n", c, optarg);
  216. goto error;
  217. }
  218. break;
  219. case 'o':
  220. offset=strtol(optarg, &tmp, 0);
  221. if ((tmp==0)||(*tmp)||(offset<0)){
  222. fprintf(stderr, "bad number: -%c %s\n", c, optarg);
  223. goto error;
  224. }
  225. break;
  226. case 'e':
  227. e_offset=strtol(optarg, &tmp, 0);
  228. if ((tmp==0)||(*tmp)||(e_offset<0)){
  229. fprintf(stderr, "bad number: -%c %s\n", c, optarg);
  230. goto error;
  231. }
  232. break;
  233. case 'v':
  234. verbose++;
  235. break;
  236. case 'V':
  237. printf("version: %s\n", version);
  238. printf("%s\n", id);
  239. exit(0);
  240. break;
  241. case 'h':
  242. printf("version: %s\n", version);
  243. printf("%s", help_msg);
  244. exit(0);
  245. break;
  246. case '?':
  247. if (isprint(optopt))
  248. fprintf(stderr, "Unknown option `-%c\n", optopt);
  249. else
  250. fprintf(stderr, "Unknown character `\\x%x\n", optopt);
  251. goto error;
  252. case ':':
  253. fprintf(stderr, "Option `-%c requires an argument.\n",
  254. optopt);
  255. goto error;
  256. break;
  257. default:
  258. abort();
  259. }
  260. }
  261. if (min_len==-1 && max_len==-1){
  262. min_len=0;
  263. max_len=4*1024*1024;
  264. }else if (min_len==-1)
  265. min_len=0;
  266. else if (max_len==-1)
  267. max_len=min_len;
  268. /* init */
  269. ibuf_len=max_len;
  270. ibuf=malloc(ibuf_len);
  271. if (ibuf==0){
  272. fprintf(stderr, "ERROR: 1. memory allocation error (%d bytes)\n",
  273. ibuf_len);
  274. exit(-1);
  275. }
  276. enc_buf_len=B_ENC_LEN(ibuf_len);
  277. enc_buf=malloc(enc_buf_len+e_offset);
  278. if (enc_buf==0){
  279. fprintf(stderr, "ERROR: 2. memory allocation error (%d bytes)\n",
  280. enc_buf_len);
  281. exit(-1);
  282. }
  283. enc_buf+=e_offset; /* make sure it's off by e_offset bytes from the
  284. aligned stuff malloc returns */
  285. dec_buf_len=ibuf_len;
  286. dec_buf=malloc(dec_buf_len+e_offset);
  287. if (dec_buf==0){
  288. fprintf(stderr, "ERROR: 3. memory allocation error (%d bytes)\n",
  289. dec_buf_len+e_offset);
  290. exit(-1);
  291. }
  292. dec_buf+=e_offset; /* make sure it's off by e_offset bytes from the
  293. aligned stuff malloc returns */
  294. seed_prng();
  295. /* profile */
  296. profile_init(&pf1, "encode");
  297. profile_init(&pf2, "decode");
  298. init_basex();
  299. if (verbose)
  300. printf("starting (loops %d, min size %d, max size %d, offset %d,"
  301. ", e_offset %d, buffer sizes %d %d %d)\n",
  302. loops, min_len, max_len, offset, e_offset, ibuf_len,
  303. enc_buf_len, dec_buf_len);
  304. for (r=0; r<loops; r++){
  305. if (min_len!=max_len)
  306. /* test encode/decode random data w/ random length*/
  307. c_len= min_len+(int)((float)(max_len-min_len+1)*
  308. (rand()/(RAND_MAX+1.0)));
  309. else
  310. /* test encode /decode random data w/ fixed length*/
  311. c_len=max_len;
  312. if (offset==-1)
  313. /* offset between 0 & MIN(clen,3) */
  314. offs= (int)((float)(MIN(c_len,3)+1)*(rand()/(RAND_MAX+1.0)));
  315. else if (offset>c_len)
  316. offs=0;
  317. else
  318. offs=offset;
  319. if (verbose>2)
  320. printf("loop %d, current len %d, offset %d, start %p\n",
  321. r, c_len-offs, offs, &ibuf[offs]);
  322. else if ((verbose >1) && (r %10==0)) putchar('.');
  323. fill_rand(ibuf, c_len);
  324. c_len-=offs;
  325. e_len=B_ENC_LEN(c_len);
  326. profile_start(&pf1);
  327. l=B_ENC(&ibuf[offs], c_len, enc_buf, e_len);
  328. profile_end(&pf1);
  329. if (l != e_len){
  330. fprintf(stderr, "ERROR: invalid length for encoding: %d "
  331. "instead of %d (loops=%d)\n", l, e_len, r);
  332. exit(-1);
  333. }
  334. profile_start(&pf2);
  335. l=B_DEC(enc_buf, e_len, dec_buf, c_len);
  336. profile_end(&pf2);
  337. if (l != c_len){
  338. fprintf(stderr, "ERROR: invalid length for decoding: %d "
  339. "instead of %d (loops=%d)\n", l, c_len, r);
  340. exit(-1);
  341. }
  342. if (memcmp(&ibuf[offs], dec_buf, c_len)!=0){
  343. fprintf(stderr, "ERROR: decoding mismatch "
  344. "(loops=%d, c_len=%d)\n", r, c_len);
  345. abort();
  346. exit(-1);
  347. }
  348. }
  349. if (verbose >1) putchar('\n');
  350. /* encode len data and decode it, print profiling info*/
  351. dump_profile_info(&pf1);
  352. dump_profile_info(&pf2);
  353. return 0;
  354. error:
  355. exit(-1);
  356. }