~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

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