1
/* $Id: PerformanceImpl.cpp 35368 2010-12-30 13:38:23Z vboxsync $ */
5
* VBox Performance API COM Classes implementation
9
* Copyright (C) 2008-2010 Oracle Corporation
11
* This file is part of VirtualBox Open Source Edition (OSE), as
12
* available from http://www.virtualbox.org. This file is free software;
13
* you can redistribute it and/or modify it under the terms of the GNU
14
* General Public License (GPL) as published by the Free Software
15
* Foundation, in version 2 as it comes in the "COPYING" file of the
16
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
#include "PerformanceImpl.h"
22
#include "AutoCaller.h"
25
#include <iprt/process.h>
28
#include <VBox/settings.h>
34
#include "Performance.h"
36
static const char *g_papcszMetricNames[] =
43
"CPU/Load/Kernel:avg",
44
"CPU/Load/Kernel:min",
45
"CPU/Load/Kernel:max",
55
"RAM/Usage/Total:avg",
56
"RAM/Usage/Total:min",
57
"RAM/Usage/Total:max",
75
"RAM/VMM/Ballooned:avg",
76
"RAM/VMM/Ballooned:min",
77
"RAM/VMM/Ballooned:max",
82
"Guest/CPU/Load/User",
83
"Guest/CPU/Load/User:avg",
84
"Guest/CPU/Load/User:min",
85
"Guest/CPU/Load/User:max",
86
"Guest/CPU/Load/Kernel",
87
"Guest/CPU/Load/Kernel:avg",
88
"Guest/CPU/Load/Kernel:min",
89
"Guest/CPU/Load/Kernel:max",
90
"Guest/CPU/Load/Idle",
91
"Guest/CPU/Load/Idle:avg",
92
"Guest/CPU/Load/Idle:min",
93
"Guest/CPU/Load/Idle:max",
94
"Guest/RAM/Usage/Total",
95
"Guest/RAM/Usage/Total:avg",
96
"Guest/RAM/Usage/Total:min",
97
"Guest/RAM/Usage/Total:max",
98
"Guest/RAM/Usage/Free",
99
"Guest/RAM/Usage/Free:avg",
100
"Guest/RAM/Usage/Free:min",
101
"Guest/RAM/Usage/Free:max",
102
"Guest/RAM/Usage/Balloon",
103
"Guest/RAM/Usage/Balloon:avg",
104
"Guest/RAM/Usage/Balloon:min",
105
"Guest/RAM/Usage/Balloon:max",
106
"Guest/RAM/Usage/Shared",
107
"Guest/RAM/Usage/Shared:avg",
108
"Guest/RAM/Usage/Shared:min",
109
"Guest/RAM/Usage/Shared:max",
110
"Guest/RAM/Usage/Cache",
111
"Guest/RAM/Usage/Cache:avg",
112
"Guest/RAM/Usage/Cache:min",
113
"Guest/RAM/Usage/Cache:max",
114
"Guest/Pagefile/Usage/Total",
115
"Guest/Pagefile/Usage/Total:avg",
116
"Guest/Pagefile/Usage/Total:min",
117
"Guest/Pagefile/Usage/Total:max",
120
////////////////////////////////////////////////////////////////////////////////
121
// PerformanceCollector class
122
////////////////////////////////////////////////////////////////////////////////
124
// constructor / destructor
125
////////////////////////////////////////////////////////////////////////////////
127
PerformanceCollector::PerformanceCollector() : mMagic(0) {}
129
PerformanceCollector::~PerformanceCollector() {}
131
HRESULT PerformanceCollector::FinalConstruct()
133
LogFlowThisFunc(("\n"));
138
void PerformanceCollector::FinalRelease()
140
LogFlowThisFunc(("\n"));
143
// public initializer/uninitializer for internal purposes only
144
////////////////////////////////////////////////////////////////////////////////
147
* Initializes the PerformanceCollector object.
149
HRESULT PerformanceCollector::init()
151
/* Enclose the state transition NotReady->InInit->Ready */
152
AutoInitSpan autoInitSpan(this);
153
AssertReturn(autoInitSpan.isOk(), E_FAIL);
155
LogFlowThisFuncEnter();
159
m.hal = pm::createHAL();
161
/* Let the sampler know it gets a valid collector. */
164
/* Start resource usage sampler */
165
int vrc = RTTimerLRCreate (&m.sampler, VBOX_USAGE_SAMPLER_MIN_INTERVAL,
166
&PerformanceCollector::staticSamplerCallback, this);
167
AssertMsgRC (vrc, ("Failed to create resource usage "
168
"sampling timer(%Rra)\n", vrc));
173
autoInitSpan.setSucceeded();
175
LogFlowThisFuncLeave();
181
* Uninitializes the PerformanceCollector object.
183
* Called either from FinalRelease() or by the parent when it gets destroyed.
185
void PerformanceCollector::uninit()
187
LogFlowThisFuncEnter();
189
/* Enclose the state transition Ready->InUninit->NotReady */
190
AutoUninitSpan autoUninitSpan(this);
191
if (autoUninitSpan.uninitDone())
193
LogFlowThisFunc(("Already uninitialized.\n"));
194
LogFlowThisFuncLeave();
200
/* Destroy resource usage sampler */
201
int vrc = RTTimerLRDestroy (m.sampler);
202
AssertMsgRC (vrc, ("Failed to destroy resource usage "
203
"sampling timer (%Rra)\n", vrc));
212
LogFlowThisFuncLeave();
215
// IPerformanceCollector properties
216
////////////////////////////////////////////////////////////////////////////////
218
STDMETHODIMP PerformanceCollector::COMGETTER(MetricNames)(ComSafeArrayOut(BSTR, theMetricNames))
220
if (ComSafeArrayOutIsNull(theMetricNames))
223
AutoCaller autoCaller(this);
224
if (FAILED(autoCaller.rc())) return autoCaller.rc();
226
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
228
com::SafeArray<BSTR> metricNames(RT_ELEMENTS(g_papcszMetricNames));
229
for (size_t i = 0; i < RT_ELEMENTS(g_papcszMetricNames); i++)
231
Bstr tmp(g_papcszMetricNames[i]); /* gcc-3.3 cruft */
232
tmp.cloneTo(&metricNames[i]);
234
//gMetricNames.detachTo(ComSafeArrayOutArg(theMetricNames));
235
metricNames.detachTo(ComSafeArrayOutArg(theMetricNames));
240
// IPerformanceCollector methods
241
////////////////////////////////////////////////////////////////////////////////
243
HRESULT PerformanceCollector::toIPerformanceMetric(pm::Metric *src, IPerformanceMetric **dst)
245
ComObjPtr<PerformanceMetric> metric;
246
HRESULT rc = metric.createObject();
248
rc = metric->init (src);
249
AssertComRCReturnRC(rc);
250
metric.queryInterfaceTo(dst);
254
HRESULT PerformanceCollector::toIPerformanceMetric(pm::BaseMetric *src, IPerformanceMetric **dst)
256
ComObjPtr<PerformanceMetric> metric;
257
HRESULT rc = metric.createObject();
259
rc = metric->init (src);
260
AssertComRCReturnRC(rc);
261
metric.queryInterfaceTo(dst);
265
STDMETHODIMP PerformanceCollector::GetMetrics(ComSafeArrayIn(IN_BSTR, metricNames),
266
ComSafeArrayIn(IUnknown *, objects),
267
ComSafeArrayOut(IPerformanceMetric *, outMetrics))
269
LogFlowThisFuncEnter();
270
//LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType));
274
AutoCaller autoCaller(this);
275
if (FAILED(autoCaller.rc())) return autoCaller.rc();
277
pm::Filter filter (ComSafeArrayInArg (metricNames),
278
ComSafeArrayInArg (objects));
280
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
282
MetricList filteredMetrics;
283
MetricList::iterator it;
284
for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
285
if (filter.match ((*it)->getObject(), (*it)->getName()))
286
filteredMetrics.push_back (*it);
288
com::SafeIfaceArray<IPerformanceMetric> retMetrics (filteredMetrics.size());
290
for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
292
ComObjPtr<PerformanceMetric> metric;
293
rc = metric.createObject();
295
rc = metric->init (*it);
296
AssertComRCReturnRC(rc);
297
LogFlow (("PerformanceCollector::GetMetrics() store a metric at "
298
"retMetrics[%d]...\n", i));
299
metric.queryInterfaceTo(&retMetrics[i++]);
301
retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
302
LogFlowThisFuncLeave();
306
STDMETHODIMP PerformanceCollector::SetupMetrics(ComSafeArrayIn(IN_BSTR, metricNames),
307
ComSafeArrayIn(IUnknown *, objects),
310
ComSafeArrayOut(IPerformanceMetric *, outMetrics))
312
AutoCaller autoCaller(this);
313
if (FAILED(autoCaller.rc())) return autoCaller.rc();
315
pm::Filter filter(ComSafeArrayInArg (metricNames),
316
ComSafeArrayInArg (objects));
318
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
321
BaseMetricList filteredMetrics;
322
BaseMetricList::iterator it;
323
for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
324
if (filter.match((*it)->getObject(), (*it)->getName()))
326
LogFlow (("PerformanceCollector::SetupMetrics() setting period to %u,"
327
" count to %u for %s\n", aPeriod, aCount, (*it)->getName()));
328
(*it)->init(aPeriod, aCount);
329
if (aPeriod == 0 || aCount == 0)
331
LogFlow (("PerformanceCollector::SetupMetrics() disabling %s\n",
337
LogFlow (("PerformanceCollector::SetupMetrics() enabling %s\n",
341
filteredMetrics.push_back(*it);
344
com::SafeIfaceArray<IPerformanceMetric> retMetrics(filteredMetrics.size());
346
for (it = filteredMetrics.begin();
347
it != filteredMetrics.end() && SUCCEEDED(rc); ++it)
348
rc = toIPerformanceMetric(*it, &retMetrics[i++]);
349
retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
351
LogFlowThisFuncLeave();
355
STDMETHODIMP PerformanceCollector::EnableMetrics(ComSafeArrayIn(IN_BSTR, metricNames),
356
ComSafeArrayIn(IUnknown *, objects),
357
ComSafeArrayOut(IPerformanceMetric *, outMetrics))
359
AutoCaller autoCaller(this);
360
if (FAILED(autoCaller.rc())) return autoCaller.rc();
362
pm::Filter filter(ComSafeArrayInArg(metricNames),
363
ComSafeArrayInArg(objects));
365
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Write lock is not needed atm since we are */
366
/* fiddling with enable bit only, but we */
367
/* care for those who come next :-). */
370
BaseMetricList filteredMetrics;
371
BaseMetricList::iterator it;
372
for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
373
if (filter.match((*it)->getObject(), (*it)->getName()))
376
filteredMetrics.push_back(*it);
379
com::SafeIfaceArray<IPerformanceMetric> retMetrics(filteredMetrics.size());
381
for (it = filteredMetrics.begin();
382
it != filteredMetrics.end() && SUCCEEDED(rc); ++it)
383
rc = toIPerformanceMetric(*it, &retMetrics[i++]);
384
retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
386
LogFlowThisFuncLeave();
390
STDMETHODIMP PerformanceCollector::DisableMetrics(ComSafeArrayIn(IN_BSTR, metricNames),
391
ComSafeArrayIn(IUnknown *, objects),
392
ComSafeArrayOut(IPerformanceMetric *, outMetrics))
394
AutoCaller autoCaller(this);
395
if (FAILED(autoCaller.rc())) return autoCaller.rc();
397
pm::Filter filter(ComSafeArrayInArg(metricNames),
398
ComSafeArrayInArg(objects));
400
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Write lock is not needed atm since we are */
401
/* fiddling with enable bit only, but we */
402
/* care for those who come next :-). */
405
BaseMetricList filteredMetrics;
406
BaseMetricList::iterator it;
407
for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
408
if (filter.match((*it)->getObject(), (*it)->getName()))
411
filteredMetrics.push_back(*it);
414
com::SafeIfaceArray<IPerformanceMetric> retMetrics(filteredMetrics.size());
416
for (it = filteredMetrics.begin();
417
it != filteredMetrics.end() && SUCCEEDED(rc); ++it)
418
rc = toIPerformanceMetric(*it, &retMetrics[i++]);
419
retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
421
LogFlowThisFuncLeave();
425
STDMETHODIMP PerformanceCollector::QueryMetricsData(ComSafeArrayIn (IN_BSTR, metricNames),
426
ComSafeArrayIn (IUnknown *, objects),
427
ComSafeArrayOut(BSTR, outMetricNames),
428
ComSafeArrayOut(IUnknown *, outObjects),
429
ComSafeArrayOut(BSTR, outUnits),
430
ComSafeArrayOut(ULONG, outScales),
431
ComSafeArrayOut(ULONG, outSequenceNumbers),
432
ComSafeArrayOut(ULONG, outDataIndices),
433
ComSafeArrayOut(ULONG, outDataLengths),
434
ComSafeArrayOut(LONG, outData))
436
AutoCaller autoCaller(this);
437
if (FAILED(autoCaller.rc())) return autoCaller.rc();
439
pm::Filter filter(ComSafeArrayInArg(metricNames),
440
ComSafeArrayInArg(objects));
442
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
444
/* Let's compute the size of the resulting flat array */
446
MetricList filteredMetrics;
447
MetricList::iterator it;
448
for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
449
if (filter.match ((*it)->getObject(), (*it)->getName()))
451
filteredMetrics.push_back (*it);
452
flatSize += (*it)->getLength();
456
size_t flatIndex = 0;
457
size_t numberOfMetrics = filteredMetrics.size();
458
com::SafeArray<BSTR> retNames(numberOfMetrics);
459
com::SafeIfaceArray<IUnknown> retObjects(numberOfMetrics);
460
com::SafeArray<BSTR> retUnits(numberOfMetrics);
461
com::SafeArray<ULONG> retScales(numberOfMetrics);
462
com::SafeArray<ULONG> retSequenceNumbers(numberOfMetrics);
463
com::SafeArray<ULONG> retIndices(numberOfMetrics);
464
com::SafeArray<ULONG> retLengths(numberOfMetrics);
465
com::SafeArray<LONG> retData(flatSize);
467
for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it, ++i)
469
ULONG *values, length, sequenceNumber;
470
/* @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
471
(*it)->query(&values, &length, &sequenceNumber);
472
LogFlow (("PerformanceCollector::QueryMetricsData() querying metric %s "
473
"returned %d values.\n", (*it)->getName(), length));
474
memcpy(retData.raw() + flatIndex, values, length * sizeof(*values));
475
Bstr tmp((*it)->getName());
476
tmp.detachTo(&retNames[i]);
477
(*it)->getObject().queryInterfaceTo(&retObjects[i]);
478
tmp = (*it)->getUnit();
479
tmp.detachTo(&retUnits[i]);
480
retScales[i] = (*it)->getScale();
481
retSequenceNumbers[i] = sequenceNumber;
482
retLengths[i] = length;
483
retIndices[i] = (ULONG)flatIndex;
487
retNames.detachTo(ComSafeArrayOutArg(outMetricNames));
488
retObjects.detachTo(ComSafeArrayOutArg(outObjects));
489
retUnits.detachTo(ComSafeArrayOutArg(outUnits));
490
retScales.detachTo(ComSafeArrayOutArg(outScales));
491
retSequenceNumbers.detachTo(ComSafeArrayOutArg(outSequenceNumbers));
492
retIndices.detachTo(ComSafeArrayOutArg(outDataIndices));
493
retLengths.detachTo(ComSafeArrayOutArg(outDataLengths));
494
retData.detachTo(ComSafeArrayOutArg(outData));
498
// public methods for internal purposes
499
///////////////////////////////////////////////////////////////////////////////
501
void PerformanceCollector::registerBaseMetric(pm::BaseMetric *baseMetric)
503
//LogFlowThisFuncEnter();
504
AutoCaller autoCaller(this);
505
if (!SUCCEEDED(autoCaller.rc())) return;
507
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
508
LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)baseMetric->getObject(), baseMetric->getName()));
509
m.baseMetrics.push_back (baseMetric);
510
//LogFlowThisFuncLeave();
513
void PerformanceCollector::registerMetric(pm::Metric *metric)
515
//LogFlowThisFuncEnter();
516
AutoCaller autoCaller(this);
517
if (!SUCCEEDED(autoCaller.rc())) return;
519
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
520
LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)metric->getObject(), metric->getName()));
521
m.metrics.push_back (metric);
522
//LogFlowThisFuncLeave();
525
void PerformanceCollector::unregisterBaseMetricsFor(const ComPtr<IUnknown> &aObject)
527
//LogFlowThisFuncEnter();
528
AutoCaller autoCaller(this);
529
if (!SUCCEEDED(autoCaller.rc())) return;
531
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
532
LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
533
BaseMetricList::iterator it;
534
for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();)
535
if ((*it)->associatedWith(aObject))
538
it = m.baseMetrics.erase(it);
542
LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
543
//LogFlowThisFuncLeave();
546
void PerformanceCollector::unregisterMetricsFor(const ComPtr<IUnknown> &aObject)
548
//LogFlowThisFuncEnter();
549
AutoCaller autoCaller(this);
550
if (!SUCCEEDED(autoCaller.rc())) return;
552
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
553
LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p\n", this, __PRETTY_FUNCTION__, (void *)aObject));
554
MetricList::iterator it;
555
for (it = m.metrics.begin(); it != m.metrics.end();)
556
if ((*it)->associatedWith(aObject))
559
it = m.metrics.erase(it);
563
//LogFlowThisFuncLeave();
566
void PerformanceCollector::suspendSampling()
568
AutoCaller autoCaller(this);
569
if (!SUCCEEDED(autoCaller.rc())) return;
571
int rc = RTTimerLRStop(m.sampler);
575
void PerformanceCollector::resumeSampling()
577
AutoCaller autoCaller(this);
578
if (!SUCCEEDED(autoCaller.rc())) return;
580
int rc = RTTimerLRStart(m.sampler, 0);
586
///////////////////////////////////////////////////////////////////////////////
589
void PerformanceCollector::staticSamplerCallback(RTTIMERLR hTimerLR, void *pvUser,
592
AssertReturnVoid (pvUser != NULL);
593
PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
594
Assert(collector->mMagic == MAGIC);
595
if (collector->mMagic == MAGIC)
596
collector->samplerCallback(iTick);
601
void PerformanceCollector::samplerCallback(uint64_t iTick)
603
Log4(("{%p} " LOG_FN_FMT ": ENTER\n", this, __PRETTY_FUNCTION__));
604
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
606
pm::CollectorHints hints;
607
uint64_t timestamp = RTTimeMilliTS();
608
BaseMetricList toBeCollected;
609
BaseMetricList::iterator it;
610
/* Compose the list of metrics being collected at this moment */
611
for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); it++)
612
if ((*it)->collectorBeat(timestamp))
614
(*it)->preCollect(hints, iTick);
615
toBeCollected.push_back(*it);
618
if (toBeCollected.size() == 0)
621
/* Let know the platform specific code what is being collected */
622
m.hal->preCollect(hints, iTick);
624
/* Finally, collect the data */
625
std::for_each (toBeCollected.begin(), toBeCollected.end(),
626
std::mem_fun (&pm::BaseMetric::collect));
627
Log4(("{%p} " LOG_FN_FMT ": LEAVE\n", this, __PRETTY_FUNCTION__));
630
////////////////////////////////////////////////////////////////////////////////
631
// PerformanceMetric class
632
////////////////////////////////////////////////////////////////////////////////
634
// constructor / destructor
635
////////////////////////////////////////////////////////////////////////////////
637
PerformanceMetric::PerformanceMetric()
641
PerformanceMetric::~PerformanceMetric()
645
HRESULT PerformanceMetric::FinalConstruct()
647
LogFlowThisFunc(("\n"));
652
void PerformanceMetric::FinalRelease()
654
LogFlowThisFunc(("\n"));
659
// public initializer/uninitializer for internal purposes only
660
////////////////////////////////////////////////////////////////////////////////
662
HRESULT PerformanceMetric::init(pm::Metric *aMetric)
664
m.name = aMetric->getName();
665
m.object = aMetric->getObject();
666
m.description = aMetric->getDescription();
667
m.period = aMetric->getPeriod();
668
m.count = aMetric->getLength();
669
m.unit = aMetric->getUnit();
670
m.min = aMetric->getMinValue();
671
m.max = aMetric->getMaxValue();
675
HRESULT PerformanceMetric::init(pm::BaseMetric *aMetric)
677
m.name = aMetric->getName();
678
m.object = aMetric->getObject();
680
m.period = aMetric->getPeriod();
681
m.count = aMetric->getLength();
682
m.unit = aMetric->getUnit();
683
m.min = aMetric->getMinValue();
684
m.max = aMetric->getMaxValue();
688
void PerformanceMetric::uninit()
692
STDMETHODIMP PerformanceMetric::COMGETTER(MetricName)(BSTR *aMetricName)
694
/// @todo (r=dmik) why do all these getters not do AutoCaller and
695
/// AutoReadLock? Is the underlying metric a constant object?
697
m.name.cloneTo(aMetricName);
701
STDMETHODIMP PerformanceMetric::COMGETTER(Object)(IUnknown **anObject)
703
m.object.queryInterfaceTo(anObject);
707
STDMETHODIMP PerformanceMetric::COMGETTER(Description)(BSTR *aDescription)
709
m.description.cloneTo(aDescription);
713
STDMETHODIMP PerformanceMetric::COMGETTER(Period)(ULONG *aPeriod)
719
STDMETHODIMP PerformanceMetric::COMGETTER(Count)(ULONG *aCount)
725
STDMETHODIMP PerformanceMetric::COMGETTER(Unit)(BSTR *aUnit)
727
m.unit.cloneTo(aUnit);
731
STDMETHODIMP PerformanceMetric::COMGETTER(MinimumValue)(LONG *aMinValue)
737
STDMETHODIMP PerformanceMetric::COMGETTER(MaximumValue)(LONG *aMaxValue)
742
/* vi: set tabstop=4 shiftwidth=4 expandtab: */