diff options
Diffstat (limited to 'src/VBox/Main/src-server/PerformanceImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-server/PerformanceImpl.cpp | 125 |
1 files changed, 114 insertions, 11 deletions
diff --git a/src/VBox/Main/src-server/PerformanceImpl.cpp b/src/VBox/Main/src-server/PerformanceImpl.cpp index 97610bb0f..c8c0a7ebe 100644 --- a/src/VBox/Main/src-server/PerformanceImpl.cpp +++ b/src/VBox/Main/src-server/PerformanceImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: PerformanceImpl.cpp $ */ +/* $Id: PerformanceImpl.cpp 37423 2011-06-12 18:37:56Z vboxsync $ */ /** @file * @@ -17,6 +17,20 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ +/* + * Rules of engagement: + * 1) All performance objects must be destroyed by PerformanceCollector only! + * 2) All public methods of PerformanceCollector must be protected with + * read or write lock. + * 3) samplerCallback only uses the write lock during the third phase + * which pulls data into SubMetric objects. This is where object destruction + * and all list modifications are done. The pre-collection phases are + * run without any locks which is only possible because: + * 4) Public methods of PerformanceCollector as well as pre-collection methods + cannot modify lists or destroy objects, and: + * 5) Pre-collection methods cannot modify metric data. + */ + #include "PerformanceImpl.h" #include "AutoCaller.h" @@ -132,12 +146,13 @@ HRESULT PerformanceCollector::FinalConstruct() { LogFlowThisFunc(("\n")); - return S_OK; + return BaseFinalConstruct(); } void PerformanceCollector::FinalRelease() { LogFlowThisFunc(("\n")); + BaseFinalRelease(); } // public initializer/uninitializer for internal purposes only @@ -157,6 +172,7 @@ HRESULT PerformanceCollector::init() HRESULT rc = S_OK; m.hal = pm::createHAL(); + m.gm = new pm::CollectorGuestManager; /* Let the sampler know it gets a valid collector. */ mMagic = MAGIC; @@ -197,6 +213,24 @@ void PerformanceCollector::uninit() mMagic = 0; + /* Destroy unregistered metrics */ + BaseMetricList::iterator it; + for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();) + if ((*it)->isUnregistered()) + { + delete *it; + it = m.baseMetrics.erase(it); + } + else + ++it; + Assert(m.baseMetrics.size() == 0); + /* + * Now when we have destroyed all base metrics that could + * try to pull data from unregistered CollectorGuest objects + * it is safe to destroy them as well. + */ + m.gm->destroyUnregistered(); + /* Destroy resource usage sampler */ int vrc = RTTimerLRDestroy (m.sampler); AssertMsgRC (vrc, ("Failed to destroy resource usage " @@ -206,6 +240,8 @@ void PerformanceCollector::uninit() //delete m.factory; //m.factory = NULL; + delete m.gm; + m.gm = NULL; delete m.hal; m.hal = NULL; @@ -472,6 +508,7 @@ STDMETHODIMP PerformanceCollector::QueryMetricsData(ComSafeArrayIn (IN_BSTR, met LogFlow (("PerformanceCollector::QueryMetricsData() querying metric %s " "returned %d values.\n", (*it)->getName(), length)); memcpy(retData.raw() + flatIndex, values, length * sizeof(*values)); + RTMemFree(values); Bstr tmp((*it)->getName()); tmp.detachTo(&retNames[i]); (*it)->getObject().queryInterfaceTo(&retObjects[i]); @@ -529,17 +566,16 @@ void PerformanceCollector::unregisterBaseMetricsFor(const ComPtr<IUnknown> &aObj if (!SUCCEEDED(autoCaller.rc())) return; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size())); + int n = 0; BaseMetricList::iterator it; - for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();) + for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it) if ((*it)->associatedWith(aObject)) { - delete *it; - it = m.baseMetrics.erase(it); + (*it)->unregister(); + ++n; } - else - ++it; - LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size())); + LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p, marked %d metrics\n", + this, __PRETTY_FUNCTION__, (void *)aObject, n)); //LogFlowThisFuncLeave(); } @@ -563,6 +599,24 @@ void PerformanceCollector::unregisterMetricsFor(const ComPtr<IUnknown> &aObject) //LogFlowThisFuncLeave(); } +void PerformanceCollector::registerGuest(pm::CollectorGuest* pGuest) +{ + AutoCaller autoCaller(this); + if (!SUCCEEDED(autoCaller.rc())) return; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + m.gm->registerGuest(pGuest); +} + +void PerformanceCollector::unregisterGuest(pm::CollectorGuest* pGuest) +{ + AutoCaller autoCaller(this); + if (!SUCCEEDED(autoCaller.rc())) return; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + m.gm->unregisterGuest(pGuest); +} + void PerformanceCollector::suspendSampling() { AutoCaller autoCaller(this); @@ -598,10 +652,26 @@ void PerformanceCollector::staticSamplerCallback(RTTIMERLR hTimerLR, void *pvUse NOREF (hTimerLR); } +/* + * Metrics collection is a three stage process: + * 1) Pre-collection (hinting) + * At this stage we compose the list of all metrics to be collected + * If any metrics cannot be collected separately or if it is more + * efficient to collect several metric at once, these metrics should + * use hints to mark that they will need to be collected. + * 2) Pre-collection (bulk) + * Using hints set at stage 1 platform-specific HAL + * instance collects all marked host-related metrics. + * Hinted guest-related metrics then get collected by CollectorGuestManager. + * 3) Collection + * Metrics that are collected individually get collected and stored. Values + * saved in HAL and CollectorGuestManager are extracted and stored to + * individual metrics. + */ void PerformanceCollector::samplerCallback(uint64_t iTick) { Log4(("{%p} " LOG_FN_FMT ": ENTER\n", this, __PRETTY_FUNCTION__)); - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + /* No locking until stage 3!*/ pm::CollectorHints hints; uint64_t timestamp = RTTimeMilliTS(); @@ -616,10 +686,41 @@ void PerformanceCollector::samplerCallback(uint64_t iTick) } if (toBeCollected.size() == 0) + { + Log4(("{%p} " LOG_FN_FMT ": LEAVE (nothing to collect)\n", this, __PRETTY_FUNCTION__)); return; + } /* Let know the platform specific code what is being collected */ m.hal->preCollect(hints, iTick); + /* Collect the data in bulk from all hinted guests */ + m.gm->preCollect(hints, iTick); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + /* + * Before we can collect data we need to go through both lists + * again to see if any base metrics are marked as unregistered. + * Those should be destroyed now. + */ + LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: toBeCollected.size()=%d\n", this, __PRETTY_FUNCTION__, toBeCollected.size())); + toBeCollected.remove_if(std::mem_fun(&pm::BaseMetric::isUnregistered)); + LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: toBeCollected.size()=%d\n", this, __PRETTY_FUNCTION__, toBeCollected.size())); + LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size())); + for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();) + if ((*it)->isUnregistered()) + { + delete *it; + it = m.baseMetrics.erase(it); + } + else + ++it; + LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size())); + /* + * Now when we have destroyed all base metrics that could + * try to pull data from unregistered CollectorGuest objects + * it is safe to destroy them as well. + */ + m.gm->destroyUnregistered(); /* Finally, collect the data */ std::for_each (toBeCollected.begin(), toBeCollected.end(), @@ -646,7 +747,7 @@ HRESULT PerformanceMetric::FinalConstruct() { LogFlowThisFunc(("\n")); - return S_OK; + return BaseFinalConstruct(); } void PerformanceMetric::FinalRelease() @@ -654,6 +755,8 @@ void PerformanceMetric::FinalRelease() LogFlowThisFunc(("\n")); uninit (); + + BaseFinalRelease(); } // public initializer/uninitializer for internal purposes only |