VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 7 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: VBoxManageMetrics.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'metrics' command.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <VBox/com/com.h>
33#include <VBox/com/array.h>
34#include <VBox/com/ErrorInfo.h>
35#include <VBox/com/errorprint.h>
36#include <VBox/com/VirtualBox.h>
37
38#include <iprt/asm.h>
39#include <iprt/stream.h>
40#include <iprt/string.h>
41#include <iprt/time.h>
42#include <iprt/thread.h>
43#include <VBox/log.h>
44
45#include <set>
46#include <utility>
47
48#include "VBoxManage.h"
49using namespace com;
50
51DECLARE_TRANSLATION_CONTEXT(Metrics);
52
53// funcs
54///////////////////////////////////////////////////////////////////////////////
55
56
57static HRESULT parseFilterParameters(int argc, char *argv[],
58 ComPtr<IVirtualBox> aVirtualBox,
59 ComSafeArrayOut(BSTR, outMetrics),
60 ComSafeArrayOut(IUnknown *, outObjects))
61{
62 HRESULT hrc = S_OK;
63 com::SafeArray<BSTR> retMetrics(1);
64 com::SafeIfaceArray <IUnknown> retObjects;
65
66 Bstr metricNames, baseNames;
67
68 /* Metric list */
69 if (argc > 1)
70 metricNames = argv[1];
71 else
72 {
73 metricNames = L"*";
74 baseNames = L"*";
75 }
76 metricNames.cloneTo(&retMetrics[0]);
77
78 /* Object name */
79 if (argc > 0 && strcmp(argv[0], "*"))
80 {
81 if (!strcmp(argv[0], "host"))
82 {
83 ComPtr<IHost> host;
84 CHECK_ERROR(aVirtualBox, COMGETTER(Host)(host.asOutParam()));
85 retObjects.reset(1);
86 host.queryInterfaceTo(&retObjects[0]);
87 }
88 else
89 {
90 ComPtr<IMachine> machine;
91 hrc = aVirtualBox->FindMachine(Bstr(argv[0]).raw(),
92 machine.asOutParam());
93 if (SUCCEEDED(hrc))
94 {
95 retObjects.reset(1);
96 machine.queryInterfaceTo(&retObjects[0]);
97 }
98 else
99 {
100 errorArgument(Metrics::tr("Invalid machine name: '%s'"), argv[0]);
101 return hrc;
102 }
103 }
104
105 }
106
107 retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
108 retObjects.detachTo(ComSafeArrayOutArg(outObjects));
109
110 return hrc;
111}
112
113static Bstr toBaseName(Utf8Str& aFullName)
114{
115 char *pszRaw = aFullName.mutableRaw();
116 /*
117 * Currently there are two metrics which base name is the same as the
118 * sub-metric name: CPU/MHz and Net/<iface>/LinkSpeed.
119 */
120 if (pszRaw && strcmp(pszRaw, "CPU/MHz") && !RTStrSimplePatternMatch("Net/*/LinkSpeed", pszRaw))
121 {
122 char *pszSlash = strrchr(pszRaw, '/');
123 if (pszSlash)
124 {
125 *pszSlash = 0;
126 aFullName.jolt();
127 }
128 }
129 return Bstr(aFullName);
130}
131
132static Bstr getObjectName(ComPtr<IUnknown> aObject)
133{
134 HRESULT hrc;
135
136 ComPtr<IHost> host = aObject;
137 if (!host.isNull())
138 return Bstr(Metrics::tr("host"));
139
140 ComPtr<IMachine> machine = aObject;
141 if (!machine.isNull())
142 {
143 Bstr name;
144 CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
145 if (SUCCEEDED(hrc))
146 return name;
147 }
148 return Bstr(Metrics::tr("unknown"));
149}
150
151static void listAffectedMetrics(ComSafeArrayIn(IPerformanceMetric*, aMetrics))
152{
153 HRESULT hrc;
154 com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics));
155 if (metrics.size())
156 {
157 ComPtr<IUnknown> object;
158 Bstr metricName;
159 RTPrintf(Metrics::tr("The following metrics were modified:\n\n"
160 "Object Metric\n"
161 "---------- --------------------\n"));
162 for (size_t i = 0; i < metrics.size(); i++)
163 {
164 CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam()));
165 CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam()));
166 RTPrintf("%-10ls %-20ls\n",
167 getObjectName(object).raw(), metricName.raw());
168 }
169 RTPrintf("\n");
170 }
171 else
172 {
173 RTMsgError(Metrics::tr("No metrics match the specified filter!"));
174 }
175}
176
177/**
178 * list
179 */
180static RTEXITCODE handleMetricsList(int argc, char *argv[],
181 ComPtr<IVirtualBox> aVirtualBox,
182 ComPtr<IPerformanceCollector> performanceCollector)
183{
184 HRESULT hrc;
185 com::SafeArray<BSTR> metrics;
186 com::SafeIfaceArray<IUnknown> objects;
187
188 setCurrentSubcommand(HELP_SCOPE_METRICS_LIST);
189
190 hrc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
191 ComSafeArrayAsOutParam(metrics),
192 ComSafeArrayAsOutParam(objects));
193 if (FAILED(hrc))
194 return RTEXITCODE_FAILURE;
195
196 com::SafeIfaceArray<IPerformanceMetric> metricInfo;
197
198 CHECK_ERROR(performanceCollector,
199 GetMetrics(ComSafeArrayAsInParam(metrics),
200 ComSafeArrayAsInParam(objects),
201 ComSafeArrayAsOutParam(metricInfo)));
202
203 ComPtr<IUnknown> object;
204 Bstr metricName, unit, description;
205 ULONG period, count;
206 LONG minimum, maximum;
207 RTPrintf(Metrics::tr(
208"Object Metric Unit Minimum Maximum Period Count Description\n"
209"--------------- ---------------------------------------- ---- ---------- ---------- ---------- ---------- -----------\n"));
210 for (size_t i = 0; i < metricInfo.size(); i++)
211 {
212 CHECK_ERROR(metricInfo[i], COMGETTER(Object)(object.asOutParam()));
213 CHECK_ERROR(metricInfo[i], COMGETTER(MetricName)(metricName.asOutParam()));
214 CHECK_ERROR(metricInfo[i], COMGETTER(Period)(&period));
215 CHECK_ERROR(metricInfo[i], COMGETTER(Count)(&count));
216 CHECK_ERROR(metricInfo[i], COMGETTER(MinimumValue)(&minimum));
217 CHECK_ERROR(metricInfo[i], COMGETTER(MaximumValue)(&maximum));
218 CHECK_ERROR(metricInfo[i], COMGETTER(Unit)(unit.asOutParam()));
219 CHECK_ERROR(metricInfo[i], COMGETTER(Description)(description.asOutParam()));
220 RTPrintf("%-15ls %-40ls %-4ls %10d %10d %10u %10u %ls\n",
221 getObjectName(object).raw(), metricName.raw(), unit.raw(),
222 minimum, maximum, period, count, description.raw());
223 }
224
225 return RTEXITCODE_SUCCESS;
226}
227
228/**
229 * Metrics setup
230 */
231static RTEXITCODE handleMetricsSetup(int argc, char *argv[],
232 ComPtr<IVirtualBox> aVirtualBox,
233 ComPtr<IPerformanceCollector> performanceCollector)
234{
235 HRESULT hrc;
236 com::SafeArray<BSTR> metrics;
237 com::SafeIfaceArray<IUnknown> objects;
238 uint32_t period = 1, samples = 1;
239 bool listMatches = false;
240 int i;
241
242 setCurrentSubcommand(HELP_SCOPE_METRICS_SETUP);
243
244 for (i = 1; i < argc; i++)
245 {
246 if ( !strcmp(argv[i], "--period")
247 || !strcmp(argv[i], "-period"))
248 {
249 if (argc <= i + 1)
250 return errorArgument(Metrics::tr("Missing argument to '%s'"), argv[i]);
251 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &period)
252 || !period)
253 return errorArgument(Metrics::tr("Invalid value for 'period' parameter: '%s'"), argv[i]);
254 }
255 else if ( !strcmp(argv[i], "--samples")
256 || !strcmp(argv[i], "-samples"))
257 {
258 if (argc <= i + 1)
259 return errorArgument(Metrics::tr("Missing argument to '%s'"), argv[i]);
260 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &samples)
261 || !samples)
262 return errorArgument(Metrics::tr("Invalid value for 'samples' parameter: '%s'"), argv[i]);
263 }
264 else if ( !strcmp(argv[i], "--list")
265 || !strcmp(argv[i], "-list"))
266 listMatches = true;
267 else
268 break; /* The rest of params should define the filter */
269 }
270
271 hrc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
272 ComSafeArrayAsOutParam(metrics),
273 ComSafeArrayAsOutParam(objects));
274 if (FAILED(hrc))
275 return RTEXITCODE_FAILURE;
276
277 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
278 CHECK_ERROR(performanceCollector,
279 SetupMetrics(ComSafeArrayAsInParam(metrics),
280 ComSafeArrayAsInParam(objects), period, samples,
281 ComSafeArrayAsOutParam(affectedMetrics)));
282 if (FAILED(hrc))
283 return RTEXITCODE_SYNTAX; /** @todo figure out why we must return 2 here. */
284
285 if (listMatches)
286 listAffectedMetrics(ComSafeArrayAsInParam(affectedMetrics));
287
288 return RTEXITCODE_SUCCESS;
289}
290
291/**
292 * metrics query
293 */
294static RTEXITCODE handleMetricsQuery(int argc, char *argv[],
295 ComPtr<IVirtualBox> aVirtualBox,
296 ComPtr<IPerformanceCollector> performanceCollector)
297{
298 HRESULT hrc;
299 com::SafeArray<BSTR> metrics;
300 com::SafeIfaceArray<IUnknown> objects;
301
302 setCurrentSubcommand(HELP_SCOPE_METRICS_QUERY);
303
304 hrc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
305 ComSafeArrayAsOutParam(metrics),
306 ComSafeArrayAsOutParam(objects));
307 if (FAILED(hrc))
308 return RTEXITCODE_FAILURE;
309
310 com::SafeArray<BSTR> retNames;
311 com::SafeIfaceArray<IUnknown> retObjects;
312 com::SafeArray<BSTR> retUnits;
313 com::SafeArray<ULONG> retScales;
314 com::SafeArray<ULONG> retSequenceNumbers;
315 com::SafeArray<ULONG> retIndices;
316 com::SafeArray<ULONG> retLengths;
317 com::SafeArray<LONG> retData;
318 CHECK_ERROR(performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
319 ComSafeArrayAsInParam(objects),
320 ComSafeArrayAsOutParam(retNames),
321 ComSafeArrayAsOutParam(retObjects),
322 ComSafeArrayAsOutParam(retUnits),
323 ComSafeArrayAsOutParam(retScales),
324 ComSafeArrayAsOutParam(retSequenceNumbers),
325 ComSafeArrayAsOutParam(retIndices),
326 ComSafeArrayAsOutParam(retLengths),
327 ComSafeArrayAsOutParam(retData)) );
328
329 RTPrintf(Metrics::tr(
330 "Object Metric Values\n"
331 "--------------- ---------------------------------------- --------------------------------------------\n"));
332 for (unsigned i = 0; i < retNames.size(); i++)
333 {
334 Bstr metricUnit(retUnits[i]);
335 Bstr metricName(retNames[i]);
336 RTPrintf("%-15ls %-40ls ", getObjectName(retObjects[i]).raw(), metricName.raw());
337 const char *separator = "";
338 for (unsigned j = 0; j < retLengths[i]; j++)
339 {
340 if (retScales[i] == 1)
341 RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
342 else
343 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i],
344 (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw());
345 separator = ", ";
346 }
347 RTPrintf("\n");
348 }
349
350 return RTEXITCODE_SUCCESS;
351}
352
353static void getTimestamp(char *pts, size_t tsSize)
354{
355 *pts = 0;
356 AssertReturnVoid(tsSize >= 13); /* 3+3+3+3+1 */
357 RTTIMESPEC TimeSpec;
358 RTTIME Time;
359 RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
360 pts += RTStrFormatNumber(pts, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
361 *pts++ = ':';
362 pts += RTStrFormatNumber(pts, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
363 *pts++ = ':';
364 pts += RTStrFormatNumber(pts, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
365 *pts++ = '.';
366 pts += RTStrFormatNumber(pts, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
367 *pts = 0;
368}
369
370/** Used by the handleMetricsCollect loop. */
371static bool volatile g_fKeepGoing = true;
372
373#ifdef RT_OS_WINDOWS
374/**
375 * Handler routine for catching Ctrl-C, Ctrl-Break and closing of
376 * the console.
377 *
378 * @returns true if handled, false if not handled.
379 * @param dwCtrlType The type of control signal.
380 *
381 * @remarks This is called on a new thread.
382 */
383static BOOL WINAPI ctrlHandler(DWORD dwCtrlType) RT_NOTHROW_DEF
384{
385 switch (dwCtrlType)
386 {
387 /* Ctrl-C or Ctrl-Break or Close */
388 case CTRL_C_EVENT:
389 case CTRL_BREAK_EVENT:
390 case CTRL_CLOSE_EVENT:
391 /* Let's shut down gracefully. */
392 ASMAtomicWriteBool(&g_fKeepGoing, false);
393 return TRUE;
394 }
395 /* Don't care about the rest -- let it die a horrible death. */
396 return FALSE;
397}
398#endif /* RT_OS_WINDOWS */
399
400/**
401 * collect
402 */
403static RTEXITCODE handleMetricsCollect(int argc, char *argv[],
404 ComPtr<IVirtualBox> aVirtualBox,
405 ComPtr<IPerformanceCollector> performanceCollector)
406{
407 HRESULT hrc;
408 com::SafeArray<BSTR> metrics;
409 com::SafeIfaceArray<IUnknown> objects;
410 uint32_t period = 1, samples = 1;
411 bool isDetached = false, listMatches = false;
412 int i;
413
414 setCurrentSubcommand(HELP_SCOPE_METRICS_COLLECT);
415
416 for (i = 1; i < argc; i++)
417 {
418 if ( !strcmp(argv[i], "--period")
419 || !strcmp(argv[i], "-period"))
420 {
421 if (argc <= i + 1)
422 return errorArgument(Metrics::tr("Missing argument to '%s'"), argv[i]);
423 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &period)
424 || !period)
425 return errorArgument(Metrics::tr("Invalid value for 'period' parameter: '%s'"), argv[i]);
426 }
427 else if ( !strcmp(argv[i], "--samples")
428 || !strcmp(argv[i], "-samples"))
429 {
430 if (argc <= i + 1)
431 return errorArgument(Metrics::tr("Missing argument to '%s'"), argv[i]);
432 if ( VINF_SUCCESS != RTStrToUInt32Full(argv[++i], 10, &samples)
433 || !samples)
434 return errorArgument(Metrics::tr("Invalid value for 'samples' parameter: '%s'"), argv[i]);
435 }
436 else if ( !strcmp(argv[i], "--list")
437 || !strcmp(argv[i], "-list"))
438 listMatches = true;
439 else if ( !strcmp(argv[i], "--detach")
440 || !strcmp(argv[i], "-detach"))
441 isDetached = true;
442 else
443 break; /* The rest of params should define the filter */
444 }
445
446 hrc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
447 ComSafeArrayAsOutParam(metrics),
448 ComSafeArrayAsOutParam(objects));
449 if (FAILED(hrc))
450 return RTEXITCODE_FAILURE;
451
452 com::SafeIfaceArray<IPerformanceMetric> metricInfo;
453
454 CHECK_ERROR(performanceCollector,
455 GetMetrics(ComSafeArrayAsInParam(metrics),
456 ComSafeArrayAsInParam(objects),
457 ComSafeArrayAsOutParam(metricInfo)));
458
459 std::set<std::pair<ComPtr<IUnknown>,Bstr> > baseMetrics;
460 ComPtr<IUnknown> objectFiltered;
461 Bstr metricNameFiltered;
462 for (i = 0; i < (int)metricInfo.size(); i++)
463 {
464 CHECK_ERROR(metricInfo[i], COMGETTER(Object)(objectFiltered.asOutParam()));
465 CHECK_ERROR(metricInfo[i], COMGETTER(MetricName)(metricNameFiltered.asOutParam()));
466 Utf8Str baseMetricName(metricNameFiltered);
467 baseMetrics.insert(std::make_pair(objectFiltered, toBaseName(baseMetricName)));
468 }
469 com::SafeArray<BSTR> baseMetricsFiltered(baseMetrics.size());
470 com::SafeIfaceArray<IUnknown> objectsFiltered(baseMetrics.size());
471 std::set<std::pair<ComPtr<IUnknown>,Bstr> >::iterator it;
472 i = 0;
473 for (it = baseMetrics.begin(); it != baseMetrics.end(); ++it)
474 {
475 it->first.queryInterfaceTo(&objectsFiltered[i]);
476 Bstr(it->second).detachTo(&baseMetricsFiltered[i++]);
477 }
478 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
479 CHECK_ERROR(performanceCollector,
480 SetupMetrics(ComSafeArrayAsInParam(baseMetricsFiltered),
481 ComSafeArrayAsInParam(objectsFiltered), period, samples,
482 ComSafeArrayAsOutParam(affectedMetrics)));
483 if (FAILED(hrc))
484 return RTEXITCODE_SYNTAX; /** @todo figure out why we must return 2 here. */
485
486 if (listMatches)
487 listAffectedMetrics(ComSafeArrayAsInParam(affectedMetrics));
488 if (!affectedMetrics.size())
489 return RTEXITCODE_FAILURE;
490
491 if (isDetached)
492 {
493 RTMsgWarning(Metrics::tr("The background process holding collected metrics will shutdown\n"
494 "in few seconds, discarding all collected data and parameters."));
495 return RTEXITCODE_SUCCESS;
496 }
497
498#ifdef RT_OS_WINDOWS
499 SetConsoleCtrlHandler(ctrlHandler, true);
500#endif /* RT_OS_WINDOWS */
501
502 RTPrintf(Metrics::tr("Time stamp Object Metric Value\n"));
503
504 while (g_fKeepGoing)
505 {
506 RTPrintf("------------ ---------- -------------------- --------------------\n");
507 RTThreadSleep(period * 1000); // Sleep for 'period' seconds
508 char ts[15];
509
510 getTimestamp(ts, sizeof(ts));
511 com::SafeArray<BSTR> retNames;
512 com::SafeIfaceArray<IUnknown> retObjects;
513 com::SafeArray<BSTR> retUnits;
514 com::SafeArray<ULONG> retScales;
515 com::SafeArray<ULONG> retSequenceNumbers;
516 com::SafeArray<ULONG> retIndices;
517 com::SafeArray<ULONG> retLengths;
518 com::SafeArray<LONG> retData;
519 CHECK_ERROR(performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
520 ComSafeArrayAsInParam(objects),
521 ComSafeArrayAsOutParam(retNames),
522 ComSafeArrayAsOutParam(retObjects),
523 ComSafeArrayAsOutParam(retUnits),
524 ComSafeArrayAsOutParam(retScales),
525 ComSafeArrayAsOutParam(retSequenceNumbers),
526 ComSafeArrayAsOutParam(retIndices),
527 ComSafeArrayAsOutParam(retLengths),
528 ComSafeArrayAsOutParam(retData)) );
529 for (unsigned j = 0; j < retNames.size(); j++)
530 {
531 Bstr metricUnit(retUnits[j]);
532 Bstr metricName(retNames[j]);
533 RTPrintf("%-12s %-10ls %-20ls ", ts, getObjectName(retObjects[j]).raw(), metricName.raw());
534 const char *separator = "";
535 for (unsigned k = 0; k < retLengths[j]; k++)
536 {
537 if (retScales[j] == 1)
538 RTPrintf("%s%d %ls", separator, retData[retIndices[j] + k], metricUnit.raw());
539 else
540 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[j] + k] / retScales[j],
541 (retData[retIndices[j] + k] * 100 / retScales[j]) % 100, metricUnit.raw());
542 separator = ", ";
543 }
544 RTPrintf("\n");
545 }
546 RTStrmFlush(g_pStdOut);
547 }
548
549#ifdef RT_OS_WINDOWS
550 SetConsoleCtrlHandler(ctrlHandler, false);
551#endif /* RT_OS_WINDOWS */
552
553 return RTEXITCODE_SUCCESS;
554}
555
556/**
557 * Enable metrics
558 */
559static RTEXITCODE handleMetricsEnable(int argc, char *argv[],
560 ComPtr<IVirtualBox> aVirtualBox,
561 ComPtr<IPerformanceCollector> performanceCollector)
562{
563 HRESULT hrc;
564 com::SafeArray<BSTR> metrics;
565 com::SafeIfaceArray<IUnknown> objects;
566 bool listMatches = false;
567 int i;
568
569 setCurrentSubcommand(HELP_SCOPE_METRICS_ENABLE);
570
571 for (i = 1; i < argc; i++)
572 {
573 if ( !strcmp(argv[i], "--list")
574 || !strcmp(argv[i], "-list"))
575 listMatches = true;
576 else
577 break; /* The rest of params should define the filter */
578 }
579
580 hrc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
581 ComSafeArrayAsOutParam(metrics),
582 ComSafeArrayAsOutParam(objects));
583 if (FAILED(hrc))
584 return RTEXITCODE_FAILURE;
585
586 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
587 CHECK_ERROR(performanceCollector,
588 EnableMetrics(ComSafeArrayAsInParam(metrics),
589 ComSafeArrayAsInParam(objects),
590 ComSafeArrayAsOutParam(affectedMetrics)));
591 if (FAILED(hrc))
592 return RTEXITCODE_SYNTAX; /** @todo figure out why we must return 2 here. */
593
594 if (listMatches)
595 listAffectedMetrics(ComSafeArrayAsInParam(affectedMetrics));
596
597 return RTEXITCODE_SUCCESS;
598}
599
600/**
601 * Disable metrics
602 */
603static RTEXITCODE handleMetricsDisable(int argc, char *argv[],
604 ComPtr<IVirtualBox> aVirtualBox,
605 ComPtr<IPerformanceCollector> performanceCollector)
606{
607 HRESULT hrc;
608 com::SafeArray<BSTR> metrics;
609 com::SafeIfaceArray<IUnknown> objects;
610 bool listMatches = false;
611 int i;
612
613 setCurrentSubcommand(HELP_SCOPE_METRICS_DISABLE);
614
615 for (i = 1; i < argc; i++)
616 {
617 if ( !strcmp(argv[i], "--list")
618 || !strcmp(argv[i], "-list"))
619 listMatches = true;
620 else
621 break; /* The rest of params should define the filter */
622 }
623
624 hrc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
625 ComSafeArrayAsOutParam(metrics),
626 ComSafeArrayAsOutParam(objects));
627 if (FAILED(hrc))
628 return RTEXITCODE_FAILURE;
629
630 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
631 CHECK_ERROR(performanceCollector,
632 DisableMetrics(ComSafeArrayAsInParam(metrics),
633 ComSafeArrayAsInParam(objects),
634 ComSafeArrayAsOutParam(affectedMetrics)));
635 if (FAILED(hrc))
636 return RTEXITCODE_SYNTAX; /** @todo figure out why we must return 2 here. */
637
638 if (listMatches)
639 listAffectedMetrics(ComSafeArrayAsInParam(affectedMetrics));
640
641 return RTEXITCODE_SUCCESS;
642}
643
644
645RTEXITCODE handleMetrics(HandlerArg *a)
646{
647 /* at least one option: subcommand name */
648 if (a->argc < 1)
649 return errorSyntax(Metrics::tr("Subcommand missing"));
650
651 ComPtr<IPerformanceCollector> performanceCollector;
652 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(PerformanceCollector)(performanceCollector.asOutParam()), RTEXITCODE_FAILURE);
653
654 RTEXITCODE rcExit;
655 if (!strcmp(a->argv[0], "list"))
656 rcExit = handleMetricsList(a->argc, a->argv, a->virtualBox, performanceCollector);
657 else if (!strcmp(a->argv[0], "setup"))
658 rcExit = handleMetricsSetup(a->argc, a->argv, a->virtualBox, performanceCollector);
659 else if (!strcmp(a->argv[0], "query"))
660 rcExit = handleMetricsQuery(a->argc, a->argv, a->virtualBox, performanceCollector);
661 else if (!strcmp(a->argv[0], "collect"))
662 rcExit = handleMetricsCollect(a->argc, a->argv, a->virtualBox, performanceCollector);
663 else if (!strcmp(a->argv[0], "enable"))
664 rcExit = handleMetricsEnable(a->argc, a->argv, a->virtualBox, performanceCollector);
665 else if (!strcmp(a->argv[0], "disable"))
666 rcExit = handleMetricsDisable(a->argc, a->argv, a->virtualBox, performanceCollector);
667 else
668 return errorSyntax(Metrics::tr("Invalid subcommand '%s'"), a->argv[0]);
669
670 return rcExit;
671}
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