VirtualBox

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

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

Frontends/VBoxManage: split off metrics command to reduce chance of compiler screwup.

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