VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp@ 25275

Last change on this file since 25275 was 25019, checked in by vboxsync, 14 years ago

VBoxManage: -Wshadow warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1/* $Id: VBoxManageMetrics.cpp 25019 2009-11-26 15:38:39Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'metrics' command.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * 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#ifndef VBOX_ONLY_DOCS
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <VBox/com/com.h>
28#include <VBox/com/array.h>
29#include <VBox/com/ErrorInfo.h>
30#include <VBox/com/errorprint.h>
31#include <VBox/com/VirtualBox.h>
32
33#include <iprt/asm.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <iprt/time.h>
37#include <iprt/thread.h>
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41using namespace com;
42
43
44// funcs
45///////////////////////////////////////////////////////////////////////////////
46
47
48static char *toBaseMetricNames(const char *metricList)
49{
50 char *newList = (char*)RTMemAlloc(strlen(metricList) + 1);
51 int cSlashes = 0;
52 bool fSkip = false;
53 const char *src = metricList;
54 char c, *dst = newList;
55 while ((c = *src++))
56 if (c == ':')
57 fSkip = true;
58 else if (c == '/' && ++cSlashes == 2)
59 fSkip = true;
60 else if (c == ',')
61 {
62 fSkip = false;
63 cSlashes = 0;
64 *dst++ = c;
65 }
66 else
67 if (!fSkip)
68 *dst++ = c;
69 *dst = 0;
70 return newList;
71}
72
73static int parseFilterParameters(int argc, char *argv[],
74 ComPtr<IVirtualBox> aVirtualBox,
75 ComSafeArrayOut(BSTR, outMetrics),
76 ComSafeArrayOut(BSTR, outBaseMetrics),
77 ComSafeArrayOut(IUnknown *, outObjects))
78{
79 HRESULT rc = S_OK;
80 com::SafeArray<BSTR> retMetrics(1);
81 com::SafeArray<BSTR> retBaseMetrics(1);
82 com::SafeIfaceArray <IUnknown> retObjects;
83
84 Bstr metricNames, baseNames;
85
86 /* Metric list */
87 if (argc > 1)
88 {
89 metricNames = argv[1];
90 char *tmp = toBaseMetricNames(argv[1]);
91 if (!tmp)
92 return VERR_NO_MEMORY;
93 baseNames = tmp;
94 RTMemFree(tmp);
95 }
96 else
97 {
98 metricNames = L"*";
99 baseNames = L"*";
100 }
101 metricNames.cloneTo(&retMetrics[0]);
102 baseNames.cloneTo(&retBaseMetrics[0]);
103
104 /* Object name */
105 if (argc > 0 && strcmp(argv[0], "*"))
106 {
107 if (!strcmp(argv[0], "host"))
108 {
109 ComPtr<IHost> host;
110 CHECK_ERROR(aVirtualBox, COMGETTER(Host)(host.asOutParam()));
111 retObjects.reset(1);
112 host.queryInterfaceTo(&retObjects[0]);
113 }
114 else
115 {
116 ComPtr <IMachine> machine;
117 rc = aVirtualBox->FindMachine(Bstr(argv[0]), machine.asOutParam());
118 if (SUCCEEDED (rc))
119 {
120 retObjects.reset(1);
121 machine.queryInterfaceTo(&retObjects[0]);
122 }
123 else
124 {
125 errorArgument("Invalid machine name: '%s'", argv[0]);
126 return rc;
127 }
128 }
129
130 }
131
132 retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
133 retBaseMetrics.detachTo(ComSafeArrayOutArg(outBaseMetrics));
134 retObjects.detachTo(ComSafeArrayOutArg(outObjects));
135
136 return rc;
137}
138
139static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
140 ComPtr<IUnknown> aObject)
141{
142 HRESULT rc;
143
144 ComPtr<IHost> host = aObject;
145 if (!host.isNull())
146 return Bstr("host");
147
148 ComPtr<IMachine> machine = aObject;
149 if (!machine.isNull())
150 {
151 Bstr name;
152 CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
153 if (SUCCEEDED(rc))
154 return name;
155 }
156 return Bstr("unknown");
157}
158
159static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox,
160 ComSafeArrayIn(IPerformanceMetric*, aMetrics))
161{
162 HRESULT rc;
163 com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics));
164 if (metrics.size())
165 {
166 ComPtr<IUnknown> object;
167 Bstr metricName;
168 RTPrintf("The following metrics were modified:\n\n"
169 "Object Metric\n"
170 "---------- --------------------\n");
171 for (size_t i = 0; i < metrics.size(); i++)
172 {
173 CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam()));
174 CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam()));
175 RTPrintf("%-10ls %-20ls\n",
176 getObjectName(aVirtualBox, object).raw(), metricName.raw());
177 }
178 RTPrintf("\n");
179 }
180 else
181 {
182 RTPrintf("No metrics match the specified filter!\n");
183 }
184}
185
186/**
187 * list *
188 */
189static int handleMetricsList(int argc, char *argv[],
190 ComPtr<IVirtualBox> aVirtualBox,
191 ComPtr<IPerformanceCollector> performanceCollector)
192{
193 HRESULT rc;
194 com::SafeArray<BSTR> metrics;
195 com::SafeArray<BSTR> baseMetrics;
196 com::SafeIfaceArray<IUnknown> objects;
197
198 rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
199 ComSafeArrayAsOutParam(metrics),
200 ComSafeArrayAsOutParam(baseMetrics),
201 ComSafeArrayAsOutParam(objects));
202 if (FAILED(rc))
203 return 1;
204
205 com::SafeIfaceArray<IPerformanceMetric> metricInfo;
206
207 CHECK_ERROR(performanceCollector,
208 GetMetrics(ComSafeArrayAsInParam(metrics),
209 ComSafeArrayAsInParam(objects),
210 ComSafeArrayAsOutParam(metricInfo)));
211
212 ComPtr<IUnknown> object;
213 Bstr metricName, unit, description;
214 ULONG period, count;
215 LONG minimum, maximum;
216 RTPrintf(
217"Object Metric Unit Minimum Maximum Period Count Description\n"
218"---------- -------------------- ---- ---------- ---------- ---------- ---------- -----------\n");
219 for (size_t i = 0; i < metricInfo.size(); i++)
220 {
221 CHECK_ERROR(metricInfo[i], COMGETTER(Object)(object.asOutParam()));
222 CHECK_ERROR(metricInfo[i], COMGETTER(MetricName)(metricName.asOutParam()));
223 CHECK_ERROR(metricInfo[i], COMGETTER(Period)(&period));
224 CHECK_ERROR(metricInfo[i], COMGETTER(Count)(&count));
225 CHECK_ERROR(metricInfo[i], COMGETTER(MinimumValue)(&minimum));
226 CHECK_ERROR(metricInfo[i], COMGETTER(MaximumValue)(&maximum));
227 CHECK_ERROR(metricInfo[i], COMGETTER(Unit)(unit.asOutParam()));
228 CHECK_ERROR(metricInfo[i], COMGETTER(Description)(description.asOutParam()));
229 RTPrintf("%-10ls %-20ls %-4ls %10d %10d %10u %10u %ls\n",
230 getObjectName(aVirtualBox, object).raw(), metricName.raw(), unit.raw(),
231 minimum, maximum, period, count, description.raw());
232 }
233
234 return 0;
235}
236
237/**
238 * Metics setup
239 */
240static int handleMetricsSetup(int argc, char *argv[],
241 ComPtr<IVirtualBox> aVirtualBox,
242 ComPtr<IPerformanceCollector> performanceCollector)
243{
244 HRESULT rc;
245 com::SafeArray<BSTR> metrics;
246 com::SafeArray<BSTR> baseMetrics;
247 com::SafeIfaceArray<IUnknown> objects;
248 uint32_t period = 1, samples = 1;
249 bool listMatches = false;
250 int i;
251
252 for (i = 1; i < argc; i++)
253 {
254 if ( !strcmp(argv[i], "--period")
255 || !strcmp(argv[i], "-period"))
256 {
257 if (argc <= i + 1)
258 return errorArgument("Missing argument to '%s'", argv[i]);
259 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &period)
260 || !period)
261 return errorArgument("Invalid value for 'period' parameter: '%s'", argv[i]);
262 }
263 else if ( !strcmp(argv[i], "--samples")
264 || !strcmp(argv[i], "-samples"))
265 {
266 if (argc <= i + 1)
267 return errorArgument("Missing argument to '%s'", argv[i]);
268 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &samples)
269 || !samples)
270 return errorArgument("Invalid value for 'samples' parameter: '%s'", argv[i]);
271 }
272 else if ( !strcmp(argv[i], "--list")
273 || !strcmp(argv[i], "-list"))
274 listMatches = true;
275 else
276 break; /* The rest of params should define the filter */
277 }
278
279 rc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
280 ComSafeArrayAsOutParam(metrics),
281 ComSafeArrayAsOutParam(baseMetrics),
282 ComSafeArrayAsOutParam(objects));
283 if (FAILED(rc))
284 return 1;
285
286 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
287 CHECK_ERROR(performanceCollector,
288 SetupMetrics(ComSafeArrayAsInParam(metrics),
289 ComSafeArrayAsInParam(objects), period, samples,
290 ComSafeArrayAsOutParam(affectedMetrics)));
291 if (listMatches)
292 listAffectedMetrics(aVirtualBox,
293 ComSafeArrayAsInParam(affectedMetrics));
294
295 return 0;
296}
297
298/**
299 * metrics query
300 */
301static int handleMetricsQuery(int argc, char *argv[],
302 ComPtr<IVirtualBox> aVirtualBox,
303 ComPtr<IPerformanceCollector> performanceCollector)
304{
305 HRESULT rc;
306 com::SafeArray<BSTR> metrics;
307 com::SafeArray<BSTR> baseMetrics;
308 com::SafeIfaceArray<IUnknown> objects;
309
310 rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
311 ComSafeArrayAsOutParam(metrics),
312 ComSafeArrayAsOutParam(baseMetrics),
313 ComSafeArrayAsOutParam(objects));
314 if (FAILED(rc))
315 return 1;
316
317 com::SafeArray<BSTR> retNames;
318 com::SafeIfaceArray<IUnknown> retObjects;
319 com::SafeArray<BSTR> retUnits;
320 com::SafeArray<ULONG> retScales;
321 com::SafeArray<ULONG> retSequenceNumbers;
322 com::SafeArray<ULONG> retIndices;
323 com::SafeArray<ULONG> retLengths;
324 com::SafeArray<LONG> retData;
325 CHECK_ERROR (performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
326 ComSafeArrayAsInParam(objects),
327 ComSafeArrayAsOutParam(retNames),
328 ComSafeArrayAsOutParam(retObjects),
329 ComSafeArrayAsOutParam(retUnits),
330 ComSafeArrayAsOutParam(retScales),
331 ComSafeArrayAsOutParam(retSequenceNumbers),
332 ComSafeArrayAsOutParam(retIndices),
333 ComSafeArrayAsOutParam(retLengths),
334 ComSafeArrayAsOutParam(retData)) );
335
336 RTPrintf("Object Metric Values\n"
337 "---------- -------------------- --------------------------------------------\n");
338 for (unsigned i = 0; i < retNames.size(); i++)
339 {
340 Bstr metricUnit(retUnits[i]);
341 Bstr metricName(retNames[i]);
342 RTPrintf("%-10ls %-20ls ", getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw());
343 const char *separator = "";
344 for (unsigned j = 0; j < retLengths[i]; j++)
345 {
346 if (retScales[i] == 1)
347 RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
348 else
349 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i],
350 (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw());
351 separator = ", ";
352 }
353 RTPrintf("\n");
354 }
355
356 return 0;
357}
358
359static void getTimestamp(char *pts, size_t tsSize)
360{
361 *pts = 0;
362 AssertReturnVoid(tsSize >= 13); /* 3+3+3+3+1 */
363 RTTIMESPEC TimeSpec;
364 RTTIME Time;
365 RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
366 pts += RTStrFormatNumber(pts, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
367 *pts++ = ':';
368 pts += RTStrFormatNumber(pts, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
369 *pts++ = ':';
370 pts += RTStrFormatNumber(pts, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
371 *pts++ = '.';
372 pts += RTStrFormatNumber(pts, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
373 *pts = 0;
374}
375
376/** Used by the handleMetricsCollect loop. */
377static bool volatile g_fKeepGoing = true;
378
379#ifdef RT_OS_WINDOWS
380/**
381 * Handler routine for catching Ctrl-C, Ctrl-Break and closing of
382 * the console.
383 *
384 * @returns true if handled, false if not handled.
385 * @param dwCtrlType The type of control signal.
386 *
387 * @remarks This is called on a new thread.
388 */
389static BOOL WINAPI ctrlHandler(DWORD dwCtrlType)
390{
391 switch (dwCtrlType)
392 {
393 /* Ctrl-C or Ctrl-Break or Close */
394 case CTRL_C_EVENT:
395 case CTRL_BREAK_EVENT:
396 case CTRL_CLOSE_EVENT:
397 /* Let's shut down gracefully. */
398 ASMAtomicWriteBool(&g_fKeepGoing, false);
399 return TRUE;
400 }
401 /* Don't care about the rest -- let it die a horrible death. */
402 return FALSE;
403}
404#endif /* RT_OS_WINDOWS */
405
406/**
407 * collect
408 */
409static int handleMetricsCollect(int argc, char *argv[],
410 ComPtr<IVirtualBox> aVirtualBox,
411 ComPtr<IPerformanceCollector> performanceCollector)
412{
413 HRESULT rc;
414 com::SafeArray<BSTR> metrics;
415 com::SafeArray<BSTR> baseMetrics;
416 com::SafeIfaceArray<IUnknown> objects;
417 uint32_t period = 1, samples = 1;
418 bool isDetached = false, listMatches = false;
419 int i;
420 for (i = 1; i < argc; i++)
421 {
422 if ( !strcmp(argv[i], "--period")
423 || !strcmp(argv[i], "-period"))
424 {
425 if (argc <= i + 1)
426 return errorArgument("Missing argument to '%s'", argv[i]);
427 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &period)
428 || !period)
429 return errorArgument("Invalid value for 'period' parameter: '%s'", argv[i]);
430 }
431 else if ( !strcmp(argv[i], "--samples")
432 || !strcmp(argv[i], "-samples"))
433 {
434 if (argc <= i + 1)
435 return errorArgument("Missing argument to '%s'", argv[i]);
436 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &samples)
437 || !samples)
438 return errorArgument("Invalid value for 'samples' parameter: '%s'", argv[i]);
439 }
440 else if ( !strcmp(argv[i], "--list")
441 || !strcmp(argv[i], "-list"))
442 listMatches = true;
443 else if ( !strcmp(argv[i], "--detach")
444 || !strcmp(argv[i], "-detach"))
445 isDetached = true;
446 else
447 break; /* The rest of params should define the filter */
448 }
449
450 rc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
451 ComSafeArrayAsOutParam(metrics),
452 ComSafeArrayAsOutParam(baseMetrics),
453 ComSafeArrayAsOutParam(objects));
454 if (FAILED(rc))
455 return 1;
456
457
458 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
459 CHECK_ERROR(performanceCollector,
460 SetupMetrics(ComSafeArrayAsInParam(baseMetrics),
461 ComSafeArrayAsInParam(objects), period, samples,
462 ComSafeArrayAsOutParam(affectedMetrics)));
463 if (listMatches)
464 listAffectedMetrics(aVirtualBox,
465 ComSafeArrayAsInParam(affectedMetrics));
466 if (!affectedMetrics.size())
467 return 1;
468
469 if (isDetached)
470 {
471 RTPrintf("Warning! The background process holding collected metrics will shutdown\n"
472 "in few seconds, discarding all collected data and parameters.\n");
473 return 0;
474 }
475
476#ifdef RT_OS_WINDOWS
477 SetConsoleCtrlHandler(ctrlHandler, true);
478#endif /* RT_OS_WINDOWS */
479
480 RTPrintf("Time stamp Object Metric Value\n");
481
482 while (g_fKeepGoing)
483 {
484 RTPrintf("------------ ---------- -------------------- --------------------\n");
485 RTThreadSleep(period * 1000); // Sleep for 'period' seconds
486 char ts[15];
487
488 getTimestamp(ts, sizeof(ts));
489 com::SafeArray<BSTR> retNames;
490 com::SafeIfaceArray<IUnknown> retObjects;
491 com::SafeArray<BSTR> retUnits;
492 com::SafeArray<ULONG> retScales;
493 com::SafeArray<ULONG> retSequenceNumbers;
494 com::SafeArray<ULONG> retIndices;
495 com::SafeArray<ULONG> retLengths;
496 com::SafeArray<LONG> retData;
497 CHECK_ERROR (performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
498 ComSafeArrayAsInParam(objects),
499 ComSafeArrayAsOutParam(retNames),
500 ComSafeArrayAsOutParam(retObjects),
501 ComSafeArrayAsOutParam(retUnits),
502 ComSafeArrayAsOutParam(retScales),
503 ComSafeArrayAsOutParam(retSequenceNumbers),
504 ComSafeArrayAsOutParam(retIndices),
505 ComSafeArrayAsOutParam(retLengths),
506 ComSafeArrayAsOutParam(retData)) );
507 for (unsigned j = 0; j < retNames.size(); j++)
508 {
509 Bstr metricUnit(retUnits[j]);
510 Bstr metricName(retNames[j]);
511 RTPrintf("%-12s %-10ls %-20ls ", ts, getObjectName(aVirtualBox, retObjects[j]).raw(), metricName.raw());
512 const char *separator = "";
513 for (unsigned k = 0; k < retLengths[j]; k++)
514 {
515 if (retScales[j] == 1)
516 RTPrintf("%s%d %ls", separator, retData[retIndices[j] + k], metricUnit.raw());
517 else
518 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[j] + k] / retScales[j],
519 (retData[retIndices[j] + k] * 100 / retScales[j]) % 100, metricUnit.raw());
520 separator = ", ";
521 }
522 RTPrintf("\n");
523 }
524 RTStrmFlush(g_pStdOut);
525 }
526
527#ifdef RT_OS_WINDOWS
528 SetConsoleCtrlHandler(ctrlHandler, false);
529#endif /* RT_OS_WINDOWS */
530
531 return 0;
532}
533
534int handleMetrics(HandlerArg *a)
535{
536 int rc;
537
538 /* at least one option: subcommand name */
539 if (a->argc < 1)
540 return errorSyntax(USAGE_METRICS, "Subcommand missing");
541
542 ComPtr<IPerformanceCollector> performanceCollector;
543 CHECK_ERROR(a->virtualBox, COMGETTER(PerformanceCollector)(performanceCollector.asOutParam()));
544
545 if (!strcmp(a->argv[0], "list"))
546 rc = handleMetricsList(a->argc, a->argv, a->virtualBox, performanceCollector);
547 else if (!strcmp(a->argv[0], "setup"))
548 rc = handleMetricsSetup(a->argc, a->argv, a->virtualBox, performanceCollector);
549 else if (!strcmp(a->argv[0], "query"))
550 rc = handleMetricsQuery(a->argc, a->argv, a->virtualBox, performanceCollector);
551 else if (!strcmp(a->argv[0], "collect"))
552 rc = handleMetricsCollect(a->argc, a->argv, a->virtualBox, performanceCollector);
553 else
554 return errorSyntax(USAGE_METRICS, "Invalid subcommand '%s'", a->argv[0]);
555
556 return rc;
557}
558
559#endif /* VBOX_ONLY_DOCS */
560
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use