VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTStrCache.cpp@ 62021

Last change on this file since 62021 was 59747, checked in by vboxsync, 9 years ago

iprt/asm.h: Cleaned up the ASMMemIsAll8/U32 mess and implmeneted the former in assembly. (Found inverted usage due to bad naming in copyUtf8Block, but it is fortunately an unused method.) Replaces the complicated ASMBitFirstSet based scanning in RTSgBufIsZero with a simple call to the new ASMMemIsZero function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/* $Id: tstRTStrCache.cpp 59747 2016-02-19 23:18:18Z vboxsync $ */
2/** @file
3 * IPRT Testcase - StrCache.
4 */
5
6/*
7 * Copyright (C) 2009-2015 Oracle Corporation
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/strcache.h>
32
33#include <iprt/asm.h>
34#include <iprt/ctype.h>
35#include <iprt/err.h>
36#include <iprt/initterm.h>
37#include <iprt/mem.h>
38#include <iprt/rand.h>
39#include <iprt/string.h>
40#include <iprt/test.h>
41#include <iprt/thread.h>
42#include <iprt/time.h>
43
44
45static void tstShowStats(RTSTRCACHE hStrCache)
46{
47 size_t cbStrings;
48 size_t cbChunks;
49 size_t cbBigEntries;
50 uint32_t cHashCollisions;
51 uint32_t cHashCollisions2;
52 uint32_t cHashInserts;
53 uint32_t cRehashes;
54 uint32_t cStrings = RTStrCacheGetStats(hStrCache, &cbStrings, &cbChunks, &cbBigEntries,
55 &cHashCollisions, &cHashCollisions2, &cHashInserts, &cRehashes);
56 if (cbStrings == UINT32_MAX)
57 {
58 RTTESTI_CHECK(!RTStrCacheIsRealImpl());
59 return;
60 }
61
62 RTTestIValue("Strings", cStrings, RTTESTUNIT_OCCURRENCES);
63 RTTestIValue("Memory overhead", (uint64_t)(cbChunks + cbBigEntries - cbStrings) * 100 / cbStrings, RTTESTUNIT_PCT);
64 if (cHashInserts > 0)
65 {
66 RTTestIValue("Collisions", (uint64_t)cHashCollisions * 100 / cHashInserts, RTTESTUNIT_PCT);
67 RTTestIValue("Collisions2", (uint64_t)cHashCollisions2 * 100 / cHashInserts, RTTESTUNIT_PCT);
68 }
69 RTTestIPrintf(RTTESTLVL_ALWAYS, "cHashInserts=%u cHashCollisions=%u cHashCollisions2=%u cRehashes=%u\n",
70 cHashInserts, cHashCollisions, cHashCollisions2, cRehashes);
71 RTTestIPrintf(RTTESTLVL_ALWAYS, "cbChunks=%zu cbBigEntries=%zu cbStrings=%zu\n", cbChunks, cbBigEntries, cbStrings);
72}
73
74
75/**
76 * Check hash and memory performance.
77 */
78static void tst2(void)
79{
80 RTTestISub("Hash performance");
81
82 /*
83 * Generate test strings using a specific pseudo random generator.
84 */
85 size_t cbStrings = 0;
86 char *apszTests[8192];
87 RTRAND hRand;
88 RTTESTI_CHECK_RC_RETV(RTRandAdvCreateParkMiller(&hRand), VINF_SUCCESS);
89 for (uint32_t i = 0; i < 8192; i++)
90 {
91 char szBuf[8192];
92 uint32_t cch = RTRandAdvU32Ex(hRand, 3, sizeof(szBuf) - 1);
93 RTRandAdvBytes(hRand, szBuf, cch);
94 szBuf[cch] = '\0';
95 for (uint32_t off = 0; off < cch; off++)
96 {
97 uint8_t b = szBuf[off];
98 b &= 0x7f;
99 if (!b || b == 0x7f)
100 b = ' ';
101 else if (RTLocCIsCntrl(b) && b != '\n' && b != '\r' && b != '\t')
102 b += 0x30;
103 szBuf[off] = b;
104 }
105 apszTests[i] = (char *)RTMemDup(szBuf, cch + 1);
106 RTTESTI_CHECK_RETV(apszTests[i] != NULL);
107 cbStrings += cch + 1;
108 }
109 RTRandAdvDestroy(hRand);
110 RTTestIValue("Average string", cbStrings / RT_ELEMENTS(apszTests), RTTESTUNIT_BYTES);
111
112 /*
113 * Test new insertion first time around.
114 */
115 RTSTRCACHE hStrCache;
116 RTTESTI_CHECK_RC_RETV(RTStrCacheCreate(&hStrCache, "hash performance"), VINF_SUCCESS);
117
118 uint64_t nsTsStart = RTTimeNanoTS();
119 for (uint32_t i = 0; i < RT_ELEMENTS(apszTests); i++)
120 RTTESTI_CHECK_RETV(RTStrCacheEnter(hStrCache, apszTests[i]) != NULL);
121 uint64_t cNsElapsed = RTTimeNanoTS() - nsTsStart;
122 RTTestIValue("First insert", cNsElapsed / RT_ELEMENTS(apszTests), RTTESTUNIT_NS_PER_CALL);
123
124 /*
125 * Insert existing strings.
126 */
127 nsTsStart = RTTimeNanoTS();
128 for (uint32_t i = 0; i < 8192; i++)
129 RTTESTI_CHECK(RTStrCacheEnter(hStrCache, apszTests[i]) != NULL);
130 cNsElapsed = RTTimeNanoTS() - nsTsStart;
131 RTTestIValue("Duplicate insert", cNsElapsed / RT_ELEMENTS(apszTests), RTTESTUNIT_NS_PER_CALL);
132
133 tstShowStats(hStrCache);
134 RTTESTI_CHECK_RC(RTStrCacheDestroy(hStrCache), VINF_SUCCESS);
135}
136
137
138/**
139 * Basic API checks.
140 * We'll return if any of these fails.
141 */
142static void tst1(RTSTRCACHE hStrCache)
143{
144 const char *psz;
145
146 /* Simple string entering and length. */
147 RTTESTI_CHECK_RETV(psz = RTStrCacheEnter(hStrCache, "abcdefgh"));
148 RTTESTI_CHECK_RETV(strcmp(psz, "abcdefgh") == 0);
149 RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("abcdefgh"));
150 RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0);
151
152 RTTESTI_CHECK_RETV(psz = RTStrCacheEnter(hStrCache, "abcdefghijklmnopqrstuvwxyz"));
153 RTTESTI_CHECK_RETV(strcmp(psz, "abcdefghijklmnopqrstuvwxyz") == 0);
154 RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("abcdefghijklmnopqrstuvwxyz"));
155 RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0);
156
157 /* Unterminated strings. */
158 RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, "0123456789", 3));
159 RTTESTI_CHECK_RETV(strcmp(psz, "012") == 0);
160 RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("012"));
161 RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0);
162
163 RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, "0123456789abcdefghijklmnopqrstuvwxyz", 16));
164 RTTESTI_CHECK_RETV(strcmp(psz, "0123456789abcdef") == 0);
165 RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("0123456789abcdef"));
166 RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0);
167
168 /* String referencing. */
169 char szTest[4096+16];
170 memset(szTest, 'a', sizeof(szTest));
171 char szTest2[4096+16];
172 memset(szTest2, 'f', sizeof(szTest));
173 for (int32_t i = 4096; i > 3; i /= 3)
174 {
175 void *pv2;
176 RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, szTest, i));
177 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz));
178 RTTESTI_CHECK(RTStrCacheRetain(psz) == 2);
179 RTTESTI_CHECK(RTStrCacheRetain(psz) == 3);
180 RTTESTI_CHECK(RTStrCacheRetain(psz) == 4);
181 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz));
182 RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 3);
183 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz));
184 RTTESTI_CHECK(RTStrCacheRetain(psz) == 4);
185 RTTESTI_CHECK(RTStrCacheRetain(psz) == 5);
186 RTTESTI_CHECK(RTStrCacheRetain(psz) == 6);
187 RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 5);
188 RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 4);
189 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz));
190
191 for (uint32_t cRefs = 3;; cRefs--)
192 {
193 RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == cRefs);
194 if (cRefs == 0)
195 break;
196 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x cRefs=%d\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz, cRefs));
197 for (uint32_t j = 0; j < 42; j++)
198 {
199 const char *psz2;
200 RTTESTI_CHECK_RETV(psz2 = RTStrCacheEnterN(hStrCache, szTest2, i));
201 RTTESTI_CHECK_RETV(psz2 != psz);
202 RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz2) == 0);
203 RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x cRefs=%d\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz, cRefs));
204 }
205 }
206 }
207
208 /* Lots of allocations. */
209 memset(szTest, 'b', sizeof(szTest));
210 memset(szTest2, 'e', sizeof(szTest));
211 const char *pszTest1Rets[4096 + 16];
212 const char *pszTest2Rets[4096 + 16];
213 for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
214 {
215 RTTESTI_CHECK(pszTest1Rets[i] = RTStrCacheEnterN(hStrCache, szTest, i));
216 RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i);
217 RTTESTI_CHECK(pszTest2Rets[i] = RTStrCacheEnterN(hStrCache, szTest2, i));
218 RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i);
219 }
220
221 if (RTStrCacheIsRealImpl())
222 {
223 for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
224 {
225 uint32_t cRefs;
226 const char *psz1, *psz2;
227 RTTESTI_CHECK((psz1 = RTStrCacheEnterN(hStrCache, szTest, i)) == pszTest1Rets[i]);
228 RTTESTI_CHECK((psz2 = RTStrCacheEnterN(hStrCache, szTest2, i)) == pszTest2Rets[i]);
229 RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz1)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i));
230 RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz2)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i));
231 }
232 }
233
234 for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++)
235 {
236 uint32_t cRefs;
237 RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i);
238 RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest1Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i));
239 RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i);
240 RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest2Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i));
241 }
242}
243
244
245int main()
246{
247 RTTEST hTest;
248 int rc = RTTestInitAndCreate("tstRTStrCache", &hTest);
249 if (rc)
250 return rc;
251 RTTestBanner(hTest);
252
253 /*
254 * Smoke tests using first the default and then a custom pool.
255 */
256 RTTestSub(hTest, "Smoke test on default cache");
257 tst1(RTSTRCACHE_DEFAULT);
258
259 RTTestSub(hTest, "Smoke test on custom cache");
260 RTSTRCACHE hStrCache;
261 RTTESTI_CHECK_RC(rc = RTStrCacheCreate(&hStrCache, "test 2a"), VINF_SUCCESS);
262 if (RT_SUCCESS(rc))
263 RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(hStrCache), VINF_SUCCESS);
264 RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(NIL_RTSTRCACHE), VINF_SUCCESS);
265 RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(RTSTRCACHE_DEFAULT), VINF_SUCCESS);
266 RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(RTSTRCACHE_DEFAULT), VINF_SUCCESS);
267
268 RTTESTI_CHECK_RC(rc = RTStrCacheCreate(&hStrCache, "test 2b"), VINF_SUCCESS);
269 if (RT_SUCCESS(rc))
270 {
271 tst1(hStrCache);
272 RTTESTI_CHECK_RC(rc = RTStrCacheDestroy(hStrCache), VINF_SUCCESS);
273 }
274
275 /*
276 * Cache performance on relatively real world examples.
277 */
278 tst2();
279
280 /*
281 * Summary.
282 */
283 return RTTestSummaryAndDestroy(hTest);
284}
285
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