VirtualBox

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

Last change on this file since 21840 was 21840, checked in by vboxsync, 16 years ago

tstCompressionBenchmark: More tests.

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

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