VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/Performance.cpp@ 98262

Last change on this file since 98262 was 98262, checked in by vboxsync, 21 months ago

Main: rc() -> hrc()/vrc(). bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.4 KB
RevLine 
[10641]1/* $Id: Performance.cpp 98262 2023-01-24 01:42:14Z vboxsync $ */
2/** @file
3 * VBox Performance Classes implementation.
4 */
5
6/*
[98103]7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
[10641]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[10641]26 */
27
[76592]28/**
[10868]29 * @todo list:
30 *
[11498]31 * 1) Detection of erroneous metric names
[10868]32 */
33
[76592]34#define LOG_GROUP LOG_GROUP_MAIN_PERFORMANCECOLLECTOR
[27885]35#ifndef VBOX_COLLECTOR_TEST_CASE
[76592]36# include "VirtualBoxImpl.h"
37# include "MachineImpl.h"
38# include "MediumImpl.h"
39# include "AutoCaller.h"
[27885]40#endif
[13915]41#include "Performance.h"
[44548]42#include "HostNetworkInterfaceImpl.h"
43#include "netif.h"
[13915]44
[10679]45#include <VBox/com/array.h>
[10641]46#include <VBox/com/ptr.h>
[10679]47#include <VBox/com/string.h>
[76474]48#include <iprt/errcore.h>
[10641]49#include <iprt/string.h>
50#include <iprt/mem.h>
[11689]51#include <iprt/cpuset.h>
[10641]52
[12400]53#include <algorithm>
54
[76593]55#include "LoggingNew.h"
[10641]56
57using namespace pm;
58
59// Stubs for non-pure virtual methods
60
[17911]61int CollectorHAL::getHostCpuLoad(ULONG * /* user */, ULONG * /* kernel */, ULONG * /* idle */)
[10641]62{
[48007]63 return VERR_NOT_IMPLEMENTED;
[10641]64}
65
[17911]66int CollectorHAL::getProcessCpuLoad(RTPROCESS /* process */, ULONG * /* user */, ULONG * /* kernel */)
[10641]67{
[48007]68 return VERR_NOT_IMPLEMENTED;
[10641]69}
70
[17911]71int CollectorHAL::getRawHostCpuLoad(uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* idle */)
[10641]72{
[48007]73 return VERR_NOT_IMPLEMENTED;
[10641]74}
75
[43507]76int CollectorHAL::getRawHostNetworkLoad(const char * /* name */, uint64_t * /* rx */, uint64_t * /* tx */)
[43445]77{
[48007]78 return VERR_NOT_IMPLEMENTED;
[43445]79}
80
[43629]81int CollectorHAL::getRawHostDiskLoad(const char * /* name */, uint64_t * /* disk_ms */, uint64_t * /* total_ms */)
82{
[48007]83 return VERR_NOT_IMPLEMENTED;
[43629]84}
85
[51092]86int CollectorHAL::getRawProcessCpuLoad(RTPROCESS /* process */, uint64_t * /* user */,
87 uint64_t * /* kernel */, uint64_t * /* total */)
[10641]88{
[48007]89 return VERR_NOT_IMPLEMENTED;
[10641]90}
91
[27858]92int CollectorHAL::getHostMemoryUsage(ULONG * /* total */, ULONG * /* used */, ULONG * /* available */)
[27849]93{
[48007]94 return VERR_NOT_IMPLEMENTED;
[27849]95}
96
[51092]97int CollectorHAL::getHostFilesystemUsage(const char * /* name */, ULONG * /* total */, ULONG * /* used */,
98 ULONG * /* available */)
[43629]99{
[48007]100 return VERR_NOT_IMPLEMENTED;
[43629]101}
102
[43958]103int CollectorHAL::getHostDiskSize(const char * /* name */, uint64_t * /* size */)
104{
[48007]105 return VERR_NOT_IMPLEMENTED;
[43958]106}
107
[27858]108int CollectorHAL::getProcessMemoryUsage(RTPROCESS /* process */, ULONG * /* used */)
[27849]109{
[48007]110 return VERR_NOT_IMPLEMENTED;
[27849]111}
112
[45051]113int CollectorHAL::getDiskListByFs(const char * /* name */, DiskList& /* listUsage */, DiskList& /* listLoad */)
[43831]114{
[48007]115 return VERR_NOT_IMPLEMENTED;
[43831]116}
117
[11498]118/* Generic implementations */
119
120int CollectorHAL::getHostCpuMHz(ULONG *mhz)
121{
[11591]122 unsigned cCpus = 0;
123 uint64_t u64TotalMHz = 0;
124 RTCPUSET OnlineSet;
125 RTMpGetOnlineSet(&OnlineSet);
[85263]126 for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
[11810]127 {
[67726]128 Log7Func(("{%p}: Checking if CPU %d is member of online set...\n", this, (int)iCpu));
[11591]129 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
130 {
[67726]131 Log7Func(("{%p}: Getting frequency for CPU %d...\n", this, (int)iCpu));
[11591]132 uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
133 if (uMHz != 0)
134 {
[67726]135 Log7Func(("{%p}: CPU %d %u MHz\n", this, (int)iCpu, uMHz));
[11591]136 u64TotalMHz += uMHz;
137 cCpus++;
138 }
139 }
[11810]140 }
[11591]141
[94088]142 if (cCpus)
143 {
144 *mhz = (ULONG)(u64TotalMHz / cCpus);
145 return VINF_SUCCESS;
146 }
[11591]147
[94088]148 /* This is always the case on darwin, so don't assert there. */
149#ifndef RT_OS_DARWIN
150 AssertFailed();
151#endif
152 *mhz = 0;
153 return VERR_NOT_IMPLEMENTED;
[11498]154}
155
[27885]156#ifndef VBOX_COLLECTOR_TEST_CASE
[30847]157
[40358]158CollectorGuestQueue::CollectorGuestQueue()
159{
160 mEvent = NIL_RTSEMEVENT;
161 RTSemEventCreate(&mEvent);
162}
163
164CollectorGuestQueue::~CollectorGuestQueue()
165{
166 RTSemEventDestroy(mEvent);
167}
168
169void CollectorGuestQueue::push(CollectorGuestRequest* rq)
170{
171 RTCLock lock(mLockMtx);
172
173 mQueue.push(rq);
174 RTSemEventSignal(mEvent);
175}
176
177CollectorGuestRequest* CollectorGuestQueue::pop()
178{
[85263]179 int vrc = VINF_SUCCESS;
180 CollectorGuestRequest *rq = NULL;
[40358]181
182 do
183 {
184 {
185 RTCLock lock(mLockMtx);
186
187 if (!mQueue.empty())
188 {
189 rq = mQueue.front();
190 mQueue.pop();
191 }
192 }
193
194 if (rq)
195 return rq;
[85263]196 vrc = RTSemEventWaitNoResume(mEvent, RT_INDEFINITE_WAIT);
197 } while (RT_SUCCESS(vrc));
[40358]198
199 return NULL;
200}
201
[48013]202HRESULT CGRQEnable::execute()
[40358]203{
204 Assert(mCGuest);
205 return mCGuest->enableInternal(mMask);
206}
207
208void CGRQEnable::debugPrint(void *aObject, const char *aFunction, const char *aText)
209{
[40536]210 NOREF(aObject);
211 NOREF(aFunction);
212 NOREF(aText);
[67726]213 Log7((LOG_FN_FMT ": {%p}: CGRQEnable(mask=0x%x) %s\n", aObject, aFunction, mMask, aText));
[40358]214}
215
[48013]216HRESULT CGRQDisable::execute()
[40358]217{
218 Assert(mCGuest);
219 return mCGuest->disableInternal(mMask);
220}
221
222void CGRQDisable::debugPrint(void *aObject, const char *aFunction, const char *aText)
223{
[40536]224 NOREF(aObject);
225 NOREF(aFunction);
226 NOREF(aText);
[67726]227 Log7((LOG_FN_FMT ": {%p}: CGRQDisable(mask=0x%x) %s\n", aObject, aFunction, mMask, aText));
[40358]228}
229
[48013]230HRESULT CGRQAbort::execute()
[40358]231{
232 return E_ABORT;
233}
234
235void CGRQAbort::debugPrint(void *aObject, const char *aFunction, const char *aText)
236{
[40536]237 NOREF(aObject);
238 NOREF(aFunction);
239 NOREF(aText);
[67726]240 Log7((LOG_FN_FMT ": {%p}: CGRQAbort %s\n", aObject, aFunction, aText));
[40358]241}
242
[36128]243CollectorGuest::CollectorGuest(Machine *machine, RTPROCESS process) :
[36839]244 mUnregistered(false), mEnabled(false), mValid(false), mMachine(machine), mProcess(process),
[36128]245 mCpuUser(0), mCpuKernel(0), mCpuIdle(0),
246 mMemTotal(0), mMemFree(0), mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0),
[43908]247 mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0), mVmNetRx(0), mVmNetTx(0)
[30847]248{
249 Assert(mMachine);
250 /* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
251 mMachine->AddRef();
252}
253
[36128]254CollectorGuest::~CollectorGuest()
[27849]255{
[30847]256 /* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
257 mMachine->Release();
[36128]258 // Assert(!cEnabled); why?
[27849]259}
260
[85263]261HRESULT CollectorGuest::enableVMMStats(bool mCollectVMMStats)
[40084]262{
[85263]263 HRESULT hrc = S_OK;
[40084]264
265 if (mGuest)
266 {
[63563]267 /** @todo replace this with a direct call to mGuest in trunk! */
[40084]268 AutoCaller autoCaller(mMachine);
[98262]269 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[40084]270
271 ComPtr<IInternalSessionControl> directControl;
272
[85263]273 hrc = mMachine->i_getDirectControl(&directControl);
274 if (hrc != S_OK)
275 return hrc;
[40084]276
277 /* enable statistics collection; this is a remote call (!) */
[85263]278 hrc = directControl->EnableVMMStatistics(mCollectVMMStats);
[67726]279 Log7Func(("{%p}: %sable VMM stats (%s)\n",
[85263]280 this, mCollectVMMStats ? "En" : "Dis", SUCCEEDED(hrc) ? "success" : "failed"));
[40084]281 }
282
[85263]283 return hrc;
[40084]284}
285
[85263]286HRESULT CollectorGuest::enable(ULONG mask)
[27849]287{
[40358]288 return enqueueRequest(new CGRQEnable(mask));
289}
[30847]290
[85263]291HRESULT CollectorGuest::disable(ULONG mask)
[40358]292{
293 return enqueueRequest(new CGRQDisable(mask));
294}
295
[48013]296HRESULT CollectorGuest::enableInternal(ULONG mask)
[40358]297{
[27885]298 HRESULT ret = S_OK;
299
[40358]300 if ((mEnabled & mask) == mask)
301 return E_UNEXPECTED;
[27885]302
[40358]303 if (!mEnabled)
304 {
305 /* Must make sure that the machine object does not get uninitialized
306 * in the middle of enabling this collector. Causes timing-related
307 * behavior otherwise, which we don't want. In particular the
308 * GetRemoteConsole call below can hang if the VM didn't completely
309 * terminate (the VM processes stop processing events shortly before
310 * closing the session). This avoids the hang. */
311 AutoCaller autoCaller(mMachine);
[98262]312 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[27885]313
[51498]314 mMachineName = mMachine->i_getName();
[27885]315
[40358]316 ComPtr<IInternalSessionControl> directControl;
317
[51498]318 ret = mMachine->i_getDirectControl(&directControl);
[40358]319 if (ret != S_OK)
320 return ret;
321
322 /* get the associated console; this is a remote call (!) */
[55214]323 ret = directControl->COMGETTER(RemoteConsole)(mConsole.asOutParam());
[40358]324 if (ret != S_OK)
325 return ret;
326
327 ret = mConsole->COMGETTER(Guest)(mGuest.asOutParam());
328 if (ret == S_OK)
329 {
330 ret = mGuest->COMSETTER(StatisticsUpdateInterval)(1 /* 1 sec */);
[67726]331 Log7Func(("{%p}: Set guest statistics update interval to 1 sec (%s)\n",
332 this, SUCCEEDED(ret) ? "success" : "failed"));
[40358]333 }
[27885]334 }
[43908]335 if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
[40358]336 enableVMMStats(true);
337 mEnabled |= mask;
[36128]338
[27885]339 return ret;
[27849]340}
341
[85263]342HRESULT CollectorGuest::disableInternal(ULONG mask)
[27849]343{
[40358]344 if (!(mEnabled & mask))
345 return E_UNEXPECTED;
[36128]346
[43908]347 if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
[40358]348 enableVMMStats(false);
349 mEnabled &= ~mask;
350 if (!mEnabled)
351 {
352 Assert(mGuest && mConsole);
353 HRESULT ret = mGuest->COMSETTER(StatisticsUpdateInterval)(0 /* off */);
354 NOREF(ret);
[67726]355 Log7Func(("{%p}: Set guest statistics update interval to 0 sec (%s)\n",
356 this, SUCCEEDED(ret) ? "success" : "failed"));
[43908]357 invalidate(VMSTATS_ALL);
[40358]358 }
359
[36128]360 return S_OK;
361}
362
[85263]363HRESULT CollectorGuest::enqueueRequest(CollectorGuestRequest *aRequest)
[40358]364{
365 if (mManager)
366 {
367 aRequest->setGuest(this);
368 return mManager->enqueueRequest(aRequest);
369 }
370
[67726]371 Log7Func(("{%p}: Attempted enqueue guest request when mManager is null\n", this));
[40358]372 return E_POINTER;
373}
374
[40084]375void CollectorGuest::updateStats(ULONG aValidStats, ULONG aCpuUser,
376 ULONG aCpuKernel, ULONG aCpuIdle,
377 ULONG aMemTotal, ULONG aMemFree,
378 ULONG aMemBalloon, ULONG aMemShared,
379 ULONG aMemCache, ULONG aPageTotal,
380 ULONG aAllocVMM, ULONG aFreeVMM,
[43908]381 ULONG aBalloonedVMM, ULONG aSharedVMM,
382 ULONG aVmNetRx, ULONG aVmNetTx)
[36128]383{
[43908]384 if ((aValidStats & VMSTATS_GUEST_CPULOAD) == VMSTATS_GUEST_CPULOAD)
[27885]385 {
[40084]386 mCpuUser = aCpuUser;
387 mCpuKernel = aCpuKernel,
388 mCpuIdle = aCpuIdle;
[27885]389 }
[43908]390 if ((aValidStats & VMSTATS_GUEST_RAMUSAGE) == VMSTATS_GUEST_RAMUSAGE)
[40084]391 {
392 mMemTotal = aMemTotal;
393 mMemFree = aMemFree;
394 mMemBalloon = aMemBalloon;
395 mMemShared = aMemShared;
396 mMemCache = aMemCache;
397 mPageTotal = aPageTotal;
398 }
[43908]399 if ((aValidStats & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
[40084]400 {
401 mAllocVMM = aAllocVMM;
402 mFreeVMM = aFreeVMM;
403 mBalloonedVMM = aBalloonedVMM;
404 mSharedVMM = aSharedVMM;
405 }
[43908]406 if ((aValidStats & VMSTATS_NET_RATE) == VMSTATS_NET_RATE)
407 {
408 mVmNetRx = aVmNetRx;
409 mVmNetTx = aVmNetTx;
410 }
[40084]411 mValid = aValidStats;
[27849]412}
[27930]413
[40358]414CollectorGuestManager::CollectorGuestManager()
415 : mVMMStatsProvider(NULL), mGuestBeingCalled(NULL)
[27930]416{
[85263]417 int vrc = RTThreadCreate(&mThread, CollectorGuestManager::requestProcessingThread,
[40358]418 this, 0, RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE,
419 "CGMgr");
[85263]420 NOREF(vrc);
421 Log7Func(("{%p}: RTThreadCreate returned %Rrc (mThread=%p)\n", this, vrc, mThread));
[40358]422}
[36128]423
[40358]424CollectorGuestManager::~CollectorGuestManager()
425{
426 Assert(mGuests.size() == 0);
427 int rcThread = 0;
[85263]428 HRESULT hrc = enqueueRequest(new CGRQAbort());
429 if (SUCCEEDED(hrc))
[27930]430 {
[40358]431 /* We wait only if we were able to put the abort request to a queue */
[67726]432 Log7Func(("{%p}: Waiting for CGM request processing thread to stop...\n", this));
[85263]433 int vrc = RTThreadWait(mThread, 1000 /* 1 sec */, &rcThread);
434 Log7Func(("{%p}: RTThreadWait returned %Rrc (thread exit code: %Rrc)\n", this, vrc, rcThread));
[85269]435 RT_NOREF(vrc);
[36128]436 }
437}
[28004]438
[36128]439void CollectorGuestManager::registerGuest(CollectorGuest* pGuest)
440{
[40358]441 pGuest->setManager(this);
[36128]442 mGuests.push_back(pGuest);
443 /*
444 * If no VMM stats provider was elected previously than this is our
445 * candidate.
446 */
447 if (!mVMMStatsProvider)
448 mVMMStatsProvider = pGuest;
[67726]449 Log7Func(("{%p}: Registered guest=%p provider=%p\n", this, pGuest, mVMMStatsProvider));
[36128]450}
[28005]451
[36128]452void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest)
453{
[67726]454 Log7Func(("{%p}: About to unregister guest=%p provider=%p\n", this, pGuest, mVMMStatsProvider));
[36839]455 //mGuests.remove(pGuest); => destroyUnregistered()
456 pGuest->unregister();
[36128]457 if (pGuest == mVMMStatsProvider)
458 {
459 /* This was our VMM stats provider, it is time to re-elect */
[36839]460 CollectorGuestList::iterator it;
461 /* Assume that nobody can provide VMM stats */
462 mVMMStatsProvider = NULL;
463
[55769]464 for (it = mGuests.begin(); it != mGuests.end(); ++it)
[36128]465 {
[36839]466 /* Skip unregistered as they are about to be destroyed */
467 if ((*it)->isUnregistered())
468 continue;
[28005]469
[36839]470 if ((*it)->isEnabled())
471 {
472 /* Found the guest already collecting stats, elect it */
473 mVMMStatsProvider = *it;
[85263]474 HRESULT hrc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM));
475 if (FAILED(hrc))
[40358]476 {
477 /* This is not a good candidate -- try to find another */
478 mVMMStatsProvider = NULL;
479 continue;
480 }
[36839]481 break;
482 }
[40358]483 }
484 if (!mVMMStatsProvider)
485 {
486 /* If nobody collects stats, take the first registered */
[55769]487 for (it = mGuests.begin(); it != mGuests.end(); ++it)
[36839]488 {
[40358]489 /* Skip unregistered as they are about to be destroyed */
490 if ((*it)->isUnregistered())
491 continue;
492
[36839]493 mVMMStatsProvider = *it;
[43908]494 //mVMMStatsProvider->enable(VMSTATS_VMM_RAM);
[85263]495 HRESULT hrc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM));
496 if (SUCCEEDED(hrc))
[40358]497 break;
498 /* This was not a good candidate -- try to find another */
499 mVMMStatsProvider = NULL;
[36839]500 }
[36128]501 }
[27930]502 }
[67727]503 Log7Func(("[%p}: LEAVE new provider=%p\n", this, mVMMStatsProvider));
[27930]504}
505
[36839]506void CollectorGuestManager::destroyUnregistered()
507{
508 CollectorGuestList::iterator it;
[36128]509
[36839]510 for (it = mGuests.begin(); it != mGuests.end();)
511 if ((*it)->isUnregistered())
512 {
513 delete *it;
514 it = mGuests.erase(it);
[67726]515 Log7Func(("{%p}: Number of guests after erasing unregistered is %d\n",
516 this, mGuests.size()));
[36839]517 }
518 else
519 ++it;
520}
521
[85263]522HRESULT CollectorGuestManager::enqueueRequest(CollectorGuestRequest *aRequest)
[40358]523{
524#ifdef DEBUG
525 aRequest->debugPrint(this, __PRETTY_FUNCTION__, "added to CGM queue");
526#endif /* DEBUG */
527 /*
528 * It is very unlikely that we will get high frequency calls to configure
529 * guest metrics collection, so we rely on this fact to detect blocked
530 * guests. If the guest has not finished processing the previous request
[40568]531 * after half a second we consider it blocked.
[40358]532 */
533 if (aRequest->getGuest() && aRequest->getGuest() == mGuestBeingCalled)
534 {
[48955]535 /*
[40568]536 * Before we can declare a guest blocked we need to wait for a while
537 * and then check again as it may never had a chance to process
538 * the previous request. Half a second is an eternity for processes
539 * and is barely noticable by humans.
540 */
[67726]541 Log7Func(("{%p}: Suspecting %s is stalled. Waiting for .5 sec...\n",
542 this, aRequest->getGuest()->getVMName().c_str()));
[40568]543 RTThreadSleep(500 /* ms */);
544 if (aRequest->getGuest() == mGuestBeingCalled) {
[67726]545 Log7Func(("{%p}: Request processing stalled for %s\n",
546 this, aRequest->getGuest()->getVMName().c_str()));
[40568]547 /* Request execution got stalled for this guest -- report an error */
548 return E_FAIL;
549 }
[40358]550 }
551 mQueue.push(aRequest);
552 return S_OK;
553}
554
555/* static */
556DECLCALLBACK(int) CollectorGuestManager::requestProcessingThread(RTTHREAD /* aThread */, void *pvUser)
557{
558 CollectorGuestRequest *pReq;
559 CollectorGuestManager *mgr = static_cast<CollectorGuestManager*>(pvUser);
560
561 HRESULT rc = S_OK;
562
[67726]563 Log7Func(("{%p}: Starting request processing loop...\n", mgr));
[40358]564 while ((pReq = mgr->mQueue.pop()) != NULL)
565 {
566#ifdef DEBUG
567 pReq->debugPrint(mgr, __PRETTY_FUNCTION__, "is being executed...");
568#endif /* DEBUG */
569 mgr->mGuestBeingCalled = pReq->getGuest();
570 rc = pReq->execute();
571 mgr->mGuestBeingCalled = NULL;
572 delete pReq;
573 if (rc == E_ABORT)
574 break;
575 if (FAILED(rc))
[67726]576 Log7Func(("{%p}: request::execute returned %u\n", mgr, rc));
[40358]577 }
[67726]578 Log7Func(("{%p}: Exiting request processing loop... rc=%u\n", mgr, rc));
[40358]579
580 return VINF_SUCCESS;
581}
582
583
[28525]584#endif /* !VBOX_COLLECTOR_TEST_CASE */
[27849]585
[12400]586bool BaseMetric::collectorBeat(uint64_t nowAt)
[10713]587{
588 if (isEnabled())
589 {
[43445]590 if (mLastSampleTaken == 0)
[10713]591 {
592 mLastSampleTaken = nowAt;
[67726]593 Log4Func(("{%p}: Collecting %s for obj(%p)...\n",
594 this, getName(), (void *)mObject));
[12400]595 return true;
[10713]596 }
[43445]597 /*
598 * We use low resolution timers which may fire just a little bit early.
599 * We compensate for that by jumping into the future by several
600 * milliseconds (see @bugref{6345}).
601 */
602 if (nowAt - mLastSampleTaken + PM_SAMPLER_PRECISION_MS >= mPeriod * 1000)
603 {
604 /*
605 * We don't want the beat to drift. This is why the timestamp of
606 * the last taken sample is not the actual time but the time we
607 * should have taken the measurement at.
608 */
609 mLastSampleTaken += mPeriod * 1000;
[67726]610 Log4Func(("{%p}: Collecting %s for obj(%p)...\n",
611 this, getName(), (void *)mObject));
[43445]612 return true;
613 }
[67726]614 Log4Func(("{%p}: Enabled but too early to collect %s for obj(%p)\n",
615 this, getName(), (void *)mObject));
[10713]616 }
[12400]617 return false;
[10713]618}
619
[11180]620void HostCpuLoad::init(ULONG period, ULONG length)
[10641]621{
622 mPeriod = period;
623 mLength = length;
624 mUser->init(mLength);
625 mKernel->init(mLength);
626 mIdle->init(mLength);
627}
628
629void HostCpuLoad::collect()
630{
[11180]631 ULONG user, kernel, idle;
[85263]632 int vrc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
633 if (RT_SUCCESS(vrc))
[10753]634 {
635 mUser->put(user);
636 mKernel->put(kernel);
637 mIdle->put(idle);
638 }
[10641]639}
640
[44450]641void HostCpuLoadRaw::init(ULONG period, ULONG length)
642{
643 HostCpuLoad::init(period, length);
644 mHAL->getRawHostCpuLoad(&mUserPrev, &mKernelPrev, &mIdlePrev);
645}
646
[28058]647void HostCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[12400]648{
649 hints.collectHostCpuLoad();
650}
651
[10641]652void HostCpuLoadRaw::collect()
653{
[10868]654 uint64_t user, kernel, idle;
655 uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
[10641]656
[85263]657 int vrc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
658 if (RT_SUCCESS(vrc))
[10713]659 {
660 userDiff = user - mUserPrev;
661 kernelDiff = kernel - mKernelPrev;
662 idleDiff = idle - mIdlePrev;
663 totalDiff = userDiff + kernelDiff + idleDiff;
[10868]664
665 if (totalDiff == 0)
666 {
667 /* This is only possible if none of counters has changed! */
[21878]668 LogFlowThisFunc(("Impossible! User, kernel and idle raw "
[10868]669 "counters has not changed since last sample.\n" ));
670 mUser->put(0);
671 mKernel->put(0);
672 mIdle->put(0);
673 }
674 else
675 {
[11180]676 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
677 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
678 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
[10868]679 }
[11591]680
[10713]681 mUserPrev = user;
682 mKernelPrev = kernel;
683 mIdlePrev = idle;
684 }
[10641]685}
686
[44548]687#ifndef VBOX_COLLECTOR_TEST_CASE
688static bool getLinkSpeed(const char *szShortName, uint32_t *pSpeed)
689{
[94722]690# ifdef VBOX_WITH_HOSTNETIF_API
[44742]691 NETIFSTATUS enmState = NETIF_S_UNKNOWN;
[85263]692 int vrc = NetIfGetState(szShortName, &enmState);
693 if (RT_FAILURE(vrc))
[44548]694 return false;
[44742]695 if (enmState != NETIF_S_UP)
696 *pSpeed = 0;
697 else
698 {
[85263]699 vrc = NetIfGetLinkSpeed(szShortName, pSpeed);
700 if (RT_FAILURE(vrc))
[44742]701 return false;
702 }
[44548]703 return true;
[94722]704# else /* !VBOX_WITH_HOSTNETIF_API */
705 RT_NOREF(szShortName, pSpeed);
706 return false;
707# endif /* VBOX_WITH_HOSTNETIF_API */
[44548]708}
709
710void HostNetworkSpeed::init(ULONG period, ULONG length)
711{
712 mPeriod = period;
713 mLength = length;
714 mLinkSpeed->init(length);
715 /*
716 * Retrieve the link speed now as it may be wrong if the metric was
717 * registered at boot (see @bugref{6613}).
718 */
719 getLinkSpeed(mShortName.c_str(), &mSpeed);
720}
721
[43445]722void HostNetworkLoadRaw::init(ULONG period, ULONG length)
723{
724 mPeriod = period;
725 mLength = length;
726 mRx->init(mLength);
727 mTx->init(mLength);
[44548]728 /*
729 * Retrieve the link speed now as it may be wrong if the metric was
730 * registered at boot (see @bugref{6613}).
731 */
732 uint32_t uSpeedMbit = 65535;
733 if (getLinkSpeed(mShortName.c_str(), &uSpeedMbit))
734 mSpeed = (uint64_t)uSpeedMbit * (1000000/8); /* Convert to bytes/sec */
[85263]735 /*int vrc =*/ mHAL->getRawHostNetworkLoad(mShortName.c_str(), &mRxPrev, &mTxPrev);
736 //AssertRC(vrc);
[43445]737}
738
739void HostNetworkLoadRaw::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
740{
[43456]741 if (RT_FAILURE(mRc))
742 {
743 ComPtr<IHostNetworkInterface> networkInterface;
744 ComPtr<IHost> host = getObject();
745 HRESULT hrc = host->FindHostNetworkInterfaceByName(com::Bstr(mInterfaceName).raw(), networkInterface.asOutParam());
746 if (SUCCEEDED(hrc))
747 {
[61362]748 static uint32_t s_tsLogRelLast;
749 uint32_t tsNow = RTTimeProgramSecTS();
750 if ( tsNow < RT_SEC_1HOUR
751 || (tsNow - s_tsLogRelLast >= 60))
[61347]752 {
753 s_tsLogRelLast = tsNow;
754 LogRel(("Failed to collect network metrics for %s: %Rrc (%d). Max one msg/min.\n", mInterfaceName.c_str(), mRc, mRc));
755 }
[43456]756 mRc = VINF_SUCCESS;
757 }
758 }
[43445]759}
760
761void HostNetworkLoadRaw::collect()
762{
[44031]763 uint64_t rx = mRxPrev;
764 uint64_t tx = mTxPrev;
[43445]765
[44031]766 if (RT_UNLIKELY(mSpeed * getPeriod() == 0))
767 {
768 LogFlowThisFunc(("Check cable for %s! speed=%llu period=%d.\n", mShortName.c_str(), mSpeed, getPeriod()));
769 /* We do not collect host network metrics for unplugged interfaces! */
770 return;
771 }
[43618]772 mRc = mHAL->getRawHostNetworkLoad(mShortName.c_str(), &rx, &tx);
[43456]773 if (RT_SUCCESS(mRc))
[43445]774 {
775 uint64_t rxDiff = rx - mRxPrev;
776 uint64_t txDiff = tx - mTxPrev;
777
[44031]778 mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (mSpeed * getPeriod())));
779 mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (mSpeed * getPeriod())));
[43445]780
781 mRxPrev = rx;
782 mTxPrev = tx;
783 }
[43456]784 else
785 LogFlowThisFunc(("Failed to collect data: %Rrc (%d)."
786 " Will update the list of interfaces...\n", mRc,mRc));
[43445]787}
[44548]788#endif /* !VBOX_COLLECTOR_TEST_CASE */
[43445]789
[43629]790void HostDiskLoadRaw::init(ULONG period, ULONG length)
791{
792 mPeriod = period;
793 mLength = length;
794 mUtil->init(mLength);
[85263]795 int vrc = mHAL->getRawHostDiskLoad(mDiskName.c_str(), &mDiskPrev, &mTotalPrev);
796 AssertRC(vrc);
[43629]797}
798
799void HostDiskLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
800{
801 hints.collectHostCpuLoad();
802}
803
804void HostDiskLoadRaw::collect()
805{
806 uint64_t disk, total;
807
[85263]808 int vrc = mHAL->getRawHostDiskLoad(mDiskName.c_str(), &disk, &total);
809 if (RT_SUCCESS(vrc))
[43629]810 {
811 uint64_t diskDiff = disk - mDiskPrev;
812 uint64_t totalDiff = total - mTotalPrev;
813
814 if (RT_UNLIKELY(totalDiff == 0))
815 {
816 Assert(totalDiff);
817 LogFlowThisFunc(("Improbable! Less than millisecond passed! Disk=%s\n", mDiskName.c_str()));
818 mUtil->put(0);
819 }
820 else if (diskDiff > totalDiff)
821 {
822 /*
823 * It is possible that the disk spent more time than CPU because
824 * CPU measurements are taken during the pre-collect phase. We try
825 * to compensate for than by adding the extra to the next round of
826 * measurements.
827 */
828 mUtil->put(PM_NETWORK_LOAD_MULTIPLIER);
829 Assert((diskDiff - totalDiff) < mPeriod * 1000);
830 if ((diskDiff - totalDiff) > mPeriod * 1000)
831 {
832 LogRel(("Disk utilization time exceeds CPU time by more"
833 " than the collection period (%llu ms)\n", diskDiff - totalDiff));
834 }
835 else
836 {
837 disk = mDiskPrev + totalDiff;
838 LogFlowThisFunc(("Moved %u milliseconds to the next period.\n", (unsigned)(diskDiff - totalDiff)));
839 }
840 }
841 else
842 {
843 mUtil->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * diskDiff / totalDiff));
844 }
845
846 mDiskPrev = disk;
847 mTotalPrev = total;
848 }
849 else
[85263]850 LogFlowThisFunc(("Failed to collect data: %Rrc (%d)\n", vrc, vrc));
[43629]851}
852
[11180]853void HostCpuMhz::init(ULONG period, ULONG length)
[10679]854{
855 mPeriod = period;
856 mLength = length;
857 mMHz->init(mLength);
858}
859
[10641]860void HostCpuMhz::collect()
861{
[11180]862 ULONG mhz;
[85263]863 int vrc = mHAL->getHostCpuMHz(&mhz);
864 if (RT_SUCCESS(vrc))
[10713]865 mMHz->put(mhz);
[10641]866}
867
[11180]868void HostRamUsage::init(ULONG period, ULONG length)
[10679]869{
870 mPeriod = period;
871 mLength = length;
872 mTotal->init(mLength);
873 mUsed->init(mLength);
874 mAvailable->init(mLength);
875}
876
[28058]877void HostRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[12400]878{
879 hints.collectHostRamUsage();
880}
881
[10641]882void HostRamUsage::collect()
883{
[11180]884 ULONG total, used, available;
[85263]885 int vrc = mHAL->getHostMemoryUsage(&total, &used, &available);
886 if (RT_SUCCESS(vrc))
[10713]887 {
888 mTotal->put(total);
889 mUsed->put(used);
[28036]890 mAvailable->put(available);
[10713]891 }
[35964]892}
893
[43629]894void HostFilesystemUsage::init(ULONG period, ULONG length)
895{
896 mPeriod = period;
897 mLength = length;
898 mTotal->init(mLength);
899 mUsed->init(mLength);
900 mAvailable->init(mLength);
901}
902
903void HostFilesystemUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
904{
905}
906
907void HostFilesystemUsage::collect()
908{
909 ULONG total, used, available;
[85263]910 int vrc = mHAL->getHostFilesystemUsage(mFsName.c_str(), &total, &used, &available);
911 if (RT_SUCCESS(vrc))
[43629]912 {
913 mTotal->put(total);
914 mUsed->put(used);
915 mAvailable->put(available);
916 }
917}
918
[43958]919void HostDiskUsage::init(ULONG period, ULONG length)
920{
921 mPeriod = period;
922 mLength = length;
923 mTotal->init(mLength);
924}
925
926void HostDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
927{
928}
929
930void HostDiskUsage::collect()
931{
932 uint64_t total;
[85263]933 int vrc = mHAL->getHostDiskSize(mDiskName.c_str(), &total);
934 if (RT_SUCCESS(vrc))
[48009]935 mTotal->put((ULONG)(total / _1M));
[43958]936}
937
[40358]938#ifndef VBOX_COLLECTOR_TEST_CASE
[85263]939
[35964]940void HostRamVmm::init(ULONG period, ULONG length)
941{
942 mPeriod = period;
943 mLength = length;
944 mAllocVMM->init(mLength);
945 mFreeVMM->init(mLength);
946 mBalloonVMM->init(mLength);
947 mSharedVMM->init(mLength);
948}
949
[85263]950HRESULT HostRamVmm::enable()
[40358]951{
[85263]952 HRESULT hrc = S_OK;
[40358]953 CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
954 if (provider)
[85263]955 hrc = provider->enable(VMSTATS_VMM_RAM);
[40358]956 BaseMetric::enable();
[85263]957 return hrc;
[40358]958}
959
[85263]960HRESULT HostRamVmm::disable()
[40358]961{
[85263]962 HRESULT rc = S_OK;
[40358]963 BaseMetric::disable();
964 CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
965 if (provider)
[43908]966 rc = provider->disable(VMSTATS_VMM_RAM);
[40358]967 return rc;
968}
969
[36128]970void HostRamVmm::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[35964]971{
[36128]972 hints.collectHostRamVmm();
[35964]973}
974
975void HostRamVmm::collect()
976{
[36128]977 CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
978 if (provider)
979 {
[67726]980 Log7Func(("{%p}: provider=%p enabled=%RTbool valid=%RTbool...\n",
981 this, provider, provider->isEnabled(), provider->isValid(VMSTATS_VMM_RAM) ));
[43908]982 if (provider->isValid(VMSTATS_VMM_RAM))
[36128]983 {
984 /* Provider is ready, get updated stats */
985 mAllocCurrent = provider->getAllocVMM();
986 mFreeCurrent = provider->getFreeVMM();
987 mBalloonedCurrent = provider->getBalloonedVMM();
988 mSharedCurrent = provider->getSharedVMM();
[43908]989 provider->invalidate(VMSTATS_VMM_RAM);
[36128]990 }
[40358]991 /*
992 * Note that if there are no new values from the provider we will use
993 * the ones most recently provided instead of zeros, which is probably
994 * a desirable behavior.
995 */
[36128]996 }
997 else
998 {
999 mAllocCurrent = 0;
1000 mFreeCurrent = 0;
1001 mBalloonedCurrent = 0;
1002 mSharedCurrent = 0;
1003 }
[67726]1004 Log7Func(("{%p}: mAllocCurrent=%u mFreeCurrent=%u mBalloonedCurrent=%u mSharedCurrent=%u\n",
1005 this, mAllocCurrent, mFreeCurrent, mBalloonedCurrent, mSharedCurrent));
[36128]1006 mAllocVMM->put(mAllocCurrent);
1007 mFreeVMM->put(mFreeCurrent);
1008 mBalloonVMM->put(mBalloonedCurrent);
1009 mSharedVMM->put(mSharedCurrent);
[10641]1010}
[85263]1011
[40358]1012#endif /* !VBOX_COLLECTOR_TEST_CASE */
[10641]1013
1014
[10679]1015
[11180]1016void MachineCpuLoad::init(ULONG period, ULONG length)
[10679]1017{
1018 mPeriod = period;
1019 mLength = length;
1020 mUser->init(mLength);
1021 mKernel->init(mLength);
1022}
1023
[10641]1024void MachineCpuLoad::collect()
1025{
[11180]1026 ULONG user, kernel;
[85263]1027 int vrc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
1028 if (RT_SUCCESS(vrc))
[10713]1029 {
1030 mUser->put(user);
1031 mKernel->put(kernel);
1032 }
[10641]1033}
1034
[28058]1035void MachineCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[12400]1036{
1037 hints.collectProcessCpuLoad(mProcess);
1038}
1039
[10641]1040void MachineCpuLoadRaw::collect()
1041{
[10868]1042 uint64_t processUser, processKernel, hostTotal;
[10641]1043
[85263]1044 int vrc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
1045 if (RT_SUCCESS(vrc))
[10713]1046 {
[10868]1047 if (hostTotal == mHostTotalPrev)
[10713]1048 {
[10868]1049 /* Nearly impossible, but... */
1050 mUser->put(0);
1051 mKernel->put(0);
[10713]1052 }
[10868]1053 else
1054 {
[11180]1055 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
1056 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
[10868]1057 }
[11591]1058
[10868]1059 mHostTotalPrev = hostTotal;
1060 mProcessUserPrev = processUser;
1061 mProcessKernelPrev = processKernel;
[10713]1062 }
[10641]1063}
1064
[11180]1065void MachineRamUsage::init(ULONG period, ULONG length)
[10679]1066{
1067 mPeriod = period;
1068 mLength = length;
1069 mUsed->init(mLength);
1070}
1071
[28058]1072void MachineRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[12400]1073{
1074 hints.collectProcessRamUsage(mProcess);
1075}
1076
[10641]1077void MachineRamUsage::collect()
1078{
[11180]1079 ULONG used;
[85263]1080 int vrc = mHAL->getProcessMemoryUsage(mProcess, &used);
1081 if (RT_SUCCESS(vrc))
[10713]1082 mUsed->put(used);
[10641]1083}
1084
[27822]1085
[40358]1086#ifndef VBOX_COLLECTOR_TEST_CASE
[85263]1087
[43949]1088void MachineDiskUsage::init(ULONG period, ULONG length)
1089{
1090 mPeriod = period;
1091 mLength = length;
1092 mUsed->init(mLength);
1093}
1094
1095void MachineDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
1096{
1097}
1098
1099void MachineDiskUsage::collect()
1100{
1101 ULONG used = 0;
1102
1103 for (MediaList::iterator it = mDisks.begin(); it != mDisks.end(); ++it)
1104 {
1105 ComObjPtr<Medium> pMedium = *it;
1106
1107 /* just in case */
[60054]1108 AssertContinue(!pMedium.isNull());
[43949]1109
1110 AutoCaller localAutoCaller(pMedium);
[98262]1111 if (FAILED(localAutoCaller.hrc())) continue;
[43949]1112
1113 AutoReadLock local_alock(pMedium COMMA_LOCKVAL_SRC_POS);
1114
[49795]1115 used += (ULONG)(pMedium->i_getSize() / _1M);
[43949]1116 }
1117
1118 mUsed->put(used);
1119}
1120
[43908]1121void MachineNetRate::init(ULONG period, ULONG length)
1122{
1123 mPeriod = period;
1124 mLength = length;
1125
1126 mRx->init(mLength);
1127 mTx->init(mLength);
1128}
1129
1130void MachineNetRate::collect()
1131{
1132 if (mCGuest->isValid(VMSTATS_NET_RATE))
1133 {
1134 mRx->put(mCGuest->getVmNetRx());
1135 mTx->put(mCGuest->getVmNetTx());
1136 mCGuest->invalidate(VMSTATS_NET_RATE);
1137 }
1138}
1139
[85263]1140HRESULT MachineNetRate::enable()
[43908]1141{
[85263]1142 HRESULT rc = mCGuest->enable(VMSTATS_NET_RATE);
[43908]1143 BaseMetric::enable();
1144 return rc;
1145}
1146
[85263]1147HRESULT MachineNetRate::disable()
[43908]1148{
1149 BaseMetric::disable();
1150 return mCGuest->disable(VMSTATS_NET_RATE);
1151}
1152
1153void MachineNetRate::preCollect(CollectorHints& hints, uint64_t /* iTick */)
1154{
1155 hints.collectGuestStats(mCGuest->getProcess());
1156}
1157
[27822]1158void GuestCpuLoad::init(ULONG period, ULONG length)
1159{
1160 mPeriod = period;
1161 mLength = length;
1162
1163 mUser->init(mLength);
1164 mKernel->init(mLength);
1165 mIdle->init(mLength);
1166}
1167
[36128]1168void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t /* iTick */)
[27822]1169{
[36128]1170 hints.collectGuestStats(mCGuest->getProcess());
[27822]1171}
1172
1173void GuestCpuLoad::collect()
1174{
[43908]1175 if (mCGuest->isValid(VMSTATS_GUEST_CPULOAD))
[36128]1176 {
1177 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuUser()) / 100);
1178 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuKernel()) / 100);
1179 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuIdle()) / 100);
[43908]1180 mCGuest->invalidate(VMSTATS_GUEST_CPULOAD);
[36128]1181 }
[27822]1182}
1183
[85263]1184HRESULT GuestCpuLoad::enable()
[40358]1185{
[85263]1186 HRESULT rc = mCGuest->enable(VMSTATS_GUEST_CPULOAD);
[40358]1187 BaseMetric::enable();
1188 return rc;
1189}
1190
[85263]1191HRESULT GuestCpuLoad::disable()
[40358]1192{
1193 BaseMetric::disable();
[43908]1194 return mCGuest->disable(VMSTATS_GUEST_CPULOAD);
[40358]1195}
1196
[27822]1197void GuestRamUsage::init(ULONG period, ULONG length)
1198{
1199 mPeriod = period;
1200 mLength = length;
1201
1202 mTotal->init(mLength);
1203 mFree->init(mLength);
1204 mBallooned->init(mLength);
[29620]1205 mShared->init(mLength);
[27822]1206 mCache->init(mLength);
1207 mPagedTotal->init(mLength);
1208}
1209
1210void GuestRamUsage::collect()
1211{
[43908]1212 if (mCGuest->isValid(VMSTATS_GUEST_RAMUSAGE))
[36128]1213 {
1214 mTotal->put(mCGuest->getMemTotal());
1215 mFree->put(mCGuest->getMemFree());
1216 mBallooned->put(mCGuest->getMemBalloon());
1217 mShared->put(mCGuest->getMemShared());
1218 mCache->put(mCGuest->getMemCache());
1219 mPagedTotal->put(mCGuest->getPageTotal());
[43908]1220 mCGuest->invalidate(VMSTATS_GUEST_RAMUSAGE);
[36128]1221 }
[27822]1222}
1223
[85263]1224HRESULT GuestRamUsage::enable()
[40358]1225{
[85263]1226 HRESULT rc = mCGuest->enable(VMSTATS_GUEST_RAMUSAGE);
[40358]1227 BaseMetric::enable();
1228 return rc;
1229}
1230
[85263]1231HRESULT GuestRamUsage::disable()
[40358]1232{
1233 BaseMetric::disable();
[43908]1234 return mCGuest->disable(VMSTATS_GUEST_RAMUSAGE);
[40358]1235}
1236
1237void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
1238{
1239 hints.collectGuestStats(mCGuest->getProcess());
1240}
[85263]1241
[40358]1242#endif /* !VBOX_COLLECTOR_TEST_CASE */
1243
[25149]1244void CircularBuffer::init(ULONG ulLength)
[10641]1245{
1246 if (mData)
1247 RTMemFree(mData);
[25149]1248 mLength = ulLength;
[11481]1249 if (mLength)
[25149]1250 mData = (ULONG*)RTMemAllocZ(ulLength * sizeof(ULONG));
[11481]1251 else
1252 mData = NULL;
[10713]1253 mWrapped = false;
1254 mEnd = 0;
[12973]1255 mSequenceNumber = 0;
[10641]1256}
1257
[11180]1258ULONG CircularBuffer::length()
[10641]1259{
[10713]1260 return mWrapped ? mLength : mEnd;
[10641]1261}
1262
[11180]1263void CircularBuffer::put(ULONG value)
[10641]1264{
[10713]1265 if (mData)
1266 {
1267 mData[mEnd++] = value;
1268 if (mEnd >= mLength)
1269 {
1270 mEnd = 0;
1271 mWrapped = true;
1272 }
[12973]1273 ++mSequenceNumber;
[10713]1274 }
[10641]1275}
1276
[11180]1277void CircularBuffer::copyTo(ULONG *data)
[10641]1278{
[10713]1279 if (mWrapped)
1280 {
[11180]1281 memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
[10713]1282 // Copy the wrapped part
1283 if (mEnd)
[11180]1284 memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
[10713]1285 }
1286 else
[11180]1287 memcpy(data, mData, mEnd * sizeof(ULONG));
[10641]1288}
1289
[11180]1290void SubMetric::query(ULONG *data)
[10641]1291{
[10713]1292 copyTo(data);
[10641]1293}
[11591]1294
[12973]1295void Metric::query(ULONG **data, ULONG *count, ULONG *sequenceNumber)
[10641]1296{
[11180]1297 ULONG length;
1298 ULONG *tmpData;
[10641]1299
1300 length = mSubMetric->length();
[12973]1301 *sequenceNumber = mSubMetric->getSequenceNumber() - length;
[10641]1302 if (length)
1303 {
[11180]1304 tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
[10713]1305 mSubMetric->query(tmpData);
[10641]1306 if (mAggregate)
1307 {
1308 *count = 1;
[11180]1309 *data = (ULONG*)RTMemAlloc(sizeof(**data));
[10641]1310 **data = mAggregate->compute(tmpData, length);
[10713]1311 RTMemFree(tmpData);
[10641]1312 }
1313 else
1314 {
1315 *count = length;
1316 *data = tmpData;
1317 }
1318 }
1319 else
1320 {
1321 *count = 0;
1322 *data = 0;
1323 }
1324}
1325
[11180]1326ULONG AggregateAvg::compute(ULONG *data, ULONG length)
[10641]1327{
[10713]1328 uint64_t tmp = 0;
[11180]1329 for (ULONG i = 0; i < length; ++i)
[10713]1330 tmp += data[i];
[11180]1331 return (ULONG)(tmp / length);
[10641]1332}
1333
1334const char * AggregateAvg::getName()
1335{
1336 return "avg";
1337}
1338
[11180]1339ULONG AggregateMin::compute(ULONG *data, ULONG length)
[10641]1340{
[11180]1341 ULONG tmp = *data;
1342 for (ULONG i = 0; i < length; ++i)
[10713]1343 if (data[i] < tmp)
1344 tmp = data[i];
1345 return tmp;
[10641]1346}
1347
1348const char * AggregateMin::getName()
1349{
1350 return "min";
1351}
1352
[11180]1353ULONG AggregateMax::compute(ULONG *data, ULONG length)
[10641]1354{
[11180]1355 ULONG tmp = *data;
1356 for (ULONG i = 0; i < length; ++i)
[10713]1357 if (data[i] > tmp)
1358 tmp = data[i];
1359 return tmp;
[10641]1360}
1361
1362const char * AggregateMax::getName()
1363{
1364 return "max";
1365}
1366
[56587]1367Filter::Filter(const std::vector<com::Utf8Str> &metricNames,
1368 const std::vector<ComPtr<IUnknown> > &objects)
[10679]1369{
[56587]1370 if (!objects.size())
[12942]1371 {
[56587]1372 if (metricNames.size())
[12942]1373 {
[56587]1374 for (size_t i = 0; i < metricNames.size(); ++i)
1375 processMetricList(metricNames[i], ComPtr<IUnknown>());
[12942]1376 }
1377 else
[22173]1378 processMetricList("*", ComPtr<IUnknown>());
[10725]1379 }
1380 else
1381 {
[56587]1382 for (size_t i = 0; i < objects.size(); ++i)
1383 switch (metricNames.size())
[10725]1384 {
1385 case 0:
[56587]1386 processMetricList("*", objects[i]);
[10725]1387 break;
1388 case 1:
[56587]1389 processMetricList(metricNames[0], objects[i]);
[10725]1390 break;
1391 default:
[56587]1392 processMetricList(metricNames[i], objects[i]);
[10725]1393 break;
1394 }
1395 }
[10679]1396}
1397
[56587]1398Filter::Filter(const com::Utf8Str &name, const ComPtr<IUnknown> &aObject)
1399{
1400 processMetricList(name, aObject);
1401}
1402
[22173]1403void Filter::processMetricList(const com::Utf8Str &name, const ComPtr<IUnknown> object)
[10679]1404{
[22173]1405 size_t startPos = 0;
[10679]1406
[22173]1407 for (size_t pos = name.find(",");
[26122]1408 pos != com::Utf8Str::npos;
[10679]1409 pos = name.find(",", startPos))
1410 {
[36527]1411 mElements.push_back(std::make_pair(object, RTCString(name.substr(startPos, pos - startPos).c_str())));
[10679]1412 startPos = pos + 1;
1413 }
[36527]1414 mElements.push_back(std::make_pair(object, RTCString(name.substr(startPos).c_str())));
[10679]1415}
1416
[12802]1417/**
1418 * The following method was borrowed from stamR3Match (VMM/STAM.cpp) and
1419 * modified to handle the special case of trailing colon in the pattern.
1420 *
1421 * @returns True if matches, false if not.
1422 * @param pszPat Pattern.
1423 * @param pszName Name to match against the pattern.
1424 * @param fSeenColon Seen colon (':').
[12678]1425 */
1426bool Filter::patternMatch(const char *pszPat, const char *pszName,
1427 bool fSeenColon)
[11571]1428{
1429 /* ASSUMES ASCII */
1430 for (;;)
1431 {
1432 char chPat = *pszPat;
1433 switch (chPat)
1434 {
1435 default:
1436 if (*pszName != chPat)
1437 return false;
1438 break;
1439
1440 case '*':
1441 {
1442 while ((chPat = *++pszPat) == '*' || chPat == '?')
1443 /* nothing */;
1444
[12802]1445 /* Handle a special case, the mask terminating with a colon. */
[12678]1446 if (chPat == ':')
1447 {
[12802]1448 if (!fSeenColon && !pszPat[1])
[12678]1449 return !strchr(pszName, ':');
[12802]1450 fSeenColon = true;
[12678]1451 }
[12802]1452
[11571]1453 for (;;)
1454 {
1455 char ch = *pszName++;
1456 if ( ch == chPat
1457 && ( !chPat
[12802]1458 || patternMatch(pszPat + 1, pszName, fSeenColon)))
[11571]1459 return true;
1460 if (!ch)
1461 return false;
1462 }
1463 /* won't ever get here */
1464 break;
1465 }
1466
1467 case '?':
1468 if (!*pszName)
1469 return false;
1470 break;
1471
[12802]1472 /* Handle a special case, the mask terminating with a colon. */
1473 case ':':
1474 if (!fSeenColon && !pszPat[1])
1475 return !*pszName;
1476 if (*pszName != ':')
1477 return false;
1478 fSeenColon = true;
1479 break;
1480
[11571]1481 case '\0':
1482 return !*pszName;
1483 }
1484 pszName++;
1485 pszPat++;
1486 }
[63174]1487 /* not reached */
[11571]1488}
1489
[36527]1490bool Filter::match(const ComPtr<IUnknown> object, const RTCString &name) const
[10679]1491{
[10725]1492 ElementList::const_iterator it;
1493
[55988]1494 //Log7(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
[55769]1495 for (it = mElements.begin(); it != mElements.end(); ++it)
[10725]1496 {
[55988]1497 //Log7(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
[10725]1498 if ((*it).first.isNull() || (*it).first == object)
1499 {
1500 // Objects match, compare names
[11571]1501 if (patternMatch((*it).second.c_str(), name.c_str()))
[10725]1502 {
[43456]1503 //LogFlowThisFunc(("...found!\n"));
[10725]1504 return true;
1505 }
1506 }
1507 }
[55988]1508 //Log7(("...no matches!\n"));
[10725]1509 return false;
[10713]1510}
[14772]1511/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette