VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/tstCompressionBenchmark.cpp@ 96860

Last change on this file since 96860 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 KB
Line 
1/* $Id: tstCompressionBenchmark.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * Compression Benchmark for SSM and PGM.
4 */
5
6/*
7 * Copyright (C) 2009-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/buildconfig.h>
35#include <iprt/crc.h>
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/getopt.h>
40#include <iprt/initterm.h>
41#include <iprt/md5.h>
42#include <iprt/sha.h>
43#include <iprt/mem.h>
44#include <iprt/param.h>
45#include <iprt/stream.h>
46#include <iprt/string.h>
47#include <iprt/time.h>
48#include <iprt/zip.h>
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54#define MY_BLOCK_SIZE _4K /**< Same as SSM uses. */
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60static size_t g_cBlocks = 20*_1M / MY_BLOCK_SIZE;
61static size_t g_cbBlocks;
62static uint8_t *g_pabSrc;
63
64/** Buffer for the decompressed data (g_cbBlocks). */
65static uint8_t *g_pabDecompr;
66
67/** Buffer for the compressed data (g_cbComprAlloc). */
68static uint8_t *g_pabCompr;
69/** The current size of the compressed data, ComprOutCallback */
70static size_t g_cbCompr;
71/** The current offset into the compressed data, DecomprInCallback. */
72static size_t g_offComprIn;
73/** The amount of space allocated for compressed data. */
74static size_t g_cbComprAlloc;
75
76
77/**
78 * Store compressed data in the g_pabCompr buffer.
79 */
80static DECLCALLBACK(int) ComprOutCallback(void *pvUser, const void *pvBuf, size_t cbBuf)
81{
82 NOREF(pvUser);
83 AssertReturn(g_cbCompr + cbBuf <= g_cbComprAlloc, VERR_BUFFER_OVERFLOW);
84 memcpy(&g_pabCompr[g_cbCompr], pvBuf, cbBuf);
85 g_cbCompr += cbBuf;
86 return VINF_SUCCESS;
87}
88
89/**
90 * Read compressed data from g_pabComrp.
91 */
92static DECLCALLBACK(int) DecomprInCallback(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
93{
94 NOREF(pvUser);
95 size_t cb = RT_MIN(cbBuf, g_cbCompr - g_offComprIn);
96 if (pcbBuf)
97 *pcbBuf = cb;
98// AssertReturn(cb > 0, VERR_EOF);
99 memcpy(pvBuf, &g_pabCompr[g_offComprIn], cb);
100 g_offComprIn += cb;
101 return VINF_SUCCESS;
102}
103
104
105/**
106 * Benchmark RTCrc routines potentially relevant for SSM or PGM - All in one go.
107 *
108 * @param pabSrc Pointer to the test data.
109 * @param cbSrc The size of the test data.
110 */
111static void tstBenchmarkCRCsAllInOne(uint8_t const *pabSrc, size_t cbSrc)
112{
113 RTPrintf("Algorithm Speed Time Digest\n"
114 "------------------------------------------------------------------------------\n");
115
116 uint64_t NanoTS = RTTimeNanoTS();
117 uint32_t u32Crc = RTCrc32(pabSrc, cbSrc);
118 NanoTS = RTTimeNanoTS() - NanoTS;
119 unsigned uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
120 RTPrintf("CRC-32 %'9u KB/s %'15llu ns - %08x\n", uSpeed, NanoTS, u32Crc);
121
122
123 NanoTS = RTTimeNanoTS();
124 uint64_t u64Crc = RTCrc64(pabSrc, cbSrc);
125 NanoTS = RTTimeNanoTS() - NanoTS;
126 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
127 RTPrintf("CRC-64 %'9u KB/s %'15llu ns - %016llx\n", uSpeed, NanoTS, u64Crc);
128
129 NanoTS = RTTimeNanoTS();
130 u32Crc = RTCrcAdler32(pabSrc, cbSrc);
131 NanoTS = RTTimeNanoTS() - NanoTS;
132 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
133 RTPrintf("Adler-32 %'9u KB/s %'15llu ns - %08x\n", uSpeed, NanoTS, u32Crc);
134
135 NanoTS = RTTimeNanoTS();
136 uint8_t abMd5Hash[RTMD5HASHSIZE];
137 RTMd5(pabSrc, cbSrc, abMd5Hash);
138 NanoTS = RTTimeNanoTS() - NanoTS;
139 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
140 char szDigest[257];
141 RTMd5ToString(abMd5Hash, szDigest, sizeof(szDigest));
142 RTPrintf("MD5 %'9u KB/s %'15llu ns - %s\n", uSpeed, NanoTS, szDigest);
143
144 NanoTS = RTTimeNanoTS();
145 uint8_t abSha1Hash[RTSHA1_HASH_SIZE];
146 RTSha1(pabSrc, cbSrc, abSha1Hash);
147 NanoTS = RTTimeNanoTS() - NanoTS;
148 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
149 RTSha1ToString(abSha1Hash, szDigest, sizeof(szDigest));
150 RTPrintf("SHA-1 %'9u KB/s %'15llu ns - %s\n", uSpeed, NanoTS, szDigest);
151
152 NanoTS = RTTimeNanoTS();
153 uint8_t abSha256Hash[RTSHA256_HASH_SIZE];
154 RTSha256(pabSrc, cbSrc, abSha256Hash);
155 NanoTS = RTTimeNanoTS() - NanoTS;
156 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
157 RTSha256ToString(abSha256Hash, szDigest, sizeof(szDigest));
158 RTPrintf("SHA-256 %'9u KB/s %'15llu ns - %s\n", uSpeed, NanoTS, szDigest);
159
160 NanoTS = RTTimeNanoTS();
161 uint8_t abSha512Hash[RTSHA512_HASH_SIZE];
162 RTSha512(pabSrc, cbSrc, abSha512Hash);
163 NanoTS = RTTimeNanoTS() - NanoTS;
164 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
165 RTSha512ToString(abSha512Hash, szDigest, sizeof(szDigest));
166 RTPrintf("SHA-512 %'9u KB/s %'15llu ns - %s\n", uSpeed, NanoTS, szDigest);
167}
168
169
170/**
171 * Benchmark RTCrc routines potentially relevant for SSM or PGM - Bage by block.
172 *
173 * @param pabSrc Pointer to the test data.
174 * @param cbSrc The size of the test data.
175 */
176static void tstBenchmarkCRCsBlockByBlock(uint8_t const *pabSrc, size_t cbSrc)
177{
178 RTPrintf("Algorithm Speed Time \n"
179 "----------------------------------------------\n");
180
181 size_t const cBlocks = cbSrc / MY_BLOCK_SIZE;
182
183 uint64_t NanoTS = RTTimeNanoTS();
184 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
185 RTCrc32(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE);
186 NanoTS = RTTimeNanoTS() - NanoTS;
187 unsigned uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
188 RTPrintf("CRC-32 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
189
190
191 NanoTS = RTTimeNanoTS();
192 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
193 RTCrc64(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE);
194 NanoTS = RTTimeNanoTS() - NanoTS;
195 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
196 RTPrintf("CRC-64 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
197
198 NanoTS = RTTimeNanoTS();
199 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
200 RTCrcAdler32(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE);
201 NanoTS = RTTimeNanoTS() - NanoTS;
202 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
203 RTPrintf("Adler-32 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
204
205 NanoTS = RTTimeNanoTS();
206 uint8_t abMd5Hash[RTMD5HASHSIZE];
207 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
208 RTMd5(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE, abMd5Hash);
209 NanoTS = RTTimeNanoTS() - NanoTS;
210 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
211 RTPrintf("MD5 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
212
213 NanoTS = RTTimeNanoTS();
214 uint8_t abSha1Hash[RTSHA1_HASH_SIZE];
215 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
216 RTSha1(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE, abSha1Hash);
217 NanoTS = RTTimeNanoTS() - NanoTS;
218 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
219 RTPrintf("SHA-1 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
220
221 NanoTS = RTTimeNanoTS();
222 uint8_t abSha256Hash[RTSHA256_HASH_SIZE];
223 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
224 RTSha256(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE, abSha256Hash);
225 NanoTS = RTTimeNanoTS() - NanoTS;
226 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
227 RTPrintf("SHA-256 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
228
229 NanoTS = RTTimeNanoTS();
230 uint8_t abSha512Hash[RTSHA512_HASH_SIZE];
231 for (uint32_t iBlock = 0; iBlock < cBlocks; iBlock++)
232 RTSha512(&pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE, abSha512Hash);
233 NanoTS = RTTimeNanoTS() - NanoTS;
234 uSpeed = (unsigned)((long double)cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
235 RTPrintf("SHA-512 %'9u KB/s %'15llu ns\n", uSpeed, NanoTS);
236}
237
238
239/** Prints an error message and returns 1 for quick return from main use. */
240static int Error(const char *pszMsgFmt, ...)
241{
242 RTStrmPrintf(g_pStdErr, "\nerror: ");
243 va_list va;
244 va_start(va, pszMsgFmt);
245 RTStrmPrintfV(g_pStdErr, pszMsgFmt, va);
246 va_end(va);
247 return 1;
248}
249
250
251int main(int argc, char **argv)
252{
253 RTR3InitExe(argc, &argv, 0);
254
255 /*
256 * Parse arguments.
257 */
258 static const RTGETOPTDEF s_aOptions[] =
259 {
260 { "--iterations", 'i', RTGETOPT_REQ_UINT32 },
261 { "--num-blocks", 'n', RTGETOPT_REQ_UINT32 },
262 { "--block-at-a-time", 'c', RTGETOPT_REQ_UINT32 },
263 { "--block-file", 'f', RTGETOPT_REQ_STRING },
264 { "--offset", 'o', RTGETOPT_REQ_UINT64 },
265 };
266
267 const char *pszBlockFile = NULL;
268 uint64_t offBlockFile = 0;
269 uint32_t cIterations = 1;
270 uint32_t cBlocksAtATime = 1;
271 RTGETOPTUNION Val;
272 RTGETOPTSTATE State;
273 int rc = RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0);
274 AssertRCReturn(rc, 1);
275
276 while ((rc = RTGetOpt(&State, &Val)))
277 {
278 switch (rc)
279 {
280 case 'n':
281 g_cBlocks = Val.u32;
282 if (g_cBlocks * MY_BLOCK_SIZE * 4 / (MY_BLOCK_SIZE * 4) != g_cBlocks)
283 return Error("The specified block count is too high: %#x (%#llx bytes)\n",
284 g_cBlocks, (uint64_t)g_cBlocks * MY_BLOCK_SIZE);
285 if (g_cBlocks < 1)
286 return Error("The specified block count is too low: %#x\n", g_cBlocks);
287 break;
288
289 case 'i':
290 cIterations = Val.u32;
291 if (cIterations < 1)
292 return Error("The number of iterations must be 1 or higher\n");
293 break;
294
295 case 'c':
296 cBlocksAtATime = Val.u32;
297 if (cBlocksAtATime < 1 || cBlocksAtATime > 10240)
298 return Error("The specified blocks-at-a-time count is out of range: %#x\n", cBlocksAtATime);
299 break;
300
301 case 'f':
302 pszBlockFile = Val.psz;
303 break;
304
305 case 'o':
306 offBlockFile = Val.u64;
307 break;
308
309 case 'O':
310 offBlockFile = Val.u64 * MY_BLOCK_SIZE;
311 break;
312
313 case 'h':
314 RTPrintf("syntax: tstCompressionBenchmark [options]\n"
315 "\n"
316 "Options:\n"
317 " -h, --help\n"
318 " Show this help page\n"
319 " -i, --iterations <num>\n"
320 " The number of iterations.\n"
321 " -n, --num-blocks <blocks>\n"
322 " The number of blocks.\n"
323 " -c, --blocks-at-a-time <blocks>\n"
324 " Number of blocks at a time.\n"
325 " -f, --block-file <filename>\n"
326 " File or device to read the block from. The default\n"
327 " is to generate some garbage.\n"
328 " -o, --offset <file-offset>\n"
329 " Offset into the block file to start reading at.\n");
330 return 0;
331
332 case 'V':
333 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
334 return 0;
335
336 default:
337 return RTGetOptPrintError(rc, &Val);
338 }
339 }
340
341 g_cbBlocks = g_cBlocks * MY_BLOCK_SIZE;
342 uint64_t cbTotal = (uint64_t)g_cBlocks * MY_BLOCK_SIZE * cIterations;
343 uint64_t cbTotalKB = cbTotal / _1K;
344 if (cbTotal / cIterations != g_cbBlocks)
345 return Error("cBlocks * cIterations -> overflow\n");
346
347 /*
348 * Gather the test memory.
349 */
350 if (pszBlockFile)
351 {
352 size_t cbFile;
353 rc = RTFileReadAllEx(pszBlockFile, offBlockFile, g_cbBlocks, RTFILE_RDALL_O_DENY_NONE, (void **)&g_pabSrc, &cbFile);
354 if (RT_FAILURE(rc))
355 return Error("Error reading %zu bytes from %s at %llu: %Rrc\n", g_cbBlocks, pszBlockFile, offBlockFile, rc);
356 if (cbFile != g_cbBlocks)
357 return Error("Error reading %zu bytes from %s at %llu: got %zu bytes\n", g_cbBlocks, pszBlockFile, offBlockFile, cbFile);
358 }
359 else
360 {
361 g_pabSrc = (uint8_t *)RTMemAlloc(g_cbBlocks);
362 if (g_pabSrc)
363 {
364 /* Just fill it with something - warn about the low quality of the something. */
365 RTPrintf("tstCompressionBenchmark: WARNING! No input file was specified so the source\n"
366 "buffer will be filled with generated data of questionable quality.\n");
367#ifdef RT_OS_LINUX
368 RTPrintf("To get real RAM on linux: sudo dd if=/dev/mem ... \n");
369#endif
370 uint8_t *pb = g_pabSrc;
371 uint8_t *pbEnd = &g_pabSrc[g_cbBlocks];
372 for (; pb != pbEnd; pb += 16)
373 {
374 char szTmp[17];
375 RTStrPrintf(szTmp, sizeof(szTmp), "aaaa%08Xzzzz", (uint32_t)(uintptr_t)pb);
376 memcpy(pb, szTmp, 16);
377 }
378 }
379 }
380
381 g_pabDecompr = (uint8_t *)RTMemAlloc(g_cbBlocks);
382 g_cbComprAlloc = RT_MAX(g_cbBlocks * 2, 256 * MY_BLOCK_SIZE);
383 g_pabCompr = (uint8_t *)RTMemAlloc(g_cbComprAlloc);
384 if (!g_pabSrc || !g_pabDecompr || !g_pabCompr)
385 return Error("failed to allocate memory buffers (g_cBlocks=%#x)\n", g_cBlocks);
386
387 /*
388 * Double loop compressing and uncompressing the data, where the outer does
389 * the specified number of iterations while the inner applies the different
390 * compression algorithms.
391 */
392 struct
393 {
394 /** The time spent decompressing. */
395 uint64_t cNanoDecompr;
396 /** The time spent compressing. */
397 uint64_t cNanoCompr;
398 /** The size of the compressed data. */
399 uint64_t cbCompr;
400 /** First error. */
401 int rc;
402 /** The compression style: block or stream. */
403 bool fBlock;
404 /** Compression type. */
405 RTZIPTYPE enmType;
406 /** Compression level. */
407 RTZIPLEVEL enmLevel;
408 /** Method name. */
409 const char *pszName;
410 } aTests[] =
411 {
412 { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZip/Store" },
413 { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZip/LZF" },
414/* { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT, "RTZip/zlib" }, - slow plus it randomly hits VERR_GENERAL_FAILURE atm. */
415 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZipBlock/Store" },
416 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZF" },
417 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZJB, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZJB" },
418 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZO, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZO" },
419 };
420 RTPrintf("tstCompressionBenchmark: TESTING..");
421 for (uint32_t i = 0; i < cIterations; i++)
422 {
423 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
424 {
425 if (RT_FAILURE(aTests[j].rc))
426 continue;
427 memset(g_pabCompr, 0xaa, g_cbComprAlloc);
428 memset(g_pabDecompr, 0xcc, g_cbBlocks);
429 g_cbCompr = 0;
430 g_offComprIn = 0;
431 RTPrintf("."); RTStrmFlush(g_pStdOut);
432
433 /*
434 * Compress it.
435 */
436 uint64_t NanoTS = RTTimeNanoTS();
437 if (aTests[j].fBlock)
438 {
439 size_t cbLeft = g_cbComprAlloc;
440 uint8_t const *pbSrcBlock = g_pabSrc;
441 uint8_t *pbDstBlock = g_pabCompr;
442 for (size_t iBlock = 0; iBlock < g_cBlocks; iBlock += cBlocksAtATime)
443 {
444 AssertBreakStmt(cbLeft > MY_BLOCK_SIZE * 4, aTests[j].rc = rc = VERR_BUFFER_OVERFLOW);
445 uint32_t *pcb = (uint32_t *)pbDstBlock;
446 pbDstBlock += sizeof(uint32_t);
447 cbLeft -= sizeof(uint32_t);
448 size_t cbSrc = RT_MIN(g_cBlocks - iBlock, cBlocksAtATime) * MY_BLOCK_SIZE;
449 size_t cbDst;
450 rc = RTZipBlockCompress(aTests[j].enmType, aTests[j].enmLevel, 0 /*fFlags*/,
451 pbSrcBlock, cbSrc,
452 pbDstBlock, cbLeft, &cbDst);
453 if (RT_FAILURE(rc))
454 {
455 Error("RTZipBlockCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
456 aTests[j].rc = rc;
457 break;
458 }
459 *pcb = (uint32_t)cbDst;
460 cbLeft -= cbDst;
461 pbDstBlock += cbDst;
462 pbSrcBlock += cbSrc;
463 }
464 if (RT_FAILURE(rc))
465 continue;
466 g_cbCompr = pbDstBlock - g_pabCompr;
467 }
468 else
469 {
470 PRTZIPCOMP pZipComp;
471 rc = RTZipCompCreate(&pZipComp, NULL, ComprOutCallback, aTests[j].enmType, aTests[j].enmLevel);
472 if (RT_FAILURE(rc))
473 {
474 Error("Failed to create the compressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
475 aTests[j].rc = rc;
476 continue;
477 }
478
479 uint8_t const *pbSrcBlock = g_pabSrc;
480 for (size_t iBlock = 0; iBlock < g_cBlocks; iBlock += cBlocksAtATime)
481 {
482 size_t cb = RT_MIN(g_cBlocks - iBlock, cBlocksAtATime) * MY_BLOCK_SIZE;
483 rc = RTZipCompress(pZipComp, pbSrcBlock, cb);
484 if (RT_FAILURE(rc))
485 {
486 Error("RTZipCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
487 aTests[j].rc = rc;
488 break;
489 }
490 pbSrcBlock += cb;
491 }
492 if (RT_FAILURE(rc))
493 continue;
494 rc = RTZipCompFinish(pZipComp);
495 if (RT_FAILURE(rc))
496 {
497 Error("RTZipCompFinish failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
498 aTests[j].rc = rc;
499 break;
500 }
501 RTZipCompDestroy(pZipComp);
502 }
503 NanoTS = RTTimeNanoTS() - NanoTS;
504 aTests[j].cbCompr += g_cbCompr;
505 aTests[j].cNanoCompr += NanoTS;
506
507 /*
508 * Decompress it.
509 */
510 NanoTS = RTTimeNanoTS();
511 if (aTests[j].fBlock)
512 {
513 uint8_t const *pbSrcBlock = g_pabCompr;
514 size_t cbLeft = g_cbCompr;
515 uint8_t *pbDstBlock = g_pabDecompr;
516 for (size_t iBlock = 0; iBlock < g_cBlocks; iBlock += cBlocksAtATime)
517 {
518 size_t cbDst = RT_MIN(g_cBlocks - iBlock, cBlocksAtATime) * MY_BLOCK_SIZE;
519 size_t cbSrc = *(uint32_t *)pbSrcBlock;
520 pbSrcBlock += sizeof(uint32_t);
521 cbLeft -= sizeof(uint32_t);
522 rc = RTZipBlockDecompress(aTests[j].enmType, 0 /*fFlags*/,
523 pbSrcBlock, cbSrc, &cbSrc,
524 pbDstBlock, cbDst, &cbDst);
525 if (RT_FAILURE(rc))
526 {
527 Error("RTZipBlockDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
528 aTests[j].rc = rc;
529 break;
530 }
531 pbDstBlock += cbDst;
532 cbLeft -= cbSrc;
533 pbSrcBlock += cbSrc;
534 }
535 if (RT_FAILURE(rc))
536 continue;
537 }
538 else
539 {
540 PRTZIPDECOMP pZipDecomp;
541 rc = RTZipDecompCreate(&pZipDecomp, NULL, DecomprInCallback);
542 if (RT_FAILURE(rc))
543 {
544 Error("Failed to create the decompressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
545 aTests[j].rc = rc;
546 continue;
547 }
548
549 uint8_t *pbDstBlock = g_pabDecompr;
550 for (size_t iBlock = 0; iBlock < g_cBlocks; iBlock += cBlocksAtATime)
551 {
552 size_t cb = RT_MIN(g_cBlocks - iBlock, cBlocksAtATime) * MY_BLOCK_SIZE;
553 rc = RTZipDecompress(pZipDecomp, pbDstBlock, cb, NULL);
554 if (RT_FAILURE(rc))
555 {
556 Error("RTZipDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
557 aTests[j].rc = rc;
558 break;
559 }
560 pbDstBlock += cb;
561 }
562 RTZipDecompDestroy(pZipDecomp);
563 if (RT_FAILURE(rc))
564 continue;
565 }
566 NanoTS = RTTimeNanoTS() - NanoTS;
567 aTests[j].cNanoDecompr += NanoTS;
568
569 if (memcmp(g_pabDecompr, g_pabSrc, g_cbBlocks))
570 {
571 Error("The compressed data doesn't match the source for '%s' (%#u)\n", aTests[j].pszName, j);
572 aTests[j].rc = VERR_BAD_EXE_FORMAT;
573 continue;
574 }
575 }
576 }
577 if (RT_SUCCESS(rc))
578 RTPrintf("\n");
579
580 /*
581 * Report the results.
582 */
583 rc = 0;
584 RTPrintf("tstCompressionBenchmark: BEGIN RESULTS\n");
585 RTPrintf("%-20s Compression Decompression\n", "");
586 RTPrintf("%-20s In Out Ratio Size In Out\n", "Method");
587 RTPrintf("%.20s-----------------------------------------------------------------------------------------\n", "---------------------------------------------");
588 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
589 {
590 if (RT_SUCCESS(aTests[j].rc))
591 {
592 unsigned uComprSpeedIn = (unsigned)((long double)cbTotalKB / (long double)aTests[j].cNanoCompr * 1000000000.0);
593 unsigned uComprSpeedOut = (unsigned)((long double)aTests[j].cbCompr / (long double)aTests[j].cNanoCompr * 1000000000.0 / 1024);
594 unsigned uDecomprSpeedIn = (unsigned)((long double)aTests[j].cbCompr / (long double)aTests[j].cNanoDecompr * 1000000000.0 / 1024);
595 unsigned uDecomprSpeedOut = (unsigned)((long double)cbTotalKB / (long double)aTests[j].cNanoDecompr * 1000000000.0);
596 unsigned uRatio = (unsigned)(aTests[j].cbCompr / cIterations * 100 / g_cbBlocks);
597 RTPrintf("%-20s %'9u KB/s %'9u KB/s %3u%% %'11llu bytes %'9u KB/s %'9u KB/s",
598 aTests[j].pszName,
599 uComprSpeedIn, uComprSpeedOut, uRatio, aTests[j].cbCompr / cIterations,
600 uDecomprSpeedIn, uDecomprSpeedOut);
601#if 0
602 RTPrintf(" [%'14llu / %'14llu ns]\n",
603 aTests[j].cNanoCompr / cIterations,
604 aTests[j].cNanoDecompr / cIterations);
605#else
606 RTPrintf("\n");
607#endif
608 }
609 else
610 {
611 RTPrintf("%-20s: %Rrc\n", aTests[j].pszName, aTests[j].rc);
612 rc = 1;
613 }
614 }
615 if (pszBlockFile)
616 RTPrintf("Input: %'10zu Blocks from '%s' starting at offset %'lld (%#llx)\n"
617 " %'11zu bytes\n",
618 g_cBlocks, pszBlockFile, offBlockFile, offBlockFile, g_cbBlocks);
619 else
620 RTPrintf("Input: %'10zu Blocks of generated rubbish %'11zu bytes\n",
621 g_cBlocks, g_cbBlocks);
622
623 /*
624 * Count zero blocks in the data set.
625 */
626 size_t cZeroBlocks = 0;
627 for (size_t iBlock = 0; iBlock < g_cBlocks; iBlock++)
628 {
629 if (ASMMemIsZero(&g_pabSrc[iBlock * MY_BLOCK_SIZE], MY_BLOCK_SIZE))
630 cZeroBlocks++;
631 }
632 RTPrintf(" %'10zu zero Blocks (%u %%)\n", cZeroBlocks, cZeroBlocks * 100 / g_cBlocks);
633
634 /*
635 * A little extension to the test, benchmark relevant CRCs.
636 */
637 RTPrintf("\n"
638 "tstCompressionBenchmark: Hash/CRC - All In One\n");
639 tstBenchmarkCRCsAllInOne(g_pabSrc, g_cbBlocks);
640
641 RTPrintf("\n"
642 "tstCompressionBenchmark: Hash/CRC - Block by Block\n");
643 tstBenchmarkCRCsBlockByBlock(g_pabSrc, g_cbBlocks);
644
645 RTPrintf("\n"
646 "tstCompressionBenchmark: Hash/CRC - Zero Block Digest\n");
647 static uint8_t s_abZeroPg[MY_BLOCK_SIZE];
648 RT_ZERO(s_abZeroPg);
649 tstBenchmarkCRCsAllInOne(s_abZeroPg, MY_BLOCK_SIZE);
650
651 RTPrintf("\n"
652 "tstCompressionBenchmark: Hash/CRC - Zero Half Block Digest\n");
653 tstBenchmarkCRCsAllInOne(s_abZeroPg, MY_BLOCK_SIZE / 2);
654
655 RTPrintf("tstCompressionBenchmark: END RESULTS\n");
656
657 return rc;
658}
659
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use