VirtualBox

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

Last change on this file since 21989 was 21917, checked in by vboxsync, 15 years ago

tstCompressionBenchmark: Added CRCs to the benchmarks.

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