VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/misc/loadgenerator.cpp@ 62771

Last change on this file since 62771 was 62484, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: loadgenerator.cpp 62484 2016-07-22 18:35:33Z vboxsync $ */
2/** @file
3 * Load Generator.
4 */
5
6/*
7 * Copyright (C) 2007-2016 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/thread.h>
32#include <iprt/time.h>
33#include <iprt/initterm.h>
34#include <iprt/string.h>
35#include <iprt/stream.h>
36#include <iprt/param.h>
37#include <iprt/path.h>
38#include <iprt/process.h>
39#include <iprt/mp.h>
40#include <iprt/asm.h>
41#include <iprt/getopt.h>
42#include <VBox/sup.h>
43
44
45/*********************************************************************************************************************************
46* Global Variables *
47*********************************************************************************************************************************/
48/** Whether the threads should quit or not. */
49static bool volatile g_fQuit = false;
50static const char *g_pszProgramName = NULL;
51
52
53/*********************************************************************************************************************************
54* Internal Functions *
55*********************************************************************************************************************************/
56static int Error(const char *pszFormat, ...);
57
58
59static void LoadGenSpin(uint64_t cNanoSeconds)
60{
61 const uint64_t u64StartTS = RTTimeNanoTS();
62 do
63 {
64 for (uint32_t volatile i = 0; i < 10240 && !g_fQuit; i++)
65 i++;
66 } while (RTTimeNanoTS() - u64StartTS < cNanoSeconds && !g_fQuit);
67}
68
69
70static DECLCALLBACK(int) LoadGenSpinThreadFunction(RTTHREAD hThreadSelf, void *pvUser)
71{
72 NOREF(hThreadSelf);
73 LoadGenSpin(*(uint64_t *)pvUser);
74 return VINF_SUCCESS;
75}
76
77
78static int LoadGenIpiInit(void)
79{
80 /*
81 * Try make sure the support library is initialized...
82 */
83 SUPR3Init(NULL);
84
85 /*
86 * Load the module.
87 */
88 char szPath[RTPATH_MAX];
89 int rc = RTPathAppPrivateArchTop(szPath, sizeof(szPath) - sizeof("/loadgenerator.r0"));
90 if (RT_SUCCESS(rc))
91 {
92 strcat(szPath, "/loadgeneratorR0.r0");
93 void *pvImageBase;
94 rc = SUPR3LoadServiceModule(szPath, "loadgeneratorR0", "LoadGenR0ServiceReqHandler", &pvImageBase);
95 if (RT_SUCCESS(rc))
96 {
97 /* done */
98 }
99 else
100 Error("SUPR3LoadServiceModule(%s): %Rrc\n", szPath, rc);
101 }
102 else
103 Error("RTPathAppPrivateArch: %Rrc\n", rc);
104 return rc;
105}
106
107
108static void LoadGenIpi(uint64_t cNanoSeconds)
109{
110 const uint64_t u64StartTS = RTTimeNanoTS();
111 do
112 {
113 int rc = SUPR3CallR0Service("loadgeneratorR0", sizeof("loadgeneratorR0") - 1,
114 0 /* uOperation */, 1 /* cIpis */, NULL /* pReqHdr */);
115 if (RT_FAILURE(rc))
116 {
117 Error("SUPR3CallR0Service: %Rrc\n", rc);
118 break;
119 }
120 } while (RTTimeNanoTS() - u64StartTS < cNanoSeconds && !g_fQuit);
121}
122
123
124static DECLCALLBACK(int) LoadGenIpiThreadFunction(RTTHREAD hThreadSelf, void *pvUser)
125{
126 LoadGenIpi(*(uint64_t *)pvUser);
127 NOREF(hThreadSelf);
128 return VINF_SUCCESS;
129}
130
131
132static int Error(const char *pszFormat, ...)
133{
134 va_list va;
135 RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgramName);
136 va_start(va, pszFormat);
137 RTStrmPrintfV(g_pStdErr, pszFormat, va);
138 va_end(va);
139 return 1;
140}
141
142
143static int SyntaxError(const char *pszFormat, ...)
144{
145 va_list va;
146 RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgramName);
147 va_start(va, pszFormat);
148 RTStrmPrintfV(g_pStdErr, pszFormat, va);
149 va_end(va);
150 return 1;
151}
152
153
154int main(int argc, char **argv)
155{
156 static const struct LOADGENTYPE
157 {
158 const char *pszName;
159 int (*pfnInit)(void);
160 PFNRTTHREAD pfnThread;
161 } s_aLoadTypes[] =
162 {
163 { "spin", NULL, LoadGenSpinThreadFunction },
164 { "ipi", LoadGenIpiInit, LoadGenIpiThreadFunction },
165 };
166 unsigned iLoadType = 0;
167 static RTTHREAD s_aThreads[256];
168 int rc;
169 uint32_t cThreads = 1;
170 bool fScaleByCpus = false;
171 RTTHREADTYPE enmThreadType = RTTHREADTYPE_DEFAULT;
172 RTPROCPRIORITY enmProcPriority = RTPROCPRIORITY_DEFAULT;
173 uint64_t cNanoSeconds = UINT64_MAX;
174
175 RTR3InitExe(argc, &argv, 0);
176
177 /*
178 * Set program name.
179 */
180 g_pszProgramName = RTPathFilename(argv[0]);
181
182 /*
183 * Parse arguments.
184 */
185 static const RTGETOPTDEF s_aOptions[] =
186 {
187 { "--number-of-threads", 'n', RTGETOPT_REQ_UINT32 },
188 { "--timeout", 't', RTGETOPT_REQ_STRING },
189 { "--thread-type", 'p', RTGETOPT_REQ_STRING },
190 { "--scale-by-cpus", 'c', RTGETOPT_REQ_NOTHING },
191 { "--load", 'l', RTGETOPT_REQ_STRING },
192 };
193 int ch;
194 RTGETOPTUNION ValueUnion;
195 RTGETOPTSTATE GetState;
196 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
197 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
198 {
199 switch (ch)
200 {
201 case 'n':
202 cThreads = ValueUnion.u64;
203 if (cThreads == 0 || cThreads > RT_ELEMENTS(s_aThreads))
204 return SyntaxError("Requested number of threads, %RU32, is out of range (1..%d).\n",
205 cThreads, RT_ELEMENTS(s_aThreads) - 1);
206 break;
207
208 case 't':
209 {
210 char *psz;
211 rc = RTStrToUInt64Ex(ValueUnion.psz, &psz, 0, &cNanoSeconds);
212 if (RT_FAILURE(rc))
213 return SyntaxError("Failed reading the alleged number '%s' (option '%s', rc=%Rrc).\n",
214 ValueUnion.psz, rc);
215 while (*psz == ' ' || *psz == '\t')
216 psz++;
217 if (*psz)
218 {
219 uint64_t u64Factor = 1;
220 if (!strcmp(psz, "ns"))
221 u64Factor = 1;
222 else if (!strcmp(psz, "ms"))
223 u64Factor = 1000;
224 else if (!strcmp(psz, "s"))
225 u64Factor = 1000000000;
226 else if (!strcmp(psz, "m"))
227 u64Factor = UINT64_C(60000000000);
228 else if (!strcmp(psz, "h"))
229 u64Factor = UINT64_C(3600000000000);
230 else
231 return SyntaxError("Unknown time suffix '%s'\n", psz);
232 uint64_t u64 = cNanoSeconds * u64Factor;
233 if (u64 < cNanoSeconds || (u64 < u64Factor && u64))
234 return SyntaxError("Time representation overflowed! (%RU64 * %RU64)\n",
235 psz, cNanoSeconds, u64Factor);
236 cNanoSeconds = u64;
237 }
238 break;
239 }
240
241 case 'p':
242 {
243 enmProcPriority = RTPROCPRIORITY_NORMAL;
244
245 uint32_t u32 = RTTHREADTYPE_INVALID;
246 char *psz;
247 rc = RTStrToUInt32Ex(ValueUnion.psz, &psz, 0, &u32);
248 if (RT_FAILURE(rc) || *psz)
249 {
250 if (!strcmp(ValueUnion.psz, "default"))
251 {
252 enmProcPriority = RTPROCPRIORITY_DEFAULT;
253 enmThreadType = RTTHREADTYPE_DEFAULT;
254 }
255 else if (!strcmp(ValueUnion.psz, "idle"))
256 {
257 enmProcPriority = RTPROCPRIORITY_LOW;
258 enmThreadType = RTTHREADTYPE_INFREQUENT_POLLER;
259 }
260 else if (!strcmp(ValueUnion.psz, "high"))
261 {
262 enmProcPriority = RTPROCPRIORITY_HIGH;
263 enmThreadType = RTTHREADTYPE_IO;
264 }
265 else
266 return SyntaxError("can't grok thread type '%s'\n",
267 ValueUnion.psz);
268 }
269 else
270 {
271 enmThreadType = (RTTHREADTYPE)u32;
272 if (enmThreadType <= RTTHREADTYPE_INVALID || enmThreadType >= RTTHREADTYPE_END)
273 return SyntaxError("thread type '%d' is out of range (%d..%d)\n",
274 ValueUnion.psz, RTTHREADTYPE_INVALID + 1, RTTHREADTYPE_END - 1);
275 }
276 break;
277 }
278
279 case 'c':
280 fScaleByCpus = true;
281 break;
282
283 case 'l':
284 {
285 for (unsigned i = 0; i < RT_ELEMENTS(s_aLoadTypes); i++)
286 if (!strcmp(s_aLoadTypes[i].pszName, ValueUnion.psz))
287 {
288 ValueUnion.psz = NULL;
289 iLoadType = i;
290 break;
291 }
292 if (ValueUnion.psz)
293 return SyntaxError("Unknown load type '%s'.\n", ValueUnion.psz);
294 break;
295 }
296
297 case 'h':
298 RTStrmPrintf(g_pStdOut,
299 "Usage: %s [-p|--thread-type <type>] [-t|--timeout <sec|xxx[h|m|s|ms|ns]>] \\\n"
300 " %*s [-n|--number-of-threads <threads>] [-l|--load <loadtype>]\n"
301 "\n"
302 "Load types: spin, ipi.\n"
303 ,
304 g_pszProgramName, strlen(g_pszProgramName), "");
305 return 1;
306
307 case 'V':
308 RTPrintf("$Revision: 62484 $\n");
309 return 0;
310
311 case VINF_GETOPT_NOT_OPTION:
312 return SyntaxError("Unknown argument #%d: '%s'\n", GetState.iNext-1, ValueUnion.psz);
313
314 default:
315 return RTGetOptPrintError(ch, &ValueUnion);
316 }
317 }
318
319 /*
320 * Scale thread count by host cpu count.
321 */
322 if (fScaleByCpus)
323 {
324 const unsigned cCpus = RTMpGetOnlineCount();
325 if (cCpus * cThreads > RT_ELEMENTS(s_aThreads))
326 return SyntaxError("Requested number of threads, %RU32, is out of range (1..%d) when scaled by %d.\n",
327 cThreads, RT_ELEMENTS(s_aThreads) - 1, cCpus);
328 cThreads *= cCpus;
329 }
330
331 /*
332 * Modify process and thread priority? (ignore failure)
333 */
334 if (enmProcPriority != RTPROCPRIORITY_DEFAULT)
335 RTProcSetPriority(enmProcPriority);
336 if (enmThreadType != RTTHREADTYPE_DEFAULT)
337 RTThreadSetType(RTThreadSelf(), enmThreadType);
338
339 /*
340 * Load type specific init.
341 */
342 if (s_aLoadTypes[iLoadType].pfnInit)
343 {
344 rc = s_aLoadTypes[iLoadType].pfnInit();
345 if (RT_FAILURE(rc))
346 return 1;
347 }
348
349
350 /*
351 * Start threads.
352 */
353 for (unsigned i = 1; i < cThreads; i++)
354 {
355 s_aThreads[i] = NIL_RTTHREAD;
356 rc = RTThreadCreate(&s_aThreads[i], s_aLoadTypes[iLoadType].pfnThread,
357 &cNanoSeconds, 128*1024, enmThreadType, RTTHREADFLAGS_WAITABLE, "spinner");
358 if (RT_FAILURE(rc))
359 {
360 ASMAtomicXchgBool(&g_fQuit, true);
361 RTStrmPrintf(g_pStdErr, "%s: failed to create thread #%d, rc=%Rrc\n", g_pszProgramName, i, rc);
362 while (i-- > 1)
363 RTThreadWait(s_aThreads[i], 1500, NULL);
364 return 1;
365 }
366 }
367
368 /* our selves */
369 s_aLoadTypes[iLoadType].pfnThread(RTThreadSelf(), &cNanoSeconds);
370
371 /*
372 * Wait for threads.
373 */
374 ASMAtomicXchgBool(&g_fQuit, true);
375 for (unsigned i = 1; i < cThreads; i++)
376 RTThreadWait(s_aThreads[i], 1500, NULL);
377
378 return 0;
379}
380
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