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