VirtualBox

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

Last change on this file since 23194 was 22006, checked in by vboxsync, 15 years ago

tstCompressionBenchmark: More tests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1/* $Id: tstCompressionBenchmark.cpp 22006 2009-08-05 18:41:29Z vboxsync $ */
2/** @file
3 * Compression Benchmark for SSM.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <iprt/asm.h>
27#include <iprt/assert.h>
28#include <iprt/crc.h>
29#include <iprt/ctype.h>
30#include <iprt/err.h>
31#include <iprt/file.h>
32#include <iprt/getopt.h>
33#include <iprt/initterm.h>
34#include <iprt/md5.h>
35#include <iprt/mem.h>
36#include <iprt/param.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/time.h>
40#include <iprt/zip.h>
41
42
43/*******************************************************************************
44* Global Variables *
45*******************************************************************************/
46static size_t g_cPages = 20*_1M / PAGE_SIZE;
47static size_t g_cbPages;
48static uint8_t *g_pabSrc;
49
50/** Buffer for the decompressed data (g_cbPages). */
51static uint8_t *g_pabDecompr;
52
53/** Buffer for the compressed data (g_cbComprAlloc). */
54static uint8_t *g_pabCompr;
55/** The current size of the compressed data, ComprOutCallback */
56static size_t g_cbCompr;
57/** The current offset into the compressed data, DecomprInCallback. */
58static size_t g_offComprIn;
59/** The amount of space allocated for compressed data. */
60static size_t g_cbComprAlloc;
61
62
63/**
64 * Store compressed data in the g_pabCompr buffer.
65 */
66static DECLCALLBACK(int) ComprOutCallback(void *pvUser, const void *pvBuf, size_t cbBuf)
67{
68 AssertReturn(g_cbCompr + cbBuf <= g_cbComprAlloc, VERR_BUFFER_OVERFLOW);
69 memcpy(&g_pabCompr[g_cbCompr], pvBuf, cbBuf);
70 g_cbCompr += cbBuf;
71 return VINF_SUCCESS;
72}
73
74/**
75 * Read compressed data from g_pabComrp.
76 */
77static DECLCALLBACK(int) DecomprInCallback(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
78{
79 size_t cb = RT_MIN(cbBuf, g_cbCompr - g_offComprIn);
80 if (pcbBuf)
81 *pcbBuf = cb;
82// AssertReturn(cb > 0, VERR_EOF);
83 memcpy(pvBuf, &g_pabCompr[g_offComprIn], cb);
84 g_offComprIn += cb;
85 return VINF_SUCCESS;
86}
87
88/**
89 * Benchmark RTCrc routines potentially relevant for SSM.
90 *
91 * @param pabSrc Pointer to the test data.
92 * @param cbSrc The size of the test data.
93 */
94static void tstBenchmarkCRCs(uint8_t const *pabSrc, size_t cbSrc)
95{
96 RTPrintf("Algorithm Speed Time Digest\n"
97 "------------------------------------------------------------------------------\n");
98
99 uint64_t NanoTS = RTTimeNanoTS();
100 uint32_t u32Crc = RTCrc32(pabSrc, cbSrc);
101 NanoTS = RTTimeNanoTS() - NanoTS;
102 unsigned uSpeed = (unsigned)(cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
103 RTPrintf("CRC-32 %'9u KB/s %'14llu ns - %08x\n", uSpeed, NanoTS, u32Crc);
104
105
106 NanoTS = RTTimeNanoTS();
107 uint64_t u64Crc = RTCrc64(pabSrc, cbSrc);
108 NanoTS = RTTimeNanoTS() - NanoTS;
109 uSpeed = (unsigned)(cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
110 RTPrintf("CRC-64 %'9u KB/s %'14llu ns - %016llx\n", uSpeed, NanoTS, u64Crc);
111
112 NanoTS = RTTimeNanoTS();
113 u32Crc = RTCrcAdler32(pabSrc, cbSrc);
114 NanoTS = RTTimeNanoTS() - NanoTS;
115 uSpeed = (unsigned)(cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
116 RTPrintf("Adler-32 %'9u KB/s %'14llu ns - %08x\n", uSpeed, NanoTS, u32Crc);
117
118 NanoTS = RTTimeNanoTS();
119 uint8_t abMd5Hash[RTMD5HASHSIZE];
120 RTMd5(pabSrc, cbSrc, abMd5Hash);
121 NanoTS = RTTimeNanoTS() - NanoTS;
122 uSpeed = (unsigned)(cbSrc / (long double)NanoTS * 1000000000.0 / 1024);
123 RTPrintf("MD5 %'9u KB/s %'14llu ns - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
124 uSpeed, NanoTS,
125 abMd5Hash[0], abMd5Hash[1], abMd5Hash[2], abMd5Hash[3],
126 abMd5Hash[4], abMd5Hash[5], abMd5Hash[6], abMd5Hash[7],
127 abMd5Hash[8], abMd5Hash[9], abMd5Hash[10], abMd5Hash[11],
128 abMd5Hash[12], abMd5Hash[13], abMd5Hash[14], abMd5Hash[15]);
129}
130
131
132/** Prints an error message and returns 1 for quick return from main use. */
133static int Error(const char *pszMsgFmt, ...)
134{
135 RTStrmPrintf(g_pStdErr, "\nerror: ");
136 va_list va;
137 va_start(va, pszMsgFmt);
138 RTStrmPrintfV(g_pStdErr, pszMsgFmt, va);
139 va_end(va);
140 return 1;
141}
142
143
144int main(int argc, char **argv)
145{
146 RTR3Init();
147
148 /*
149 * Parse arguments.
150 */
151 static const RTGETOPTDEF s_aOptions[] =
152 {
153 { "--interations", 'i', RTGETOPT_REQ_UINT32 },
154 { "--num-pages", 'n', RTGETOPT_REQ_UINT32 },
155 { "--page-at-a-time", 'c', RTGETOPT_REQ_UINT32 },
156 { "--page-file", 'f', RTGETOPT_REQ_STRING },
157 { "--offset", 'o', RTGETOPT_REQ_UINT64 },
158 { "--page-offset", 'O', RTGETOPT_REQ_UINT64 },
159 };
160
161 const char *pszPageFile = NULL;
162 uint64_t offPageFile = 0;
163 uint32_t cIterations = 1;
164 uint32_t cPagesAtATime = 1;
165 RTGETOPTUNION Val;
166 RTGETOPTSTATE State;
167 int rc = RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0);
168 AssertRCReturn(rc, 1);
169
170 while ((rc = RTGetOpt(&State, &Val)))
171 {
172 switch (rc)
173 {
174 case 'n':
175 g_cPages = Val.u32;
176 if (g_cPages * PAGE_SIZE * 4 / (PAGE_SIZE * 4) != g_cPages)
177 return Error("The specified page count is too high: %#x (%#llx bytes)\n", g_cPages, (uint64_t)g_cPages * PAGE_SHIFT);
178 if (g_cPages < 1)
179 return Error("The specified page count is too low: %#x\n", g_cPages);
180 break;
181
182 case 'i':
183 cIterations = Val.u32;
184 if (cIterations < 1)
185 return Error("The number of iterations must be 1 or higher\n");
186 break;
187
188 case 'c':
189 cPagesAtATime = Val.u32;
190 if (cPagesAtATime < 1 || cPagesAtATime > 10240)
191 return Error("The specified pages-at-a-time count is out of range: %#x\n", cPagesAtATime);
192 break;
193
194 case 'f':
195 pszPageFile = Val.psz;
196 break;
197
198 case 'o':
199 offPageFile = Val.u64;
200 break;
201
202 case 'O':
203 offPageFile = Val.u64 * PAGE_SIZE;
204 break;
205
206 default:
207 if (rc == VINF_GETOPT_NOT_OPTION)
208 Error("unknown argument: %s\n", Val.psz);
209 else if (rc > 0)
210 {
211 if (RT_C_IS_GRAPH(rc))
212 Error("unhandled option: -%c\n", rc);
213 else
214 Error("unhandled option: %d\n", rc);
215 }
216 else if (rc == VERR_GETOPT_UNKNOWN_OPTION)
217 Error("unknown option: %s\n", Val.psz);
218 else if (Val.pDef)
219 Error("%s: %Rrs\n", Val.pDef->pszLong, rc);
220 else
221 Error("%Rrs\n", rc);
222 return 1;
223 }
224 }
225
226 g_cbPages = g_cPages * PAGE_SIZE;
227 uint64_t cbTotal = (uint64_t)g_cPages * PAGE_SIZE * cIterations;
228 uint64_t cbTotalKB = cbTotal / _1K;
229 if (cbTotal / cIterations != g_cbPages)
230 return Error("cPages * cIterations -> overflow\n");
231
232 /*
233 * Gather the test memory.
234 */
235 if (pszPageFile)
236 {
237 size_t cbFile;
238 rc = RTFileReadAllEx(pszPageFile, offPageFile, g_cbPages, RTFILE_RDALL_O_DENY_NONE, (void **)&g_pabSrc, &cbFile);
239 if (RT_FAILURE(rc))
240 return Error("Error reading %zu bytes from %s at %llu: %Rrc\n", g_cbPages, pszPageFile, offPageFile, rc);
241 if (cbFile != g_cbPages)
242 return Error("Error reading %zu bytes from %s at %llu: got %zu bytes\n", g_cbPages, pszPageFile, offPageFile, cbFile);
243 }
244 else
245 {
246 g_pabSrc = (uint8_t *)RTMemAlloc(g_cbPages);
247 if (g_pabSrc)
248 {
249 /* Just fill it with something - warn about the low quality of the something. */
250 RTPrintf("tstCompressionBenchmark: WARNING! No input file was specified so the source\n"
251 "buffer will be filled with generated data of questionable quality.\n");
252#ifdef RT_OS_LINUX
253 RTPrintf("To get real RAM on linux: sudo dd if=/dev/mem ... \n");
254#endif
255 uint8_t *pb = g_pabSrc;
256 uint8_t *pbEnd = &g_pabSrc[g_cbPages];
257 for (; pb != pbEnd; pb += 16)
258 {
259 char szTmp[17];
260 RTStrPrintf(szTmp, sizeof(szTmp), "aaaa%08Xzzzz", (uint32_t)(uintptr_t)pb);
261 memcpy(pb, szTmp, 16);
262 }
263 }
264 }
265
266 g_pabDecompr = (uint8_t *)RTMemAlloc(g_cbPages);
267 g_cbComprAlloc = RT_MAX(g_cbPages * 2, 256 * PAGE_SIZE);
268 g_pabCompr = (uint8_t *)RTMemAlloc(g_cbComprAlloc);
269 if (!g_pabSrc || !g_pabDecompr || !g_pabCompr)
270 return Error("failed to allocate memory buffers (g_cPages=%#x)\n", g_cPages);
271
272 /*
273 * Double loop compressing and uncompressing the data, where the outer does
274 * the specified number of interations while the inner applies the different
275 * compression algorithms.
276 */
277 struct
278 {
279 /** The time spent decompressing. */
280 uint64_t cNanoDecompr;
281 /** The time spent compressing. */
282 uint64_t cNanoCompr;
283 /** The size of the compressed data. */
284 uint64_t cbCompr;
285 /** First error. */
286 int rc;
287 /** The compression style: block or stream. */
288 bool fBlock;
289 /** Compresstion type. */
290 RTZIPTYPE enmType;
291 /** Compresison level. */
292 RTZIPLEVEL enmLevel;
293 /** Method name. */
294 const char *pszName;
295 } aTests[] =
296 {
297 { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZip/Store" },
298 { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZip/LZF" },
299/* { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT, "RTZip/zlib" }, - slow plus it randomly hits VERR_GENERAL_FAILURE atm. */
300 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZipBlock/Store" },
301 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZF" },
302 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZJB, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZJB" },
303 { 0, 0, 0, VINF_SUCCESS, true, RTZIPTYPE_LZO, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZO" },
304 };
305 RTPrintf("tstCompressionBenchmark: TESTING..");
306 for (uint32_t i = 0; i < cIterations; i++)
307 {
308 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
309 {
310 if (RT_FAILURE(aTests[j].rc))
311 continue;
312 memset(g_pabCompr, 0xaa, g_cbComprAlloc);
313 memset(g_pabDecompr, 0xcc, g_cbPages);
314 g_cbCompr = 0;
315 g_offComprIn = 0;
316 RTPrintf("."); RTStrmFlush(g_pStdOut);
317
318 /*
319 * Compress it.
320 */
321 uint64_t NanoTS = RTTimeNanoTS();
322 if (aTests[j].fBlock)
323 {
324 size_t cbLeft = g_cbComprAlloc;
325 uint8_t const *pbSrcPage = g_pabSrc;
326 uint8_t *pbDstPage = g_pabCompr;
327 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
328 {
329 AssertBreakStmt(cbLeft > PAGE_SIZE * 4, aTests[j].rc = rc = VERR_BUFFER_OVERFLOW);
330 uint32_t *pcb = (uint32_t *)pbDstPage;
331 pbDstPage += sizeof(uint32_t);
332 cbLeft -= sizeof(uint32_t);
333 size_t cbSrc = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
334 size_t cbDst;
335 rc = RTZipBlockCompress(aTests[j].enmType, aTests[j].enmLevel, 0 /*fFlags*/,
336 pbSrcPage, cbSrc,
337 pbDstPage, cbLeft, &cbDst);
338 if (RT_FAILURE(rc))
339 {
340 Error("RTZipBlockCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
341 aTests[j].rc = rc;
342 break;
343 }
344 *pcb = (uint32_t)cbDst;
345 cbLeft -= cbDst;
346 pbDstPage += cbDst;
347 pbSrcPage += cbSrc;
348 }
349 if (RT_FAILURE(rc))
350 continue;
351 g_cbCompr = pbDstPage - g_pabCompr;
352 }
353 else
354 {
355 PRTZIPCOMP pZipComp;
356 rc = RTZipCompCreate(&pZipComp, NULL, ComprOutCallback, aTests[j].enmType, aTests[j].enmLevel);
357 if (RT_FAILURE(rc))
358 {
359 Error("Failed to create the compressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
360 aTests[j].rc = rc;
361 continue;
362 }
363
364 uint8_t const *pbSrcPage = g_pabSrc;
365 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
366 {
367 size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
368 rc = RTZipCompress(pZipComp, pbSrcPage, cb);
369 if (RT_FAILURE(rc))
370 {
371 Error("RTZipCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
372 aTests[j].rc = rc;
373 break;
374 }
375 pbSrcPage += cb;
376 }
377 if (RT_FAILURE(rc))
378 continue;
379 rc = RTZipCompFinish(pZipComp);
380 if (RT_FAILURE(rc))
381 {
382 Error("RTZipCompFinish failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
383 aTests[j].rc = rc;
384 break;
385 }
386 RTZipCompDestroy(pZipComp);
387 }
388 NanoTS = RTTimeNanoTS() - NanoTS;
389 aTests[j].cbCompr += g_cbCompr;
390 aTests[j].cNanoCompr += NanoTS;
391
392 /*
393 * Decompress it.
394 */
395 NanoTS = RTTimeNanoTS();
396 if (aTests[j].fBlock)
397 {
398 uint8_t const *pbSrcPage = g_pabCompr;
399 size_t cbLeft = g_cbCompr;
400 uint8_t *pbDstPage = g_pabDecompr;
401 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
402 {
403 size_t cbDst = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
404 size_t cbSrc = *(uint32_t *)pbSrcPage;
405 pbSrcPage += sizeof(uint32_t);
406 cbLeft -= sizeof(uint32_t);
407 rc = RTZipBlockDecompress(aTests[j].enmType, 0 /*fFlags*/,
408 pbSrcPage, cbSrc, &cbSrc,
409 pbDstPage, cbDst, &cbDst);
410 if (RT_FAILURE(rc))
411 {
412 Error("RTZipBlockDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
413 aTests[j].rc = rc;
414 break;
415 }
416 pbDstPage += cbDst;
417 cbLeft -= cbSrc;
418 pbSrcPage += cbSrc;
419 }
420 if (RT_FAILURE(rc))
421 continue;
422 }
423 else
424 {
425 PRTZIPDECOMP pZipDecomp;
426 rc = RTZipDecompCreate(&pZipDecomp, NULL, DecomprInCallback);
427 if (RT_FAILURE(rc))
428 {
429 Error("Failed to create the decompressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
430 aTests[j].rc = rc;
431 continue;
432 }
433
434 uint8_t *pbDstPage = g_pabDecompr;
435 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
436 {
437 size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
438 rc = RTZipDecompress(pZipDecomp, pbDstPage, cb, NULL);
439 if (RT_FAILURE(rc))
440 {
441 Error("RTZipDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
442 aTests[j].rc = rc;
443 break;
444 }
445 pbDstPage += cb;
446 }
447 RTZipDecompDestroy(pZipDecomp);
448 if (RT_FAILURE(rc))
449 continue;
450 }
451 NanoTS = RTTimeNanoTS() - NanoTS;
452 aTests[j].cNanoDecompr += NanoTS;
453
454 if (memcmp(g_pabDecompr, g_pabSrc, g_cbPages))
455 {
456 Error("The compressed data doesn't match the source for '%s' (%#u)\n", aTests[j].pszName, j);
457 aTests[j].rc = VERR_BAD_EXE_FORMAT;
458 continue;
459 }
460 }
461 }
462 if (RT_SUCCESS(rc))
463 RTPrintf("\n");
464
465 /*
466 * Report the results.
467 */
468 rc = 0;
469 RTPrintf("tstCompressionBenchmark: BEGIN RESULTS\n");
470 RTPrintf("%-20s Compression Decompression\n", "");
471 RTPrintf("%-20s In Out Ratio Size In Out\n", "Method");
472 RTPrintf("%.20s-----------------------------------------------------------------------------------------\n", "---------------------------------------------");
473 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
474 {
475 if (RT_SUCCESS(aTests[j].rc))
476 {
477 unsigned uComprSpeedIn = (unsigned)(cbTotalKB / (long double)aTests[j].cNanoCompr * 1000000000.0);
478 unsigned uComprSpeedOut = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoCompr * 1000000000.0 / 1024);
479 unsigned uRatio = (unsigned)(aTests[j].cbCompr / cIterations * 100 / g_cbPages);
480 unsigned uDecomprSpeedIn = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoDecompr * 1000000000.0 / 1024);
481 unsigned uDecomprSpeedOut = (unsigned)(cbTotalKB / (long double)aTests[j].cNanoDecompr * 1000000000.0);
482 RTPrintf("%-20s %'9u KB/s %'9u KB/s %3u%% %'11llu bytes %'9u KB/s %'9u KB/s",
483 aTests[j].pszName,
484 uComprSpeedIn, uComprSpeedOut, uRatio, aTests[j].cbCompr / cIterations,
485 uDecomprSpeedIn, uDecomprSpeedOut);
486#if 0
487 RTPrintf(" [%'14llu / %'14llu ns]\n",
488 aTests[j].cNanoCompr / cIterations,
489 aTests[j].cNanoDecompr / cIterations);
490#else
491 RTPrintf("\n");
492#endif
493 }
494 else
495 {
496 RTPrintf("%-20s: %Rrc\n", aTests[j].pszName, aTests[j].rc);
497 rc = 1;
498 }
499 }
500 if (pszPageFile)
501 RTPrintf("Input: %'10zu pages from '%s' starting at offset %'lld (%#llx)\n"
502 " %'11zu bytes\n",
503 g_cPages, pszPageFile, offPageFile, offPageFile, g_cbPages);
504 else
505 RTPrintf("Input: %'10zu pages of generated rubbish %'11zu bytes\n",
506 g_cPages, g_cbPages);
507
508 /*
509 * Count zero pages in the data set.
510 */
511 size_t cZeroPages = 0;
512 for (size_t iPage = 0; iPage < g_cPages; iPage++)
513 {
514 if (!ASMMemIsAllU32(&g_pabSrc[iPage * PAGE_SIZE], PAGE_SIZE, 0))
515 cZeroPages++;
516 }
517 RTPrintf(" %'10zu zero pages (%u %%)\n", cZeroPages, cZeroPages * 100 / g_cPages);
518
519 /*
520 * A little extension to the test, benchmark relevant CRCs.
521 */
522 RTPrintf("\n"
523 "tstCompressionBenchmark: Checksum/CRC\n");
524 tstBenchmarkCRCs(g_pabSrc, g_cbPages);
525
526 RTPrintf("tstCompressionBenchmark: END RESULTS\n");
527
528
529 return rc;
530}
531
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette