VirtualBox

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

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

tstCompressionBenchmark.cpp: more body.

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