VirtualBox

source: vbox/trunk/src/VBox/Main/testcase/tstCollector.cpp@ 92154

Last change on this file since 92154 was 86441, checked in by vboxsync, 4 years ago

tstCollector: file header

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1/* $Id: tstCollector.cpp 86441 2020-10-04 12:05:24Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Performance collector classes test cases.
4 */
5
6/*
7 * Copyright (C) 2008-2020 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
18#ifdef RT_OS_DARWIN
19# include "../src-server/darwin/PerformanceDarwin.cpp"
20#endif
21#ifdef RT_OS_FREEBSD
22# include "../src-server/freebsd/PerformanceFreeBSD.cpp"
23#endif
24#ifdef RT_OS_LINUX
25# include "../src-server/linux/PerformanceLinux.cpp"
26#endif
27#ifdef RT_OS_OS2
28# include "../src-server/os2/PerformanceOS2.cpp"
29#endif
30#ifdef RT_OS_SOLARIS
31# include "../src-server/solaris/PerformanceSolaris.cpp"
32#endif
33#ifdef RT_OS_WINDOWS
34# define _WIN32_DCOM
35# include <iprt/win/objidl.h>
36# include <iprt/win/objbase.h>
37# include "../src-server/win/PerformanceWin.cpp"
38#endif
39
40#include <iprt/initterm.h>
41#include <iprt/stream.h>
42#include <iprt/env.h>
43#include <iprt/err.h>
44#include <iprt/process.h>
45#include <iprt/thread.h>
46#include <iprt/time.h>
47
48#define RUN_TIME_MS 1000
49
50#define N_CALLS(n, fn) \
51 do {\
52 for (int call = 0; call < n; ++call) \
53 rc = collector->fn; \
54 if (RT_FAILURE(rc)) \
55 RTPrintf("tstCollector: "#fn" -> %Rrc\n", rc); \
56 } while (0)
57
58#define CALLS_PER_SECOND(fn, args) \
59 do { \
60 nCalls = 0; \
61 start = RTTimeMilliTS(); \
62 do { \
63 rc = collector->fn args; \
64 if (RT_FAILURE(rc)) \
65 break; \
66 ++nCalls; \
67 } while (RTTimeMilliTS() - start < RUN_TIME_MS); \
68 if (RT_FAILURE(rc)) \
69 RTPrintf("tstCollector: "#fn" -> %Rrc\n", rc); \
70 else \
71 RTPrintf("%70s -- %u calls per second\n", #fn, nCalls); \
72 } while (0)
73
74void shutdownProcessList(std::vector<RTPROCESS> const &rProcesses)
75{
76 for (size_t i = 0; i < rProcesses.size(); i++)
77 RTProcTerminate(rProcesses[i]);
78}
79
80void measurePerformance(pm::CollectorHAL *collector, const char *pszName, int cVMs)
81{
82
83 const char * const args[] = { pszName, "-child", NULL };
84 pm::CollectorHints hints;
85 std::vector<RTPROCESS> processes;
86
87 hints.collectHostCpuLoad();
88 hints.collectHostRamUsage();
89 /* Start fake VMs */
90 for (int i = 0; i < cVMs; ++i)
91 {
92 RTPROCESS pid;
93 int rc = RTProcCreate(pszName, args, RTENV_DEFAULT, 0, &pid);
94 if (RT_FAILURE(rc))
95 {
96 hints.getProcesses(processes);
97 shutdownProcessList(processes);
98
99 RTPrintf("tstCollector: RTProcCreate() -> %Rrc\n", rc);
100 return;
101 }
102 hints.collectProcessCpuLoad(pid);
103 hints.collectProcessRamUsage(pid);
104 }
105
106 hints.getProcesses(processes);
107 RTThreadSleep(30000); // Let children settle for half a minute
108
109 int rc;
110 ULONG tmp;
111 uint64_t tmp64;
112 uint64_t start;
113 unsigned int nCalls;
114 /* Pre-collect */
115 CALLS_PER_SECOND(preCollect, (hints, 0));
116 /* Host CPU load */
117 CALLS_PER_SECOND(getRawHostCpuLoad, (&tmp64, &tmp64, &tmp64));
118 /* Process CPU load */
119 CALLS_PER_SECOND(getRawProcessCpuLoad, (processes[nCalls % cVMs], &tmp64, &tmp64, &tmp64));
120 /* Host CPU speed */
121 CALLS_PER_SECOND(getHostCpuMHz, (&tmp));
122 /* Host RAM usage */
123 CALLS_PER_SECOND(getHostMemoryUsage, (&tmp, &tmp, &tmp));
124 /* Process RAM usage */
125 CALLS_PER_SECOND(getProcessMemoryUsage, (processes[nCalls % cVMs], &tmp));
126
127 start = RTTimeNanoTS();
128
129 int times;
130 for (times = 0; times < 100; times++)
131 {
132 /* Pre-collect */
133 N_CALLS(1, preCollect(hints, 0));
134 /* Host CPU load */
135 N_CALLS(1, getRawHostCpuLoad(&tmp64, &tmp64, &tmp64));
136 /* Host CPU speed */
137 N_CALLS(1, getHostCpuMHz(&tmp));
138 /* Host RAM usage */
139 N_CALLS(1, getHostMemoryUsage(&tmp, &tmp, &tmp));
140 /* Process CPU load */
141 N_CALLS(cVMs, getRawProcessCpuLoad(processes[call], &tmp64, &tmp64, &tmp64));
142 /* Process RAM usage */
143 N_CALLS(cVMs, getProcessMemoryUsage(processes[call], &tmp));
144 }
145 RTPrintf("\n%d VMs -- %.2f%% of CPU time\n", cVMs, (RTTimeNanoTS() - start) / 10000000. / times);
146
147 /* Shut down fake VMs */
148 shutdownProcessList(processes);
149}
150
151#ifdef RT_OS_SOLARIS
152#define NETIFNAME "net0"
153#else
154#define NETIFNAME "eth0"
155#endif
156int testNetwork(pm::CollectorHAL *collector)
157{
158 pm::CollectorHints hints;
159 uint64_t hostRxStart, hostTxStart;
160 uint64_t hostRxStop, hostTxStop, speed = 125000000; /* Assume 1Gbit/s */
161
162 RTPrintf("tstCollector: TESTING - Network load, sleeping for 5 s...\n");
163
164 hostRxStart = hostTxStart = 0;
165 int rc = collector->preCollect(hints, 0);
166 if (RT_FAILURE(rc))
167 {
168 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
169 return 1;
170 }
171 rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStart, &hostTxStart);
172 if (rc == VERR_NOT_IMPLEMENTED)
173 RTPrintf("tstCollector: getRawHostNetworkLoad() not implemented, skipping\n");
174 else
175 {
176 if (RT_FAILURE(rc))
177 {
178 RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc);
179 return 1;
180 }
181
182 RTThreadSleep(5000); // Sleep for five seconds
183
184 rc = collector->preCollect(hints, 0);
185 if (RT_FAILURE(rc))
186 {
187 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
188 return 1;
189 }
190 hostRxStop = hostRxStart;
191 hostTxStop = hostTxStart;
192 rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStop, &hostTxStop);
193 if (RT_FAILURE(rc))
194 {
195 RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc);
196 return 1;
197 }
198 RTPrintf("tstCollector: host network speed = %llu bytes/sec (%llu mbit/sec)\n",
199 speed, speed/(1000000/8));
200 RTPrintf("tstCollector: host network rx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n",
201 (hostRxStop - hostRxStart)/5, (hostRxStop - hostRxStart)/(5000000/8),
202 (hostRxStop - hostRxStart) * 100 / (speed * 5),
203 (hostRxStop - hostRxStart) * 10000 / (speed * 5) % 100);
204 RTPrintf("tstCollector: host network tx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n\n",
205 (hostTxStop - hostTxStart)/5, (hostTxStop - hostTxStart)/(5000000/8),
206 (hostTxStop - hostTxStart) * 100 / (speed * 5),
207 (hostTxStop - hostTxStart) * 10000 / (speed * 5) % 100);
208 }
209
210 return 0;
211}
212
213#define FSNAME "/"
214int testFsUsage(pm::CollectorHAL *collector)
215{
216 RTPrintf("tstCollector: TESTING - File system usage\n");
217
218 ULONG total, used, available;
219
220 int rc = collector->getHostFilesystemUsage(FSNAME, &total, &used, &available);
221 if (rc == VERR_NOT_IMPLEMENTED)
222 RTPrintf("tstCollector: getHostFilesystemUsage() not implemented, skipping\n");
223 else
224 {
225 if (RT_FAILURE(rc))
226 {
227 RTPrintf("tstCollector: getHostFilesystemUsage() -> %Rrc\n", rc);
228 return 1;
229 }
230 RTPrintf("tstCollector: host root fs total = %lu MB\n", total);
231 RTPrintf("tstCollector: host root fs used = %lu MB\n", used);
232 RTPrintf("tstCollector: host root fs available = %lu MB\n\n", available);
233 }
234 return 0;
235}
236
237int testDisk(pm::CollectorHAL *collector)
238{
239 pm::CollectorHints hints;
240 uint64_t diskMsStart, totalMsStart;
241 uint64_t diskMsStop, totalMsStop;
242
243 pm::DiskList disksUsage, disksLoad;
244 int rc = collector->getDiskListByFs(FSNAME, disksUsage, disksLoad);
245 if (rc == VERR_NOT_IMPLEMENTED)
246 RTPrintf("tstCollector: getDiskListByFs() not implemented, skipping\n");
247 else
248 {
249 if (RT_FAILURE(rc))
250 {
251 RTPrintf("tstCollector: getDiskListByFs(%s) -> %Rrc\n", FSNAME, rc);
252 return 1;
253 }
254 if (disksUsage.empty())
255 {
256 RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME);
257 return 0;
258 }
259 if (disksLoad.empty())
260 {
261 RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME);
262 return 0;
263 }
264
265 pm::DiskList::iterator it;
266 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
267 {
268 uint64_t diskSize = 0;
269 rc = collector->getHostDiskSize(it->c_str(), &diskSize);
270 RTPrintf("tstCollector: TESTING - Disk size (%s) = %llu\n", it->c_str(), diskSize);
271 if (rc == VERR_FILE_NOT_FOUND)
272 RTPrintf("tstCollector: getHostDiskSize(%s) returned VERR_FILE_NOT_FOUND\n", it->c_str());
273 else if (RT_FAILURE(rc))
274 {
275 RTPrintf("tstCollector: getHostDiskSize() -> %Rrc\n", rc);
276 return 1;
277 }
278 }
279
280 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
281 {
282 RTPrintf("tstCollector: TESTING - Disk utilization (%s), sleeping for 5 s...\n", it->c_str());
283
284 hints.collectHostCpuLoad();
285 rc = collector->preCollect(hints, 0);
286 if (RT_FAILURE(rc))
287 {
288 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
289 return 1;
290 }
291 rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStart, &totalMsStart);
292 if (RT_FAILURE(rc))
293 {
294 RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc);
295 return 1;
296 }
297
298 RTThreadSleep(5000); // Sleep for five seconds
299
300 rc = collector->preCollect(hints, 0);
301 if (RT_FAILURE(rc))
302 {
303 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
304 return 1;
305 }
306 rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStop, &totalMsStop);
307 if (RT_FAILURE(rc))
308 {
309 RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc);
310 return 1;
311 }
312 RTPrintf("tstCollector: host disk util = %llu msec (%u.%u %%), total = %llu msec\n\n",
313 (diskMsStop - diskMsStart),
314 (unsigned)((diskMsStop - diskMsStart) * 100 / (totalMsStop - totalMsStart)),
315 (unsigned)((diskMsStop - diskMsStart) * 10000 / (totalMsStop - totalMsStart) % 100),
316 totalMsStop - totalMsStart);
317 }
318 }
319
320 return 0;
321}
322
323
324
325int main(int argc, char *argv[])
326{
327 bool cpuTest, ramTest, netTest, diskTest, fsTest, perfTest;
328 cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = false;
329 /*
330 * Initialize the VBox runtime without loading
331 * the support driver.
332 */
333 int rc = RTR3InitExe(argc, &argv, 0);
334 if (RT_FAILURE(rc))
335 {
336 RTPrintf("tstCollector: RTR3InitExe() -> %d\n", rc);
337 return 1;
338 }
339 if (argc > 1)
340 {
341 if (!strcmp(argv[1], "-child"))
342 {
343 /* We have spawned ourselves as a child process -- scratch the leg */
344 RTThreadSleep(1000000);
345 return 1;
346 }
347 for (int i = 1; i < argc; i++)
348 {
349 if (!strcmp(argv[i], "-cpu"))
350 cpuTest = true;
351 else if (!strcmp(argv[i], "-ram"))
352 ramTest = true;
353 else if (!strcmp(argv[i], "-net"))
354 netTest = true;
355 else if (!strcmp(argv[i], "-disk"))
356 diskTest = true;
357 else if (!strcmp(argv[i], "-fs"))
358 fsTest = true;
359 else if (!strcmp(argv[i], "-perf"))
360 perfTest = true;
361 else
362 {
363 RTPrintf("tstCollector: Unknown option: %s\n", argv[i]);
364 return 2;
365 }
366 }
367 }
368 else
369 cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = true;
370
371#ifdef RT_OS_WINDOWS
372 HRESULT hRes = CoInitialize(NULL);
373 /*
374 * Need to initialize security to access performance enumerators.
375 */
376 hRes = CoInitializeSecurity(
377 NULL,
378 -1,
379 NULL,
380 NULL,
381 RPC_C_AUTHN_LEVEL_NONE,
382 RPC_C_IMP_LEVEL_IMPERSONATE,
383 NULL, EOAC_NONE, 0);
384#endif
385
386 pm::CollectorHAL *collector = pm::createHAL();
387 if (!collector)
388 {
389 RTPrintf("tstCollector: createMetricFactory() failed\n");
390 return 1;
391 }
392
393 pm::CollectorHints hints;
394 if (cpuTest)
395 {
396 hints.collectHostCpuLoad();
397 hints.collectProcessCpuLoad(RTProcSelf());
398 }
399 if (ramTest)
400 {
401 hints.collectHostRamUsage();
402 hints.collectProcessRamUsage(RTProcSelf());
403 }
404
405 uint64_t start;
406
407 uint64_t hostUserStart, hostKernelStart, hostIdleStart;
408 uint64_t hostUserStop, hostKernelStop, hostIdleStop, hostTotal;
409
410 uint64_t processUserStart, processKernelStart, processTotalStart;
411 uint64_t processUserStop, processKernelStop, processTotalStop;
412
413 rc = collector->preCollect(hints, 0);
414 if (RT_FAILURE(rc))
415 {
416 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
417 return 1;
418 }
419 if (cpuTest)
420 {
421 RTPrintf("tstCollector: TESTING - CPU load, sleeping for 5 s...\n");
422
423 rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart);
424 if (RT_FAILURE(rc))
425 {
426 RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc);
427 return 1;
428 }
429 rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart);
430 if (RT_FAILURE(rc))
431 {
432 RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc);
433 return 1;
434 }
435
436 RTThreadSleep(5000); // Sleep for 5 seconds
437
438 rc = collector->preCollect(hints, 0);
439 if (RT_FAILURE(rc))
440 {
441 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
442 return 1;
443 }
444 rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop);
445 if (RT_FAILURE(rc))
446 {
447 RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc);
448 return 1;
449 }
450 rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop);
451 if (RT_FAILURE(rc))
452 {
453 RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc);
454 return 1;
455 }
456 hostTotal = hostUserStop - hostUserStart
457 + hostKernelStop - hostKernelStart
458 + hostIdleStop - hostIdleStart;
459 RTPrintf("tstCollector: host cpu user = %u.%u %%\n",
460 (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal),
461 (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100));
462 RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n",
463 (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal),
464 (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100));
465 RTPrintf("tstCollector: host cpu idle = %u.%u %%\n",
466 (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal),
467 (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100));
468 RTPrintf("tstCollector: process cpu user = %u.%u %%\n",
469 (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)),
470 (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100));
471 RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n",
472 (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)),
473 (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100));
474
475 RTPrintf("tstCollector: TESTING - CPU load, looping for 5 s...\n");
476 rc = collector->preCollect(hints, 0);
477 if (RT_FAILURE(rc))
478 {
479 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
480 return 1;
481 }
482 rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart);
483 if (RT_FAILURE(rc))
484 {
485 RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc);
486 return 1;
487 }
488 rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart);
489 if (RT_FAILURE(rc))
490 {
491 RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc);
492 return 1;
493 }
494 start = RTTimeMilliTS();
495 while (RTTimeMilliTS() - start < 5000)
496 ; // Loop for 5 seconds
497 rc = collector->preCollect(hints, 0);
498 if (RT_FAILURE(rc))
499 {
500 RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc);
501 return 1;
502 }
503 rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop);
504 if (RT_FAILURE(rc))
505 {
506 RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc);
507 return 1;
508 }
509 rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop);
510 if (RT_FAILURE(rc))
511 {
512 RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc);
513 return 1;
514 }
515 hostTotal = hostUserStop - hostUserStart
516 + hostKernelStop - hostKernelStart
517 + hostIdleStop - hostIdleStart;
518 RTPrintf("tstCollector: host cpu user = %u.%u %%\n",
519 (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal),
520 (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100));
521 RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n",
522 (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal),
523 (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100));
524 RTPrintf("tstCollector: host cpu idle = %u.%u %%\n",
525 (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal),
526 (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100));
527 RTPrintf("tstCollector: process cpu user = %u.%u %%\n",
528 (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)),
529 (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100));
530 RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n",
531 (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)),
532 (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100));
533 }
534
535 if (ramTest)
536 {
537 RTPrintf("tstCollector: TESTING - Memory usage\n");
538
539 ULONG total, used, available, processUsed;
540
541 rc = collector->getHostMemoryUsage(&total, &used, &available);
542 if (RT_FAILURE(rc))
543 {
544 RTPrintf("tstCollector: getHostMemoryUsage() -> %Rrc\n", rc);
545 return 1;
546 }
547 rc = collector->getProcessMemoryUsage(RTProcSelf(), &processUsed);
548 if (RT_FAILURE(rc))
549 {
550 RTPrintf("tstCollector: getProcessMemoryUsage() -> %Rrc\n", rc);
551 return 1;
552 }
553 RTPrintf("tstCollector: host mem total = %lu kB\n", total);
554 RTPrintf("tstCollector: host mem used = %lu kB\n", used);
555 RTPrintf("tstCollector: host mem available = %lu kB\n", available);
556 RTPrintf("tstCollector: process mem used = %lu kB\n\n", processUsed);
557 }
558
559 if (netTest)
560 rc = testNetwork(collector);
561 if (fsTest)
562 rc = testFsUsage(collector);
563 if (diskTest)
564 rc = testDisk(collector);
565 if (perfTest)
566 {
567 RTPrintf("tstCollector: TESTING - Performance\n\n");
568
569 measurePerformance(collector, argv[0], 100);
570 }
571
572 delete collector;
573
574 RTPrintf("\ntstCollector FINISHED.\n");
575
576 return RTEXITCODE_SUCCESS;
577}
578
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use