12 #include <crcsync/crcsync.h>
14 #define FULL_BLOCK_COUNT 40
15 const int HASH_SIZE
= 64;
16 const int TEST_ITERATIONS_COUNT
= 100;
20 printf("Error code: %d, msg: %s", errno
, msg
);
33 data_t
*data
= malloc(sizeof(data
));
36 error("Can not allocate data_t structure");
38 data
->bufsize
= 10000;
40 data
->buf
= malloc(data
->bufsize
);
41 if (data
->buf
== NULL
)
43 error("Can not allocate databuf");
48 void append_data(data_t
*data
, unsigned char *buf
, ssize_t bufsize
)
50 while (data
->datasize
+ bufsize
> data
->bufsize
)
52 unsigned char *newdatabuf
= realloc(data
->buf
, data
->bufsize
*2);
53 if (newdatabuf
== NULL
)
55 error("Can not re-allocate databuf");
57 data
->buf
= newdatabuf
;
60 memcpy(data
->buf
+ data
->datasize
, buf
, bufsize
);
61 data
->datasize
+= bufsize
;
64 void free_data(data_t
*data
)
70 data_t
*read_file_to_data(char *fname
)
72 int fh
= open(fname
, O_RDONLY
);
75 error("Can not open file");
78 data_t
*data
= init_data();
79 unsigned char readbuf
[1000];
81 while ((nread
= read(fh
, readbuf
, sizeof(readbuf
))) != 0)
83 append_data(data
, readbuf
, nread
);
92 void crcvalidate_data(data_t
*data
, struct crc_context
*crcctx
)
96 unsigned char *getpos
= data
->buf
;
97 ssize_t remaining
= data
->datasize
;
99 while (remaining
!= 0)
101 size_t ndigested
= crc_read_block(crcctx
, &rd_block_rslt
, getpos
, remaining
);
102 // printf("%ld ", rd_block_rslt);
104 remaining
-= ndigested
;
106 rd_block_rslt
= crc_read_flush(crcctx
);
107 // printf("%ld ", rd_block_rslt);
109 crc_reset_running_crcs(crcctx
);
112 void sha1_data(data_t
*data
)
114 /* output SHA1 hash - this will be binary data */
115 unsigned char hash
[ APR_SHA1_DIGESTSIZE
];
116 apr_sha1_ctx_t sha1_ctx
;
118 apr_sha1_init(&sha1_ctx
);
119 apr_sha1_update_binary(&sha1_ctx
, data
->buf
, data
->datasize
);
120 apr_sha1_final(hash
, &sha1_ctx
);
123 ssize_t
compress_tst(unsigned char *org_data_buf
, size_t orglen
, unsigned char *compressed_data_buf
, size_t compressed_size
)
125 z_stream compression_stream
;
126 compression_stream
.zalloc
= Z_NULL
;
127 compression_stream
.zfree
= Z_NULL
;
128 compression_stream
.opaque
= Z_NULL
;
129 int zRC
= deflateInit(&compression_stream
, Z_DEFAULT_COMPRESSION
);
132 error("deflateInit returned an error code");
134 compression_stream
.avail_in
= orglen
;
135 compression_stream
.next_in
= org_data_buf
;
136 compression_stream
.avail_out
= compressed_size
;
137 compression_stream
.next_out
= compressed_data_buf
;
138 zRC
= deflate(&compression_stream
, Z_FINISH
);
139 if (zRC
== Z_STREAM_ERROR
)
141 error("deflate returned Z_ERROR");
143 if (compression_stream
.avail_in
!= 0)
145 error("decompression buffer was too small");
147 return compressed_size
- compression_stream
.avail_out
;
150 ssize_t
decompress_tst(unsigned char *org_data_buf
, size_t org_size
, unsigned char *compressed_data_buf
, size_t compressed_len
)
152 z_stream decompression_stream
;
153 decompression_stream
.zalloc
= Z_NULL
;
154 decompression_stream
.zfree
= Z_NULL
;
155 decompression_stream
.opaque
= Z_NULL
;
156 decompression_stream
.avail_in
= 0;
157 decompression_stream
.next_in
= Z_NULL
;
158 int zRC
= inflateInit(&decompression_stream
);
161 error("inflateInit returned an error code");
163 decompression_stream
.avail_in
= compressed_len
;
164 decompression_stream
.next_in
= compressed_data_buf
;
165 decompression_stream
.avail_out
= org_size
;
166 decompression_stream
.next_out
= org_data_buf
;
167 zRC
= inflate(&decompression_stream
, Z_NO_FLUSH
);
168 if (zRC
== Z_NEED_DICT
|| zRC
== Z_DATA_ERROR
|| zRC
== Z_MEM_ERROR
)
170 error("inflate returned Z_NEED_DIC, Z_DATA_ERROR or Z_MEM_ERROR");
172 if (decompression_stream
.avail_in
!= 0)
174 error("org data buffer was too small");
176 if (zRC
!= Z_STREAM_END
)
178 error("inflate did not return Z_STREAM_END");
180 return org_size
- decompression_stream
.avail_out
;
184 int contains(uint64_t *hashes
, uint64_t value
, int cnt
)
188 if (hashes
[cnt
] == value
)
202 double duration_ms(benchmark_t
*bm
)
204 return 1000 * (bm
->end
- bm
->start
+ 0.0)/CLOCKS_PER_SEC
;
207 int main(int argc
, char *argv
[])
211 int merge_trailing_blocks_in_last_block
;
212 for (merge_trailing_blocks_in_last_block
= 0; merge_trailing_blocks_in_last_block
!= 2; merge_trailing_blocks_in_last_block
++)
215 data_t
*original_data
= read_file_to_data(argv
[1]);
216 printf("Original data size: %zu\n", original_data
->datasize
);
218 //Set-up buffer for compressed data. Make it twice as long as the original_data
219 // so that even in a worst-case scenario of totally non-compressable data, it will still
220 // fit, withouth causing an buffer overflow
221 data_t
*compressed_data
= init_data();
222 append_data(compressed_data
, original_data
->buf
, original_data
->bufsize
);
223 append_data(compressed_data
, original_data
->buf
, original_data
->bufsize
);
224 // Benchmark the compression
225 benchmark_t bm_compress
;
226 bm_compress
.start
= clock();
227 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
229 compressed_data
->datasize
= compress_tst(original_data
->buf
, original_data
->datasize
, compressed_data
->buf
, compressed_data
->bufsize
);
231 bm_compress
.end
= clock();
232 printf("Compressed data size: %zu\n", compressed_data
->datasize
);
235 // Parameters for the hashes
236 size_t block_size
= original_data
->datasize
/FULL_BLOCK_COUNT
;
237 size_t tail_block_size
= original_data
->datasize
%FULL_BLOCK_COUNT
;
238 if (merge_trailing_blocks_in_last_block
)
240 tail_block_size
+= block_size
;
242 size_t block_count_including_final_block
= FULL_BLOCK_COUNT
+ (tail_block_size
!= 0 && !merge_trailing_blocks_in_last_block
);
244 // Set-up hashes for a perfect match and benchmark how long it takes
245 uint64_t match_hashes
[block_count_including_final_block
];
246 benchmark_t bm_crccalculate
;
247 bm_crccalculate
.start
= clock();
248 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
250 crc_of_blocks(original_data
->buf
, original_data
->datasize
, block_size
, tail_block_size
, HASH_SIZE
, match_hashes
);
252 bm_crccalculate
.end
= clock();
254 // Benchmark reconstructing a page from literal blocks
255 unsigned char *reconstructed_buf
= malloc(original_data
->datasize
);
256 benchmark_t bm_reconstruct
;
257 bm_reconstruct
.start
= clock();
258 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
261 for (blocks_cnt
=0; blocks_cnt
!= FULL_BLOCK_COUNT
; blocks_cnt
++)
263 memcpy(reconstructed_buf
+blocks_cnt
*block_size
, (original_data
->buf
)+blocks_cnt
*block_size
, block_size
);
265 if (tail_block_size
!= 0 && !merge_trailing_blocks_in_last_block
)
267 memcpy(reconstructed_buf
+blocks_cnt
*block_size
, (original_data
->buf
)+blocks_cnt
*block_size
, tail_block_size
);
270 bm_reconstruct
.end
= clock();
272 // Set-up hashes for a perfect mismatch
273 uint64_t nomatch_hashes
[block_count_including_final_block
];
275 for (cnt
=0; cnt
!= block_count_including_final_block
; cnt
++)
277 while (contains(match_hashes
, value
, block_count_including_final_block
))
281 nomatch_hashes
[cnt
] = value
;
284 struct crc_context
*crcctx
;
285 benchmark_t bm_crc_context_new
;
286 bm_crc_context_new
.start
= clock();
287 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
289 crcctx
= crc_context_new(block_size
, HASH_SIZE
, match_hashes
, block_count_including_final_block
, tail_block_size
);
291 bm_crc_context_new
.end
= clock();
293 benchmark_t bm_crcvalidate_match
;
294 bm_crcvalidate_match
.start
= clock();
295 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
297 crcvalidate_data(original_data
, crcctx
);
299 bm_crcvalidate_match
.end
= clock();
301 crcctx
= crc_context_new(block_size
, HASH_SIZE
, nomatch_hashes
, block_count_including_final_block
, tail_block_size
);
302 benchmark_t bm_crcvalidate_nomatch
;
303 bm_crcvalidate_nomatch
.start
= clock();
304 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
306 crcvalidate_data(original_data
, crcctx
);
308 bm_crcvalidate_nomatch
.end
= clock();
310 crc_context_free(crcctx
);
313 bm_sha1
.start
= clock();
314 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
316 sha1_data(original_data
);
318 bm_sha1
.end
= clock();
320 benchmark_t bm_decompress
;
321 bm_decompress
.start
= clock();
322 for (cnt
=0; cnt
!= TEST_ITERATIONS_COUNT
; cnt
++)
324 original_data
->datasize
= decompress_tst(original_data
->buf
, original_data
->bufsize
, compressed_data
->buf
, compressed_data
->datasize
);
326 bm_decompress
.end
= clock();
327 printf("Original data size after decompression: %zd\n", original_data
->datasize
);
330 "Nblocks: %zd, Block size: %zd, Tail block size: %zd, Compress: %.4f ms, Decompress: %.4f ms, Copy blocks: %.4f ms, New CRCCTX: %.4f ms, Calculate CRCs: %.4f ms, Validate match: %.4f ms, Validate nomatch: %.4f ms, SHA1: %.4f ms\n",
331 block_count_including_final_block
, block_size
, tail_block_size
,
332 duration_ms(&bm_compress
)/TEST_ITERATIONS_COUNT
,
333 duration_ms(&bm_decompress
)/TEST_ITERATIONS_COUNT
,
334 duration_ms(&bm_reconstruct
)/TEST_ITERATIONS_COUNT
,
335 duration_ms(&bm_crc_context_new
)/TEST_ITERATIONS_COUNT
,
336 duration_ms(&bm_crccalculate
)/TEST_ITERATIONS_COUNT
,
337 duration_ms(&bm_crcvalidate_match
)/TEST_ITERATIONS_COUNT
,
338 duration_ms(&bm_crcvalidate_nomatch
)/TEST_ITERATIONS_COUNT
,
339 duration_ms(&bm_sha1
)/TEST_ITERATIONS_COUNT
342 // "Nblocks: %zd, Block size: %zd, Tail block size: %zd, New CRCCTX: %.4f ms, Calculate CRCs: %.4f ms, Validate match: %.4f ms, Validate nomatch: %.4f ms\n",
343 // block_count_including_final_block, block_size, tail_block_size,
344 // duration_ms(&bm_crc_context_new)/TEST_ITERATIONS_COUNT,
345 // duration_ms(&bm_crccalculate)/TEST_ITERATIONS_COUNT,
346 // duration_ms(&bm_crcvalidate_match)/TEST_ITERATIONS_COUNT,
347 // duration_ms(&bm_crcvalidate_nomatch)/TEST_ITERATIONS_COUNT
350 free_data(original_data
);