summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server/Performance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/Performance.cpp')
-rw-r--r--src/VBox/Main/src-server/Performance.cpp308
1 files changed, 207 insertions, 101 deletions
diff --git a/src/VBox/Main/src-server/Performance.cpp b/src/VBox/Main/src-server/Performance.cpp
index 2c6beef7b..298fdc11d 100644
--- a/src/VBox/Main/src-server/Performance.cpp
+++ b/src/VBox/Main/src-server/Performance.cpp
@@ -1,7 +1,5 @@
-/* $Id: Performance.cpp $ */
-
+/* $Id: Performance.cpp 36839 2011-04-25 17:29:21Z vboxsync $ */
/** @file
- *
* VBox Performance Classes implementation.
*/
@@ -75,16 +73,6 @@ int CollectorHAL::getProcessMemoryUsage(RTPROCESS /* process */, ULONG * /* used
return E_NOTIMPL;
}
-int CollectorHAL::enable()
-{
- return E_NOTIMPL;
-}
-
-int CollectorHAL::disable()
-{
- return E_NOTIMPL;
-}
-
/* Generic implementations */
int CollectorHAL::getHostCpuMHz(ULONG *mhz)
@@ -120,28 +108,27 @@ int CollectorHAL::getHostCpuMHz(ULONG *mhz)
#ifndef VBOX_COLLECTOR_TEST_CASE
-uint32_t CollectorGuestHAL::cVMsEnabled = 0;
-
-CollectorGuestHAL::CollectorGuestHAL(Machine *machine, CollectorHAL *hostHAL)
- : CollectorHAL(), cEnabled(0), mMachine(machine), mConsole(NULL),
- mGuest(NULL), mLastTick(0), mHostHAL(hostHAL), mCpuUser(0),
- mCpuKernel(0), mCpuIdle(0), mMemTotal(0), mMemFree(0),
- mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0)
+CollectorGuest::CollectorGuest(Machine *machine, RTPROCESS process) :
+ mUnregistered(false), mEnabled(false), mValid(false), mMachine(machine), mProcess(process),
+ mCpuUser(0), mCpuKernel(0), mCpuIdle(0),
+ mMemTotal(0), mMemFree(0), mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0),
+ mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0)
{
Assert(mMachine);
/* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
mMachine->AddRef();
}
-CollectorGuestHAL::~CollectorGuestHAL()
+CollectorGuest::~CollectorGuest()
{
/* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
mMachine->Release();
- Assert(!cEnabled);
+ // Assert(!cEnabled); why?
}
-int CollectorGuestHAL::enable()
+int CollectorGuest::enable()
{
+ mEnabled = true;
/* Must make sure that the machine object does not get uninitialized
* in the middle of enabling this collector. Causes timing-related
* behavior otherwise, which we don't want. In particular the
@@ -153,59 +140,169 @@ int CollectorGuestHAL::enable()
HRESULT ret = S_OK;
- if (ASMAtomicIncU32(&cEnabled) == 1)
- {
- ASMAtomicIncU32(&cVMsEnabled);
- ComPtr<IInternalSessionControl> directControl;
+ ComPtr<IInternalSessionControl> directControl;
- ret = mMachine->getDirectControl(&directControl);
- if (ret != S_OK)
- return ret;
+ ret = mMachine->getDirectControl(&directControl);
+ if (ret != S_OK)
+ return ret;
- /* get the associated console; this is a remote call (!) */
- ret = directControl->GetRemoteConsole(mConsole.asOutParam());
- if (ret != S_OK)
- return ret;
+ /* get the associated console; this is a remote call (!) */
+ ret = directControl->GetRemoteConsole(mConsole.asOutParam());
+ if (ret != S_OK)
+ return ret;
- ret = mConsole->COMGETTER(Guest)(mGuest.asOutParam());
- if (ret == S_OK)
- mGuest->COMSETTER(StatisticsUpdateInterval)(1 /* 1 sec */);
+ ret = mConsole->COMGETTER(Guest)(mGuest.asOutParam());
+ if (ret == S_OK)
+ {
+ ret = mGuest->COMSETTER(StatisticsUpdateInterval)(1 /* 1 sec */);
+ LogAleksey(("{%p} " LOG_FN_FMT ": Set guest statistics update interval to 1 sec (%s)\n",
+ this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed"));
}
+
return ret;
}
-int CollectorGuestHAL::disable()
+int CollectorGuest::disable()
+{
+ mEnabled = false;
+ Assert(mGuest && mConsole);
+ HRESULT ret = mGuest->COMSETTER(StatisticsUpdateInterval)(0 /* off */);
+ NOREF(ret);
+ LogAleksey(("{%p} " LOG_FN_FMT ": Set guest statistics update interval to 0 sec (%s)\n",
+ this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed"));
+ invalidateStats();
+
+ return S_OK;
+}
+
+int CollectorGuest::updateStats()
{
- if (ASMAtomicDecU32(&cEnabled) == 0)
+ if (mGuest)
{
- if (ASMAtomicDecU32(&cVMsEnabled) == 0)
+ HRESULT rc;
+ rc = mGuest->InternalGetStatistics(&mCpuUser, &mCpuKernel, &mCpuIdle,
+ &mMemTotal, &mMemFree, &mMemBalloon, &mMemShared, &mMemCache,
+ &mPageTotal, &mAllocVMM, &mFreeVMM, &mBalloonedVMM, &mSharedVMM);
+ if (SUCCEEDED(rc))
{
- if (mHostHAL)
- mHostHAL->setMemHypervisorStats(0 /* ulMemAllocTotal */, 0 /* ulMemFreeTotal */, 0 /* ulMemBalloonTotal */, 0 /* ulMemSharedTotal */);
+ mValid = true;
}
- Assert(mGuest && mConsole);
- mGuest->COMSETTER(StatisticsUpdateInterval)(0 /* off */);
+ LogAleksey(("{%p} " LOG_FN_FMT ": mValid=%s mCpuUser=%u mCpuKernel=%u mCpuIdle=%u\n"
+ "mMemTotal=%u mMemFree=%u mMemBalloon=%u mMemShared=%u mMemCache=%u\n"
+ "mPageTotal=%u mAllocVMM=%u mFreeVMM=%u mBalloonedVMM=%u mSharedVMM=%u\n",
+ this, __PRETTY_FUNCTION__, mValid?"y":"n",
+ mCpuUser, mCpuKernel, mCpuIdle,
+ mMemTotal, mMemFree, mMemBalloon, mMemShared, mMemCache,
+ mPageTotal, mAllocVMM, mFreeVMM, mBalloonedVMM, mSharedVMM));
}
+
return S_OK;
}
-int CollectorGuestHAL::preCollect(const CollectorHints& /* hints */, uint64_t iTick)
+void CollectorGuestManager::preCollect(CollectorHints& hints, uint64_t /* iTick */)
{
- if ( mGuest
- && iTick != mLastTick)
+ /*
+ * Since we are running without a lock the value of mVMMStatsProvider
+ * can change at any moment. In the worst case we won't collect any data.
+ */
+ CollectorGuestList::iterator it;
+
+ LogAleksey(("{%p} " LOG_FN_FMT ": provider=%p ramvmm=%s\n",
+ this, __PRETTY_FUNCTION__, mVMMStatsProvider, hints.isHostRamVmmCollected()?"y":"n"));
+ for (it = mGuests.begin(); it != mGuests.end(); it++)
{
- ULONG ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal;
+ LogAleksey(("{%p} " LOG_FN_FMT ": it=%p pid=%d gueststats=%s...\n",
+ this, __PRETTY_FUNCTION__, *it, (*it)->getProcess(),
+ hints.isGuestStatsCollected((*it)->getProcess())?"y":"n"));
+ if ((*it)->isUnregistered())
+ continue;
+ if ( (hints.isHostRamVmmCollected() && *it == mVMMStatsProvider)
+ || hints.isGuestStatsCollected((*it)->getProcess()))
+ {
+ /* Guest stats collection needs to be enabled */
+ if ((*it)->isEnabled())
+ {
+ /* Already enabled, collect the data */
+ (*it)->updateStats();
+ }
+ else
+ {
+ (*it)->invalidateStats();
+ (*it)->enable();
+ }
+ }
+ else
+ {
+ /* Guest stats collection needs to be disabled */
+ if ((*it)->isEnabled())
+ (*it)->disable();
+ }
+ }
+}
+
+void CollectorGuestManager::registerGuest(CollectorGuest* pGuest)
+{
+ mGuests.push_back(pGuest);
+ /*
+ * If no VMM stats provider was elected previously than this is our
+ * candidate.
+ */
+ if (!mVMMStatsProvider)
+ mVMMStatsProvider = pGuest;
+ LogAleksey(("{%p} " LOG_FN_FMT ": Registered guest=%p provider=%p\n",
+ this, __PRETTY_FUNCTION__, pGuest, mVMMStatsProvider));
+}
- mGuest->InternalGetStatistics(&mCpuUser, &mCpuKernel, &mCpuIdle,
- &mMemTotal, &mMemFree, &mMemBalloon, &mMemShared, &mMemCache,
- &mPageTotal, &ulMemAllocTotal, &ulMemFreeTotal, &ulMemBalloonTotal, &ulMemSharedTotal);
+void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest)
+{
+ LogAleksey(("{%p} " LOG_FN_FMT ": About to unregister guest=%p provider=%p\n",
+ this, __PRETTY_FUNCTION__, pGuest, mVMMStatsProvider));
+ //mGuests.remove(pGuest); => destroyUnregistered()
+ pGuest->unregister();
+ if (pGuest == mVMMStatsProvider)
+ {
+ /* This was our VMM stats provider, it is time to re-elect */
+ CollectorGuestList::iterator it;
+ /* Assume that nobody can provide VMM stats */
+ mVMMStatsProvider = NULL;
- if (mHostHAL)
- mHostHAL->setMemHypervisorStats(ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal);
+ for (it = mGuests.begin(); it != mGuests.end(); it++)
+ {
+ /* Skip unregistered as they are about to be destroyed */
+ if ((*it)->isUnregistered())
+ continue;
- mLastTick = iTick;
+ if ((*it)->isEnabled())
+ {
+ /* Found the guest already collecting stats, elect it */
+ mVMMStatsProvider = *it;
+ break;
+ }
+ else if (!mVMMStatsProvider)
+ {
+ /* If nobody collects stats, take the first registered */
+ mVMMStatsProvider = *it;
+ }
+ }
}
- return S_OK;
+ LogAleksey(("{%p} " LOG_FN_FMT ": LEAVE new provider=%p\n",
+ this, __PRETTY_FUNCTION__, mVMMStatsProvider));
+}
+
+void CollectorGuestManager::destroyUnregistered()
+{
+ CollectorGuestList::iterator it;
+
+ for (it = mGuests.begin(); it != mGuests.end();)
+ if ((*it)->isUnregistered())
+ {
+ delete *it;
+ it = mGuests.erase(it);
+ LogAleksey(("{%p} " LOG_FN_FMT ": Number of guests after erasing unregistered is %d\n",
+ this, __PRETTY_FUNCTION__, mGuests.size()));
+ }
+ else
+ ++it;
}
#endif /* !VBOX_COLLECTOR_TEST_CASE */
@@ -225,12 +322,6 @@ bool BaseMetric::collectorBeat(uint64_t nowAt)
return false;
}
-/*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
-{
- LogFlowThisFunc(("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
- return mObject == object;
-}*/
-
void HostCpuLoad::init(ULONG period, ULONG length)
{
mPeriod = period;
@@ -346,25 +437,40 @@ void HostRamVmm::init(ULONG period, ULONG length)
void HostRamVmm::preCollect(CollectorHints& hints, uint64_t /* iTick */)
{
- /*
- * This is an ugly ugly hack to force VMM metrics to 0s if no VM is
- * running. The reason it should work is that the VMM stats are
- * stored in CollectorHAL in preCollect methods of guest base metrics
- * which are always added after HostRamVmm. So each pass of collector
- * first clears the metrics then gets new values.
- */
- mHAL->setMemHypervisorStats(0 /* ulMemAllocTotal */, 0 /* ulMemFreeTotal */, 0 /* ulMemBalloonTotal */, 0 /* ulMemSharedTotal */);
+ hints.collectHostRamVmm();
}
void HostRamVmm::collect()
{
- ULONG allocVMM, freeVMM, balloonVMM, sharedVMM;
-
- mHAL->getMemHypervisorStats(&allocVMM, &freeVMM, &balloonVMM, &sharedVMM);
- mAllocVMM->put(allocVMM);
- mFreeVMM->put(freeVMM);
- mBalloonVMM->put(balloonVMM);
- mSharedVMM->put(sharedVMM);
+ CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
+ if (provider)
+ {
+ LogAleksey(("{%p} " LOG_FN_FMT ": provider=%p enabled=%s valid=%s...\n",
+ this, __PRETTY_FUNCTION__, provider, provider->isEnabled()?"y":"n",
+ provider->isValid()?"y":"n"));
+ if (provider->isValid())
+ {
+ /* Provider is ready, get updated stats */
+ mAllocCurrent = provider->getAllocVMM();
+ mFreeCurrent = provider->getFreeVMM();
+ mBalloonedCurrent = provider->getBalloonedVMM();
+ mSharedCurrent = provider->getSharedVMM();
+ }
+ }
+ else
+ {
+ mAllocCurrent = 0;
+ mFreeCurrent = 0;
+ mBalloonedCurrent = 0;
+ mSharedCurrent = 0;
+ }
+ LogAleksey(("{%p} " LOG_FN_FMT ": mAllocCurrent=%u mFreeCurrent=%u mBalloonedCurrent=%u mSharedCurrent=%u\n",
+ this, __PRETTY_FUNCTION__,
+ mAllocCurrent, mFreeCurrent, mBalloonedCurrent, mSharedCurrent));
+ mAllocVMM->put(mAllocCurrent);
+ mFreeVMM->put(mFreeCurrent);
+ mBalloonVMM->put(mBalloonedCurrent);
+ mSharedVMM->put(mSharedCurrent);
}
@@ -449,19 +555,19 @@ void GuestCpuLoad::init(ULONG period, ULONG length)
mIdle->init(mLength);
}
-void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t iTick)
+void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t /* iTick */)
{
- mHAL->preCollect(hints, iTick);
+ hints.collectGuestStats(mCGuest->getProcess());
}
void GuestCpuLoad::collect()
{
- ULONG CpuUser = 0, CpuKernel = 0, CpuIdle = 0;
-
- mGuestHAL->getGuestCpuLoad(&CpuUser, &CpuKernel, &CpuIdle);
- mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuUser) / 100);
- mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuKernel) / 100);
- mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuIdle) / 100);
+ if (mCGuest->isValid())
+ {
+ mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuUser()) / 100);
+ mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuKernel()) / 100);
+ mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuIdle()) / 100);
+ }
}
void GuestRamUsage::init(ULONG period, ULONG length)
@@ -477,22 +583,22 @@ void GuestRamUsage::init(ULONG period, ULONG length)
mPagedTotal->init(mLength);
}
-void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t iTick)
+void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
{
- mHAL->preCollect(hints, iTick);
+ hints.collectGuestStats(mCGuest->getProcess());
}
void GuestRamUsage::collect()
{
- ULONG ulMemTotal = 0, ulMemFree = 0, ulMemBalloon = 0, ulMemShared = 0, ulMemCache = 0, ulPageTotal = 0;
-
- mGuestHAL->getGuestMemLoad(&ulMemTotal, &ulMemFree, &ulMemBalloon, &ulMemShared, &ulMemCache, &ulPageTotal);
- mTotal->put(ulMemTotal);
- mFree->put(ulMemFree);
- mBallooned->put(ulMemBalloon);
- mShared->put(ulMemShared);
- mCache->put(ulMemCache);
- mPagedTotal->put(ulPageTotal);
+ if (mCGuest->isValid())
+ {
+ mTotal->put(mCGuest->getMemTotal());
+ mFree->put(mCGuest->getMemFree());
+ mBallooned->put(mCGuest->getMemBalloon());
+ mShared->put(mCGuest->getMemShared());
+ mCache->put(mCGuest->getMemCache());
+ mPagedTotal->put(mCGuest->getPageTotal());
+ }
}
void CircularBuffer::init(ULONG ulLength)
@@ -708,10 +814,10 @@ void Filter::processMetricList(const com::Utf8Str &name, const ComPtr<IUnknown>
pos != com::Utf8Str::npos;
pos = name.find(",", startPos))
{
- mElements.push_back(std::make_pair(object, iprt::MiniString(name.substr(startPos, pos - startPos).c_str())));
+ mElements.push_back(std::make_pair(object, RTCString(name.substr(startPos, pos - startPos).c_str())));
startPos = pos + 1;
}
- mElements.push_back(std::make_pair(object, iprt::MiniString(name.substr(startPos).c_str())));
+ mElements.push_back(std::make_pair(object, RTCString(name.substr(startPos).c_str())));
}
/**
@@ -787,14 +893,14 @@ bool Filter::patternMatch(const char *pszPat, const char *pszName,
return true;
}
-bool Filter::match(const ComPtr<IUnknown> object, const iprt::MiniString &name) const
+bool Filter::match(const ComPtr<IUnknown> object, const RTCString &name) const
{
ElementList::const_iterator it;
- LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
+ //LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
for (it = mElements.begin(); it != mElements.end(); it++)
{
- LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
+ //LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
if ((*it).first.isNull() || (*it).first == object)
{
// Objects match, compare names
@@ -805,7 +911,7 @@ bool Filter::match(const ComPtr<IUnknown> object, const iprt::MiniString &name)
}
}
}
- LogAleksey(("...no matches!\n"));
+ //LogAleksey(("...no matches!\n"));
return false;
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */