Index: trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp
===================================================================
--- trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp	(revision 11379)
+++ trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp	(revision 11384)
@@ -654,4 +654,12 @@
 #endif /* VBOX_WITH_GUEST_PROPS defined */
 
+    if (u64Cmd & USAGE_METRICS)
+    {
+        RTPrintf("VBoxManage metrics          list [*|host|<vmname> [metric1[,metric2[,...]]]]\n"
+                 "                            setup <period> <count> [*|host|<vmname> [metric1[,metric2[,...]]]]\n"
+                 "                            query [*|host|<vmname> [metric1[,metric2[,...]]]]\n"
+                 "\n");
+    }
+
 }
 
@@ -7579,4 +7587,224 @@
 }
 
+static int parseFilterParameters(int argc, char *argv[],
+                                 ComPtr<IVirtualBox> aVirtualBox,
+                                 ComSafeArrayOut(BSTR, outMetrics),
+                                 ComSafeArrayOut(IUnknown *, outObjects))
+{
+    HRESULT rc = S_OK;
+    com::SafeArray<BSTR> retMetrics(1);
+    com::SafeIfaceArray <IUnknown> retObjects;
+
+    Bstr metricNames;
+
+    /* Metric list */
+    if (argc > 1)
+        metricNames = argv[1];
+    else
+        metricNames = L"*";
+    metricNames.cloneTo(&retMetrics[0]);
+
+    /* Object name */
+    if (argc > 0 && strcmp(argv[0], "*"))
+    {
+        if (!strcmp(argv[0], "host"))
+        {
+            ComPtr<IHost> host;
+            CHECK_ERROR(aVirtualBox, COMGETTER(Host)(host.asOutParam()));
+            retObjects.reset(1);
+            host.queryInterfaceTo(&retObjects[0]);
+        }
+        else
+        {
+            ComPtr <IMachine> machine;
+            rc = aVirtualBox->FindMachine(Bstr(argv[0]), machine.asOutParam());
+            if (SUCCEEDED (rc))
+            {
+                retObjects.reset(1);
+                machine.queryInterfaceTo(&retObjects[0]);
+            }
+            else
+            {
+                errorArgument("Invalid machine name: '%s'", argv[0]);
+                return rc;
+            }
+        }
+
+    }
+
+    retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
+    retObjects.detachTo(ComSafeArrayOutArg(outObjects));
+
+    return rc;
+}
+
+static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
+                                  ComPtr<IUnknown> aObject)
+{
+    HRESULT rc;
+
+    ComPtr<IHost> host = aObject;
+    if (!host.isNull())
+        return Bstr("host");
+
+    ComPtr<IMachine> machine = aObject;
+    if (!machine.isNull())
+    {
+        Bstr name;
+        CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
+        if (SUCCEEDED(rc))
+            return name;
+    }
+    return Bstr("unknown");
+}
+
+static int handleMetrics(int argc, char *argv[],
+                         ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
+{
+    HRESULT rc;
+    com::SafeArray<BSTR>          metrics;
+    com::SafeIfaceArray<IUnknown> objects;
+
+    /* at least one option: sub-command name */
+    if (argc < 1)
+        return errorSyntax(USAGE_METRICS, "Sub-command missing");
+
+    ComPtr<IPerformanceCollector> performanceCollector;
+    CHECK_ERROR(aVirtualBox, COMGETTER(PerformanceCollector)(performanceCollector.asOutParam()));
+
+    if (!strcmp(argv[0], "list"))
+    {
+        /*********************************************************************
+        * list                                                               *
+        *********************************************************************/
+        rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
+                                   ComSafeArrayAsOutParam(metrics),
+                                   ComSafeArrayAsOutParam(objects));
+        if (FAILED(rc))
+            return 1;
+
+        com::SafeIfaceArray<IPerformanceMetric> metricInfo;
+
+        CHECK_ERROR(performanceCollector,
+            GetMetrics(ComSafeArrayAsInParam(metrics),
+                       ComSafeArrayAsInParam(objects),
+                       ComSafeArrayAsOutParam(metricInfo)));
+
+        ComPtr<IUnknown> object;
+        Bstr metricName, unit;
+        ULONG period, count;
+        LONG minimum, maximum;
+        RTPrintf("Object     Metric               Unit Minimum    Maximum    Period     Count\n"
+                 "---------- -------------------- ---- ---------- ---------- ---------- ----------\n");
+        for (size_t i = 0; i < metricInfo.size(); i++)
+        {
+            CHECK_ERROR(metricInfo[i], COMGETTER(Object)(object.asOutParam()));
+            CHECK_ERROR(metricInfo[i], COMGETTER(MetricName)(metricName.asOutParam()));
+            CHECK_ERROR(metricInfo[i], COMGETTER(Period)(&period));
+            CHECK_ERROR(metricInfo[i], COMGETTER(Count)(&count));
+            CHECK_ERROR(metricInfo[i], COMGETTER(MinimumValue)(&minimum));
+            CHECK_ERROR(metricInfo[i], COMGETTER(MaximumValue)(&maximum));
+            CHECK_ERROR(metricInfo[i], COMGETTER(Unit)(unit.asOutParam()));
+            RTPrintf("%-10ls %-20ls %-4ls %10d %10d %10u %10u\n",
+                getObjectName(aVirtualBox, object).raw(), metricName.raw(), unit.raw(),
+                minimum, maximum, period, count);
+        }
+    }
+    else if (!strcmp(argv[0], "setup"))
+    {
+        /*********************************************************************
+        * setup                                                              *
+        *********************************************************************/
+        if (argc < 3)
+            return errorSyntax(USAGE_METRICS, "Missing parameters for '%s' subcommand", argv[0]);
+
+        ULONG period, count;
+        char *endptr = NULL;
+
+        period = strtoul (argv[1], &endptr, 10);
+        if (!endptr || *endptr)
+            return errorArgument("Invalid value for 'period' parameter: '%s'", argv[1]);
+
+        count = strtoul (argv[2], &endptr, 10);
+        if (!endptr || *endptr)
+            return errorArgument("Invalid value for 'count' parameter: '%s'", argv[2]);
+
+        rc = parseFilterParameters(argc - 3, &argv[3], aVirtualBox,
+                                   ComSafeArrayAsOutParam(metrics),
+                                   ComSafeArrayAsOutParam(objects));
+        if (FAILED(rc))
+            return 1;
+
+        CHECK_ERROR(performanceCollector,
+            SetupMetrics(ComSafeArrayAsInParam(metrics),
+                         ComSafeArrayAsInParam(objects), period, count));
+    }
+    else if (!strcmp(argv[0], "query"))
+    {
+        /*********************************************************************
+        * query                                                              *
+        *********************************************************************/
+        rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
+                                   ComSafeArrayAsOutParam(metrics),
+                                   ComSafeArrayAsOutParam(objects));
+        if (FAILED(rc))
+            return 1;
+
+        com::SafeArray<BSTR>          retNames;
+        com::SafeIfaceArray<IUnknown> retObjects;
+        com::SafeArray<ULONG>         retIndices;
+        com::SafeArray<ULONG>         retLengths;
+        com::SafeArray<LONG>          retData;
+        CHECK_ERROR (performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
+                                                 ComSafeArrayAsInParam(objects),
+                                                 ComSafeArrayAsOutParam(retNames),
+                                                 ComSafeArrayAsOutParam(retObjects),
+                                                 ComSafeArrayAsOutParam(retIndices),
+                                                 ComSafeArrayAsOutParam(retLengths),
+                                                 ComSafeArrayAsOutParam(retData)) );
+
+        RTPrintf("Object     Metric               Values\n"
+                 "---------- -------------------- --------------------------------------------\n");
+        for (unsigned i = 0; i < retNames.size(); i++)
+        {
+            // Get info for the metric
+            com::SafeArray<BSTR> nameOfMetric(1);
+            Bstr tmpName(retNames[i]);
+            tmpName.detachTo (&nameOfMetric[0]);
+            com::SafeIfaceArray<IUnknown> anObject(1);
+            ComPtr<IUnknown> tmpObject(retObjects[i]);
+            tmpObject.queryInterfaceTo(&anObject[0]);
+            com::SafeIfaceArray <IPerformanceMetric> metricInfo;
+            CHECK_RC_BREAK (performanceCollector->GetMetrics( ComSafeArrayAsInParam(nameOfMetric),
+                                                   ComSafeArrayAsInParam(anObject),
+                                                   ComSafeArrayAsOutParam(metricInfo) ));
+            BSTR metricUnitBSTR;
+            CHECK_RC_BREAK (metricInfo[0]->COMGETTER(Unit) (&metricUnitBSTR));
+            Bstr metricUnit(metricUnitBSTR);
+            Bstr metricName(retNames[i]);
+            LONG minVal, maxVal;
+            CHECK_RC_BREAK (metricInfo[0]->COMGETTER(MinimumValue) (&minVal));
+            CHECK_RC_BREAK (metricInfo[0]->COMGETTER(MaximumValue) (&maxVal));
+            RTPrintf("%-10ls %-20ls ", getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw());
+            const char *separator = "";
+            for (unsigned j = 0; j < retLengths[i]; j++)
+            {
+                if (strcmp((const char *)metricUnit.raw(), "%"))
+                    RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
+                else
+                    RTPrintf("%s%d.%02d%%", separator, retData[retIndices[i] + j] / 1000, retData[retIndices[i] + j] % 100);
+                separator = ", ";
+            }
+            RTPrintf("\n");
+        }
+    }
+    else
+    {
+        return errorSyntax(USAGE_METRICS, "Invalid subcommand '%s'", argv[0]);
+    }
+
+    return SUCCEEDED(rc) ? 0 : 1;
+}
+
 enum ConvertSettings
 {
@@ -7916,4 +8144,5 @@
         { "guestproperty",    handleGuestProperty },
 #endif /* VBOX_WITH_GUEST_PROPS defined */
+        { "metrics",          handleMetrics },
         { NULL,               NULL }
     };
Index: trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
===================================================================
--- trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 11379)
+++ trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 11384)
@@ -74,4 +74,5 @@
 #endif  /* VBOX_WITH_GUEST_PROPS defined */
 #define USAGE_CONVERTTORAW          RT_BIT_64(41)
+#define USAGE_METRICS               RT_BIT_64(42)
 #define USAGE_ALL                   (~(uint64_t)0)
 /** @} */
