VirtualBox

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

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

No LZJB of course.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: tstCompressionBenchmark.cpp 21816 2009-07-27 14:46:32Z 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 };
112
113 const char *pszPageFile = NULL;
114 uint32_t cIterations = 1;
115 uint32_t cPagesAtATime = 1;
116 RTGETOPTUNION Val;
117 RTGETOPTSTATE State;
118 int rc = RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0);
119 AssertRCReturn(rc, 1);
120
121 while ((rc = RTGetOpt(&State, &Val)))
122 {
123 switch (rc)
124 {
125 case 'n':
126 g_cPages = Val.u32;
127 if (g_cPages * PAGE_SIZE * 4 / (PAGE_SIZE * 4) != g_cPages)
128 return Error("The specified page count is too high: %#x (%#llx bytes)\n", g_cPages, (uint64_t)g_cPages * PAGE_SHIFT);
129 if (g_cPages < 1)
130 return Error("The specified page count is too low: %#x\n", g_cPages);
131 break;
132
133 case 'i':
134 cIterations = Val.u32;
135 if (cIterations < 1)
136 return Error("The number of iterations must be 1 or higher\n");
137 break;
138
139 case 'c':
140 cPagesAtATime = Val.u32;
141 if (cPagesAtATime < 1 || cPagesAtATime > 10240)
142 return Error("The specified pages-at-a-time count is out of range: %#x\n", cPagesAtATime);
143 break;
144
145 case 'f':
146 pszPageFile = Val.psz;
147 break;
148
149 default:
150 if (rc == VINF_GETOPT_NOT_OPTION)
151 Error("unknown argument: %s\n", Val.psz);
152 else if (rc > 0)
153 {
154 if (RT_C_IS_GRAPH(rc))
155 Error("unhandled option: -%c\n", rc);
156 else
157 Error("unhandled option: %d\n", rc);
158 }
159 else if (rc == VERR_GETOPT_UNKNOWN_OPTION)
160 Error("unknown option: %s\n", Val.psz);
161 else if (Val.pDef)
162 Error("%s: %Rrs\n", Val.pDef->pszLong, rc);
163 else
164 Error("%Rrs\n", rc);
165 return 1;
166 }
167 }
168
169 g_cbPages = g_cPages * PAGE_SIZE;
170 uint64_t cbTotal = (uint64_t)g_cPages * PAGE_SIZE * cIterations;
171 uint64_t cbTotalKB = cbTotal / _1K;
172 if (cbTotal / cIterations != g_cbPages)
173 return Error("cPages * cIterations -> overflow\n");
174
175 /*
176 * Gather the test memory.
177 */
178 if (pszPageFile)
179 {
180 size_t cbFile;
181 rc = RTFileReadAllEx(pszPageFile, 0, g_cbPages, RTFILE_RDALL_O_DENY_NONE, (void **)&g_pabSrc, &cbFile);
182 if (RT_FAILURE(rc))
183 return Error("Error reading %zu bytes from %s: %Rrc\n", g_cbPages, pszPageFile, rc);
184 if (cbFile != g_cbPages)
185 return Error("Error reading %zu bytes from %s: got %zu bytes\n", g_cbPages, pszPageFile, cbFile);
186 }
187 else
188 {
189 g_pabSrc = (uint8_t *)RTMemAlloc(g_cbPages);
190 if (g_pabSrc)
191 {
192 /* Just fill it with something - warn about the low quality of the something. */
193 RTPrintf("tstCompressionBenchmark: WARNING! No input file was specified so the source\n"
194 "buffer will be filled with generated data of questionable quality.\n");
195#ifdef RT_OS_LINUX
196 RTPrintf("To get real RAM on linux: sudo dd if=/dev/mem ... \n");
197#endif
198 uint8_t *pb = g_pabSrc;
199 uint8_t *pbEnd = &g_pabSrc[g_cbPages];
200 for (; pb != pbEnd; pb += 16)
201 {
202 char szTmp[17];
203 RTStrPrintf(szTmp, sizeof(szTmp), "aaaa%08Xzzzz", (uint32_t)(uintptr_t)pb);
204 memcpy(pb, szTmp, 16);
205 }
206 }
207 }
208
209 g_pabDecompr = (uint8_t *)RTMemAlloc(g_cbPages);
210 g_cbComprAlloc = g_cbPages * 2;
211 g_pabCompr = (uint8_t *)RTMemAlloc(g_cbComprAlloc);
212 if (!g_pabSrc || !g_pabDecompr || !g_pabCompr)
213 return Error("failed to allocate memory buffers (g_cPages=%#x)\n", g_cPages);
214
215 /*
216 * Double loop compressing and uncompressing the data, where the outer does
217 * the specified number of interations while the inner applies the different
218 * compression algorithms.
219 */
220 struct
221 {
222 /** The time spent decompressing. */
223 uint64_t cNanoDecompr;
224 /** The time spent compressing. */
225 uint64_t cNanoCompr;
226 /** The size of the compressed data. */
227 uint64_t cbCompr;
228 /** Number of errrors. */
229 uint32_t cErrors;
230 /** The compression style: block or stream. */
231 bool fBlock;
232 /** Compresstion type. */
233 RTZIPTYPE enmType;
234 /** Compresison level. */
235 RTZIPLEVEL enmLevel;
236 /** Method name. */
237 const char *pszName;
238 } aTests[] =
239 {
240 { 0, 0, 0, 0, false, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZip/Store" },
241 { 0, 0, 0, 0, false, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZip/LZF" },
242// { 0, 0, 0, 0, false, RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT, "RTZip/zlib" }, - slow plus it randomly hits VERR_GENERAL_FAILURE atm.
243 { 0, 0, 0, 0, true, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZipBlock/Store" },
244 { 0, 0, 0, 0, true, RTZIPTYPE_LZF, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZF" },
245// { 0, 0, 0, 0, true, RTZIPTYPE_LZJB, RTZIPLEVEL_DEFAULT, "RTZipBlock/LZJB" },
246 };
247 RTPrintf("tstCompressionBenchmark: TESTING..");
248 for (uint32_t i = 0; i < cIterations; i++)
249 {
250 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
251 {
252 memset(g_pabCompr, 0, g_cbComprAlloc);
253 memset(g_pabDecompr, 0, g_cbPages);
254 g_cbCompr = 0;
255 g_offComprIn = 0;
256 RTPrintf("."); RTStrmFlush(g_pStdOut);
257
258 /*
259 * Compress it.
260 */
261 uint64_t NanoTS = RTTimeNanoTS();
262 if (aTests[j].fBlock)
263 {
264 size_t cbLeft = g_cbComprAlloc;
265 uint8_t const *pbSrcPage = g_pabSrc;
266 uint8_t *pbDstPage = g_pabCompr;
267 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
268 {
269 AssertBreakStmt(cbLeft > PAGE_SIZE * 4, rc = VERR_BUFFER_OVERFLOW);
270 uint32_t *pcb = (uint32_t *)pbDstPage;
271 pbDstPage += sizeof(uint32_t);
272 cbLeft -= sizeof(uint32_t);
273 size_t cbSrc = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
274 size_t cbDst;
275 rc = RTZipBlockCompress(aTests[j].enmType, aTests[j].enmLevel, 0 /*fFlags*/,
276 pbSrcPage, cbSrc,
277 pbDstPage, cbLeft, &cbDst);
278 if (RT_FAILURE(rc))
279 {
280 Error("RTZipBlockCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
281 aTests[j].cErrors++;
282 break;
283 }
284 *pcb = (uint32_t)cbDst;
285 cbLeft -= cbDst;
286 pbDstPage += cbDst;
287 pbSrcPage += cbSrc;
288 }
289 if (RT_FAILURE(rc))
290 continue;
291 g_cbCompr = pbDstPage - g_pabCompr;
292 }
293 else
294 {
295 PRTZIPCOMP pZipComp;
296 rc = RTZipCompCreate(&pZipComp, NULL, ComprOutCallback, aTests[j].enmType, aTests[j].enmLevel);
297 if (RT_FAILURE(rc))
298 {
299 Error("Failed to create the compressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
300 aTests[j].cErrors++;
301 continue;
302 }
303
304 uint8_t const *pbSrcPage = g_pabSrc;
305 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
306 {
307 size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
308 rc = RTZipCompress(pZipComp, pbSrcPage, cb);
309 if (RT_FAILURE(rc))
310 {
311 Error("RTZipCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
312 aTests[j].cErrors++;
313 break;
314 }
315 pbSrcPage += cb;
316 }
317 if (RT_FAILURE(rc))
318 continue;
319 rc = RTZipCompFinish(pZipComp);
320 if (RT_FAILURE(rc))
321 {
322 Error("RTZipCompFinish failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
323 aTests[j].cErrors++;
324 break;
325 }
326 RTZipCompDestroy(pZipComp);
327 }
328 NanoTS = RTTimeNanoTS() - NanoTS;
329 aTests[j].cbCompr += g_cbCompr;
330 aTests[j].cNanoCompr += NanoTS;
331
332 /*
333 * Decompress it.
334 */
335 NanoTS = RTTimeNanoTS();
336 if (aTests[j].fBlock)
337 {
338 uint8_t const *pbSrcPage = g_pabCompr;
339 size_t cbLeft = g_cbCompr;
340 uint8_t *pbDstPage = g_pabDecompr;
341 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
342 {
343 size_t cbDst = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
344 size_t cbSrc = *(uint32_t *)pbSrcPage;
345 pbSrcPage += sizeof(uint32_t);
346 cbLeft -= sizeof(uint32_t);
347 rc = RTZipBlockDecompress(aTests[j].enmType, 0 /*fFlags*/,
348 pbSrcPage, cbSrc, &cbSrc,
349 pbDstPage, cbDst, &cbDst);
350 if (RT_FAILURE(rc))
351 {
352 Error("RTZipBlockDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
353 aTests[j].cErrors++;
354 break;
355 }
356 pbDstPage += cbDst;
357 cbLeft -= cbSrc;
358 pbSrcPage += cbSrc;
359 }
360 if (RT_FAILURE(rc))
361 continue;
362 }
363 else
364 {
365 PRTZIPDECOMP pZipDecomp;
366 rc = RTZipDecompCreate(&pZipDecomp, NULL, DecomprInCallback);
367 if (RT_FAILURE(rc))
368 {
369 Error("Failed to create the decompressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
370 aTests[j].cErrors++;
371 continue;
372 }
373
374 uint8_t *pbDstPage = g_pabDecompr;
375 for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
376 {
377 size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
378 rc = RTZipDecompress(pZipDecomp, pbDstPage, cb, NULL);
379 if (RT_FAILURE(rc))
380 {
381 Error("RTZipDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
382 aTests[j].cErrors++;
383 break;
384 }
385 pbDstPage += cb;
386 }
387 RTZipDecompDestroy(pZipDecomp);
388 if (RT_FAILURE(rc))
389 continue;
390 }
391 NanoTS = RTTimeNanoTS() - NanoTS;
392 aTests[j].cNanoDecompr += NanoTS;
393
394 if (memcmp(g_pabDecompr, g_pabSrc, g_cbPages))
395 {
396 Error("The compressed data doesn't match the source for '%s' (%#u)\n", aTests[j].pszName, j);
397 aTests[j].cErrors++;
398 continue;
399 }
400 }
401 }
402 if (RT_SUCCESS(rc))
403 RTPrintf("\n");
404
405 /*
406 * Report the results.
407 */
408 rc = 0;
409 RTPrintf("tstCompressionBenchmark: BEGIN RESULTS\n");
410 RTPrintf("%-20s Compression Decompression\n", "");
411 RTPrintf("%-20s In Out Ratio Size In Out\n", "Method");
412 RTPrintf("%.20s-----------------------------------------------------------------------------------------\n", "---------------------------------------------");
413 for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
414 {
415 if (!aTests[j].cErrors)
416 {
417 unsigned uComprSpeedIn = (unsigned)(cbTotalKB / (long double)aTests[j].cNanoCompr * 1000000000.0);
418 unsigned uComprSpeedOut = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoCompr * 1000000000.0 / 1024);
419 unsigned uRatio = (unsigned)(aTests[j].cbCompr / cIterations * 100 / g_cbPages);
420 unsigned uDecomprSpeedIn = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoDecompr * 1000000000.0 / 1024);
421 unsigned uDecomprSpeedOut = (unsigned)(cbTotalKB / (long double)aTests[j].cNanoDecompr * 1000000000.0);
422 RTPrintf("%-20s %'9u KB/s %'9u KB/s %3u%% %'11llu bytes %'9u KB/s %'9u KB/s",
423 aTests[j].pszName,
424 uComprSpeedIn, uComprSpeedOut, uRatio, aTests[j].cbCompr / cIterations,
425 uDecomprSpeedIn, uDecomprSpeedOut);
426#if 0
427 RTPrintf(" [%'14llu / %'14llu ns]\n",
428 aTests[j].cNanoCompr / cIterations,
429 aTests[j].cNanoDecompr / cIterations);
430#else
431 RTPrintf("\n");
432#endif
433 }
434 else
435 {
436 RTPrintf("%-20s: %u errors\n", aTests[j].pszName, aTests[j].cErrors);
437 rc = 1;
438 }
439 }
440 RTPrintf("Input: %'12zu pages (%'zu bytes)\n", g_cPages, g_cbPages);
441 RTPrintf("tstCompressionBenchmark: END RESULTS\n");
442
443 return rc;
444}
445
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