VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/PerformanceImpl.cpp@ 106378

Last change on this file since 106378 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.2 KB
Line 
1/* $Id: PerformanceImpl.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Performance API COM Classes implementation
4 */
5
6/*
7 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
8 *
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
26 */
27
28/*
29 * Rules of engagement:
30 * 1) All performance objects must be destroyed by PerformanceCollector only!
31 * 2) All public methods of PerformanceCollector must be protected with
32 * read or write lock.
33 * 3) samplerCallback only uses the write lock during the third phase
34 * which pulls data into SubMetric objects. This is where object destruction
35 * and all list modifications are done. The pre-collection phases are
36 * run without any locks which is only possible because:
37 * 4) Public methods of PerformanceCollector as well as pre-collection methods
38 cannot modify lists or destroy objects, and:
39 * 5) Pre-collection methods cannot modify metric data.
40 */
41
42#define LOG_GROUP LOG_GROUP_MAIN_PERFORMANCECOLLECTOR
43#include "PerformanceImpl.h"
44
45#include "AutoCaller.h"
46#include "LoggingNew.h"
47
48#include <iprt/process.h>
49
50#include <VBox/err.h>
51#include <VBox/settings.h>
52
53#include <vector>
54#include <algorithm>
55#include <functional>
56
57#include "Performance.h"
58
59static const char *g_papcszMetricNames[] =
60{
61 "CPU/Load/User",
62 "CPU/Load/User:avg",
63 "CPU/Load/User:min",
64 "CPU/Load/User:max",
65 "CPU/Load/Kernel",
66 "CPU/Load/Kernel:avg",
67 "CPU/Load/Kernel:min",
68 "CPU/Load/Kernel:max",
69 "CPU/Load/Idle",
70 "CPU/Load/Idle:avg",
71 "CPU/Load/Idle:min",
72 "CPU/Load/Idle:max",
73 "CPU/MHz",
74 "CPU/MHz:avg",
75 "CPU/MHz:min",
76 "CPU/MHz:max",
77 "Net/*/Load/Rx",
78 "Net/*/Load/Rx:avg",
79 "Net/*/Load/Rx:min",
80 "Net/*/Load/Rx:max",
81 "Net/*/Load/Tx",
82 "Net/*/Load/Tx:avg",
83 "Net/*/Load/Tx:min",
84 "Net/*/Load/Tx:max",
85 "RAM/Usage/Total",
86 "RAM/Usage/Total:avg",
87 "RAM/Usage/Total:min",
88 "RAM/Usage/Total:max",
89 "RAM/Usage/Used",
90 "RAM/Usage/Used:avg",
91 "RAM/Usage/Used:min",
92 "RAM/Usage/Used:max",
93 "RAM/Usage/Free",
94 "RAM/Usage/Free:avg",
95 "RAM/Usage/Free:min",
96 "RAM/Usage/Free:max",
97 "RAM/VMM/Used",
98 "RAM/VMM/Used:avg",
99 "RAM/VMM/Used:min",
100 "RAM/VMM/Used:max",
101 "RAM/VMM/Free",
102 "RAM/VMM/Free:avg",
103 "RAM/VMM/Free:min",
104 "RAM/VMM/Free:max",
105 "RAM/VMM/Ballooned",
106 "RAM/VMM/Ballooned:avg",
107 "RAM/VMM/Ballooned:min",
108 "RAM/VMM/Ballooned:max",
109 "RAM/VMM/Shared",
110 "RAM/VMM/Shared:avg",
111 "RAM/VMM/Shared:min",
112 "RAM/VMM/Shared:max",
113 "Guest/CPU/Load/User",
114 "Guest/CPU/Load/User:avg",
115 "Guest/CPU/Load/User:min",
116 "Guest/CPU/Load/User:max",
117 "Guest/CPU/Load/Kernel",
118 "Guest/CPU/Load/Kernel:avg",
119 "Guest/CPU/Load/Kernel:min",
120 "Guest/CPU/Load/Kernel:max",
121 "Guest/CPU/Load/Idle",
122 "Guest/CPU/Load/Idle:avg",
123 "Guest/CPU/Load/Idle:min",
124 "Guest/CPU/Load/Idle:max",
125 "Guest/RAM/Usage/Total",
126 "Guest/RAM/Usage/Total:avg",
127 "Guest/RAM/Usage/Total:min",
128 "Guest/RAM/Usage/Total:max",
129 "Guest/RAM/Usage/Free",
130 "Guest/RAM/Usage/Free:avg",
131 "Guest/RAM/Usage/Free:min",
132 "Guest/RAM/Usage/Free:max",
133 "Guest/RAM/Usage/Balloon",
134 "Guest/RAM/Usage/Balloon:avg",
135 "Guest/RAM/Usage/Balloon:min",
136 "Guest/RAM/Usage/Balloon:max",
137 "Guest/RAM/Usage/Shared",
138 "Guest/RAM/Usage/Shared:avg",
139 "Guest/RAM/Usage/Shared:min",
140 "Guest/RAM/Usage/Shared:max",
141 "Guest/RAM/Usage/Cache",
142 "Guest/RAM/Usage/Cache:avg",
143 "Guest/RAM/Usage/Cache:min",
144 "Guest/RAM/Usage/Cache:max",
145 "Guest/Pagefile/Usage/Total",
146 "Guest/Pagefile/Usage/Total:avg",
147 "Guest/Pagefile/Usage/Total:min",
148 "Guest/Pagefile/Usage/Total:max",
149};
150
151////////////////////////////////////////////////////////////////////////////////
152// PerformanceCollector class
153////////////////////////////////////////////////////////////////////////////////
154
155// constructor / destructor
156////////////////////////////////////////////////////////////////////////////////
157
158PerformanceCollector::PerformanceCollector()
159 : mMagic(0), mUnknownGuest("unknown guest")
160{
161}
162
163PerformanceCollector::~PerformanceCollector() {}
164
165HRESULT PerformanceCollector::FinalConstruct()
166{
167 LogFlowThisFunc(("\n"));
168
169 return BaseFinalConstruct();
170}
171
172void PerformanceCollector::FinalRelease()
173{
174 LogFlowThisFunc(("\n"));
175 BaseFinalRelease();
176}
177
178// public initializer/uninitializer for internal purposes only
179////////////////////////////////////////////////////////////////////////////////
180
181/**
182 * Initializes the PerformanceCollector object.
183 */
184HRESULT PerformanceCollector::init()
185{
186 /* Enclose the state transition NotReady->InInit->Ready */
187 AutoInitSpan autoInitSpan(this);
188 AssertReturn(autoInitSpan.isOk(), E_FAIL);
189
190 LogFlowThisFuncEnter();
191
192 HRESULT hrc = S_OK;
193
194 m.hal = pm::createHAL();
195 m.gm = new pm::CollectorGuestManager;
196
197 /* Let the sampler know it gets a valid collector. */
198 mMagic = PERFORMANCE_METRIC_MAGIC;
199
200 /* Start resource usage sampler */
201 int vrc = RTTimerLRCreate(&m.sampler, VBOX_USAGE_SAMPLER_MIN_INTERVAL,
202 &PerformanceCollector::staticSamplerCallback, this);
203 AssertMsgRC(vrc, ("Failed to create resource usage sampling timer(%Rra)\n", vrc));
204 if (RT_FAILURE(vrc))
205 hrc = E_FAIL;
206
207 if (SUCCEEDED(hrc))
208 autoInitSpan.setSucceeded();
209
210 LogFlowThisFuncLeave();
211
212 return hrc;
213}
214
215/**
216 * Uninitializes the PerformanceCollector object.
217 *
218 * Called either from FinalRelease() or by the parent when it gets destroyed.
219 */
220void PerformanceCollector::uninit()
221{
222 LogFlowThisFuncEnter();
223
224 /* Enclose the state transition Ready->InUninit->NotReady */
225 AutoUninitSpan autoUninitSpan(this);
226 if (autoUninitSpan.uninitDone())
227 {
228 LogFlowThisFunc(("Already uninitialized.\n"));
229 LogFlowThisFuncLeave();
230 return;
231 }
232
233 /* Destroy resource usage sampler first, as the callback will access the metrics. */
234 int vrc = RTTimerLRDestroy(m.sampler);
235 AssertMsgRC(vrc, ("Failed to destroy resource usage sampling timer (%Rra)\n", vrc));
236 m.sampler = NULL;
237
238 /* Destroy unregistered metrics */
239 BaseMetricList::iterator it;
240 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();)
241 if ((*it)->isUnregistered())
242 {
243 delete *it;
244 it = m.baseMetrics.erase(it);
245 }
246 else
247 ++it;
248 Assert(m.baseMetrics.size() == 0);
249 /*
250 * Now when we have destroyed all base metrics that could
251 * try to pull data from unregistered CollectorGuest objects
252 * it is safe to destroy them as well.
253 */
254 m.gm->destroyUnregistered();
255
256 /* Invalidate the magic now. */
257 mMagic = 0;
258
259 //delete m.factory;
260 //m.factory = NULL;
261
262 delete m.gm;
263 m.gm = NULL;
264 delete m.hal;
265 m.hal = NULL;
266
267 LogFlowThisFuncLeave();
268}
269
270// IPerformanceCollector properties
271////////////////////////////////////////////////////////////////////////////////
272
273HRESULT PerformanceCollector::getMetricNames(std::vector<com::Utf8Str> &aMetricNames)
274{
275 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
276
277 aMetricNames.resize(RT_ELEMENTS(g_papcszMetricNames));
278 for (size_t i = 0; i < RT_ELEMENTS(g_papcszMetricNames); i++)
279 aMetricNames[i] = g_papcszMetricNames[i];
280
281 return S_OK;
282}
283
284// IPerformanceCollector methods
285////////////////////////////////////////////////////////////////////////////////
286
287HRESULT PerformanceCollector::toIPerformanceMetric(pm::Metric *src, ComPtr<IPerformanceMetric> &dst)
288{
289 ComObjPtr<PerformanceMetric> metric;
290 HRESULT hrc = metric.createObject();
291 if (SUCCEEDED(hrc))
292 hrc = metric->init(src);
293 AssertComRCReturnRC(hrc);
294 dst = metric;
295 return hrc;
296}
297
298HRESULT PerformanceCollector::toIPerformanceMetric(pm::BaseMetric *src, ComPtr<IPerformanceMetric> &dst)
299{
300 ComObjPtr<PerformanceMetric> metric;
301 HRESULT hrc = metric.createObject();
302 if (SUCCEEDED(hrc))
303 hrc = metric->init(src);
304 AssertComRCReturnRC(hrc);
305 dst = metric;
306 return hrc;
307}
308
309const Utf8Str& PerformanceCollector::getFailedGuestName()
310{
311 pm::CollectorGuest *pGuest = m.gm->getBlockedGuest();
312 if (pGuest)
313 return pGuest->getVMName();
314 return mUnknownGuest;
315}
316
317HRESULT PerformanceCollector::getMetrics(const std::vector<com::Utf8Str> &aMetricNames,
318 const std::vector<ComPtr<IUnknown> > &aObjects,
319 std::vector<ComPtr<IPerformanceMetric> > &aMetrics)
320{
321 HRESULT hrc = S_OK;
322
323 pm::Filter filter(aMetricNames, aObjects);
324
325 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
326
327 MetricList filteredMetrics;
328 MetricList::iterator it;
329 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
330 if (filter.match((*it)->getObject(), (*it)->getName()))
331 filteredMetrics.push_back(*it);
332
333 aMetrics.resize(filteredMetrics.size());
334 size_t i = 0;
335 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
336 {
337 ComObjPtr<PerformanceMetric> metric;
338 hrc = metric.createObject();
339 if (SUCCEEDED(hrc))
340 hrc = metric->init(*it);
341 AssertComRCReturnRC(hrc);
342 LogFlow(("PerformanceCollector::GetMetrics() store a metric at retMetrics[%zu]...\n", i));
343 aMetrics[i++] = metric;
344 }
345 return hrc;
346}
347
348HRESULT PerformanceCollector::setupMetrics(const std::vector<com::Utf8Str> &aMetricNames,
349 const std::vector<ComPtr<IUnknown> > &aObjects,
350 ULONG aPeriod,
351 ULONG aCount,
352 std::vector<ComPtr<IPerformanceMetric> > &aAffectedMetrics)
353{
354 pm::Filter filter(aMetricNames, aObjects);
355
356 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
357
358 HRESULT hrc = S_OK;
359 BaseMetricList filteredMetrics;
360 BaseMetricList::iterator it;
361 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
362 if (filter.match((*it)->getObject(), (*it)->getName()))
363 {
364 LogFlow(("PerformanceCollector::SetupMetrics() setting period to %u, count to %u for %s\n",
365 aPeriod, aCount, (*it)->getName()));
366 (*it)->init(aPeriod, aCount);
367 if (aPeriod == 0 || aCount == 0)
368 {
369 LogFlow(("PerformanceCollector::SetupMetrics() disabling %s\n",
370 (*it)->getName()));
371 hrc = (*it)->disable();
372 if (FAILED(hrc))
373 break;
374 }
375 else
376 {
377 LogFlow(("PerformanceCollector::SetupMetrics() enabling %s\n",
378 (*it)->getName()));
379 hrc = (*it)->enable();
380 if (FAILED(hrc))
381 break;
382 }
383 filteredMetrics.push_back(*it);
384 }
385
386 aAffectedMetrics.resize(filteredMetrics.size());
387 size_t i = 0;
388 for (it = filteredMetrics.begin();
389 it != filteredMetrics.end() && SUCCEEDED(hrc); ++it)
390 hrc = toIPerformanceMetric(*it, aAffectedMetrics[i++]);
391
392 if (FAILED(hrc))
393 return setError(E_FAIL, tr("Failed to setup metrics for '%s'"),
394 getFailedGuestName().c_str());
395 return hrc;
396}
397
398HRESULT PerformanceCollector::enableMetrics(const std::vector<com::Utf8Str> &aMetricNames,
399 const std::vector<ComPtr<IUnknown> > &aObjects,
400 std::vector<ComPtr<IPerformanceMetric> > &aAffectedMetrics)
401{
402 pm::Filter filter(aMetricNames, aObjects);
403
404 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Write lock is not needed atm since we are */
405 /* fiddling with enable bit only, but we */
406 /* care for those who come next :-). */
407
408 HRESULT hrc = S_OK;
409 BaseMetricList filteredMetrics;
410 BaseMetricList::iterator it;
411 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
412 if (filter.match((*it)->getObject(), (*it)->getName()))
413 {
414 hrc = (*it)->enable();
415 if (FAILED(hrc))
416 break;
417 filteredMetrics.push_back(*it);
418 }
419
420 aAffectedMetrics.resize(filteredMetrics.size());
421 size_t i = 0;
422 for (it = filteredMetrics.begin();
423 it != filteredMetrics.end() && SUCCEEDED(hrc); ++it)
424 hrc = toIPerformanceMetric(*it, aAffectedMetrics[i++]);
425
426 LogFlowThisFuncLeave();
427
428 if (FAILED(hrc))
429 return setError(E_FAIL, tr("Failed to enable metrics for '%s'"),
430 getFailedGuestName().c_str());
431 return hrc;
432}
433
434HRESULT PerformanceCollector::disableMetrics(const std::vector<com::Utf8Str> &aMetricNames,
435 const std::vector<ComPtr<IUnknown> > &aObjects,
436 std::vector<ComPtr<IPerformanceMetric> > &aAffectedMetrics)
437{
438 pm::Filter filter(aMetricNames, aObjects);
439
440 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Write lock is not needed atm since we are */
441 /* fiddling with enable bit only, but we */
442 /* care for those who come next :-). */
443
444 HRESULT hrc = S_OK;
445 BaseMetricList filteredMetrics;
446 BaseMetricList::iterator it;
447 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
448 if (filter.match((*it)->getObject(), (*it)->getName()))
449 {
450 hrc = (*it)->disable();
451 if (FAILED(hrc))
452 break;
453 filteredMetrics.push_back(*it);
454 }
455
456 aAffectedMetrics.resize(filteredMetrics.size());
457 size_t i = 0;
458 for (it = filteredMetrics.begin();
459 it != filteredMetrics.end() && SUCCEEDED(hrc); ++it)
460 hrc = toIPerformanceMetric(*it, aAffectedMetrics[i++]);
461
462 LogFlowThisFuncLeave();
463
464 if (FAILED(hrc))
465 return setError(E_FAIL, tr("Failed to disable metrics for '%s'"),
466 getFailedGuestName().c_str());
467 return hrc;
468}
469
470HRESULT PerformanceCollector::queryMetricsData(const std::vector<com::Utf8Str> &aMetricNames,
471 const std::vector<ComPtr<IUnknown> > &aObjects,
472 std::vector<com::Utf8Str> &aReturnMetricNames,
473 std::vector<ComPtr<IUnknown> > &aReturnObjects,
474 std::vector<com::Utf8Str> &aReturnUnits,
475 std::vector<ULONG> &aReturnScales,
476 std::vector<ULONG> &aReturnSequenceNumbers,
477 std::vector<ULONG> &aReturnDataIndices,
478 std::vector<ULONG> &aReturnDataLengths,
479 std::vector<LONG> &aReturnData)
480{
481 pm::Filter filter(aMetricNames, aObjects);
482
483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
484
485 /* Let's compute the size of the resulting flat array */
486 size_t flatSize = 0;
487 MetricList filteredMetrics;
488 MetricList::iterator it;
489 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
490 if (filter.match((*it)->getObject(), (*it)->getName()))
491 {
492 filteredMetrics.push_back(*it);
493 flatSize += (*it)->getLength();
494 }
495
496 size_t flatIndex = 0;
497 size_t numberOfMetrics = filteredMetrics.size();
498 aReturnMetricNames.resize(numberOfMetrics);
499 aReturnObjects.resize(numberOfMetrics);
500 aReturnUnits.resize(numberOfMetrics);
501 aReturnScales.resize(numberOfMetrics);
502 aReturnSequenceNumbers.resize(numberOfMetrics);
503 aReturnDataIndices.resize(numberOfMetrics);
504 aReturnDataLengths.resize(numberOfMetrics);
505 aReturnData.resize(flatSize);
506
507 size_t i = 0;
508 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it, ++i)
509 {
510 ULONG *values, length, sequenceNumber;
511 /** @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
512 (*it)->query(&values, &length, &sequenceNumber);
513 LogFlow(("PerformanceCollector::QueryMetricsData() querying metric %s returned %d values.\n",
514 (*it)->getName(), length));
515 memcpy(&aReturnData[flatIndex], values, length * sizeof(*values));
516 RTMemFree(values);
517 aReturnMetricNames[i] = (*it)->getName();
518 aReturnObjects[i] = (*it)->getObject();
519 aReturnUnits[i] = (*it)->getUnit();
520 aReturnScales[i] = (*it)->getScale();
521 aReturnSequenceNumbers[i] = sequenceNumber;
522 aReturnDataIndices[i] = (ULONG)flatIndex;
523 aReturnDataLengths[i] = length;
524 flatIndex += length;
525 }
526
527 return S_OK;
528}
529
530// public methods for internal purposes
531///////////////////////////////////////////////////////////////////////////////
532
533void PerformanceCollector::registerBaseMetric(pm::BaseMetric *baseMetric)
534{
535 //LogFlowThisFuncEnter();
536 AutoCaller autoCaller(this);
537 if (!SUCCEEDED(autoCaller.hrc())) return;
538
539 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
540 Log7Func(("{%p}: obj=%p name=%s\n", this, (void *)baseMetric->getObject(), baseMetric->getName()));
541 m.baseMetrics.push_back(baseMetric);
542 //LogFlowThisFuncLeave();
543}
544
545void PerformanceCollector::registerMetric(pm::Metric *metric)
546{
547 //LogFlowThisFuncEnter();
548 AutoCaller autoCaller(this);
549 if (!SUCCEEDED(autoCaller.hrc())) return;
550
551 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
552 Log7Func(("{%p}: obj=%p name=%s\n", this, (void *)metric->getObject(), metric->getName()));
553 m.metrics.push_back(metric);
554 //LogFlowThisFuncLeave();
555}
556
557void PerformanceCollector::unregisterBaseMetricsFor(const ComPtr<IUnknown> &aObject, const Utf8Str name)
558{
559 //LogFlowThisFuncEnter();
560 AutoCaller autoCaller(this);
561 if (!SUCCEEDED(autoCaller.hrc())) return;
562
563 pm::Filter filter(name, aObject);
564
565 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
566#ifdef LOG_ENABLED
567 int n = 0;
568#endif
569 BaseMetricList::iterator it;
570 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
571 if (filter.match((*it)->getObject(), (*it)->getName()))
572 {
573 (*it)->unregister();
574#ifdef LOG_ENABLED
575 ++n;
576#endif
577 }
578 Log7Func(("{%p}: obj=%p, name=%s, marked %d metrics\n", this, (void *)aObject, name.c_str(), n));
579 //LogFlowThisFuncLeave();
580}
581
582void PerformanceCollector::unregisterMetricsFor(const ComPtr<IUnknown> &aObject, const Utf8Str name)
583{
584 //LogFlowThisFuncEnter();
585 AutoCaller autoCaller(this);
586 if (!SUCCEEDED(autoCaller.hrc())) return;
587
588 pm::Filter filter(name, aObject);
589
590 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
591 Log7Func(("{%p}: obj=%p, name=%s\n", this, (void *)aObject, name.c_str()));
592 MetricList::iterator it;
593 for (it = m.metrics.begin(); it != m.metrics.end();)
594 if (filter.match((*it)->getObject(), (*it)->getName()))
595 {
596 delete *it;
597 it = m.metrics.erase(it);
598 }
599 else
600 ++it;
601 //LogFlowThisFuncLeave();
602}
603
604void PerformanceCollector::registerGuest(pm::CollectorGuest* pGuest)
605{
606 AutoCaller autoCaller(this);
607 if (!SUCCEEDED(autoCaller.hrc())) return;
608
609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
610 m.gm->registerGuest(pGuest);
611}
612
613void PerformanceCollector::unregisterGuest(pm::CollectorGuest* pGuest)
614{
615 AutoCaller autoCaller(this);
616 if (!SUCCEEDED(autoCaller.hrc())) return;
617
618 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
619 m.gm->unregisterGuest(pGuest);
620}
621
622void PerformanceCollector::suspendSampling()
623{
624 AutoCaller autoCaller(this);
625 if (!SUCCEEDED(autoCaller.hrc())) return;
626
627 int vrc = RTTimerLRStop(m.sampler);
628 if ( RT_FAILURE(vrc)
629 && vrc != VERR_TIMER_SUSPENDED) /* calling suspendSampling() successively shouldn't assert. See @bugref{3495}. */
630 AssertMsgFailed(("PerformanceCollector::suspendSampling(): RTTimerLRStop returned %Rrc\n", vrc));
631}
632
633void PerformanceCollector::resumeSampling()
634{
635 AutoCaller autoCaller(this);
636 if (!SUCCEEDED(autoCaller.hrc())) return;
637
638 int vrc = RTTimerLRStart(m.sampler, 0);
639 if ( RT_FAILURE(vrc)
640 && vrc != VERR_TIMER_ACTIVE) /* calling resumeSampling() successively shouldn't assert. See @bugref{3495}. */
641 AssertMsgFailed(("PerformanceCollector::resumeSampling(): RTTimerLRStart returned %Rrc\n", vrc));
642}
643
644
645// private methods
646///////////////////////////////////////////////////////////////////////////////
647
648/* static */
649DECLCALLBACK(void) PerformanceCollector::staticSamplerCallback(RTTIMERLR hTimerLR, void *pvUser,
650 uint64_t iTick)
651{
652 AssertReturnVoid(pvUser != NULL);
653 PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
654 Assert(collector->mMagic == PERFORMANCE_METRIC_MAGIC);
655 if (collector->mMagic == PERFORMANCE_METRIC_MAGIC)
656 collector->samplerCallback(iTick);
657
658 NOREF(hTimerLR);
659}
660
661/*
662 * Metrics collection is a three stage process:
663 * 1) Pre-collection (hinting)
664 * At this stage we compose the list of all metrics to be collected
665 * If any metrics cannot be collected separately or if it is more
666 * efficient to collect several metric at once, these metrics should
667 * use hints to mark that they will need to be collected.
668 * 2) Pre-collection (bulk)
669 * Using hints set at stage 1 platform-specific HAL
670 * instance collects all marked host-related metrics.
671 * Hinted guest-related metrics then get collected by CollectorGuestManager.
672 * 3) Collection
673 * Metrics that are collected individually get collected and stored. Values
674 * saved in HAL and CollectorGuestManager are extracted and stored to
675 * individual metrics.
676 */
677void PerformanceCollector::samplerCallback(uint64_t iTick)
678{
679 Log4Func(("{%p}: ENTER\n", this));
680 /* No locking until stage 3!*/
681
682 pm::CollectorHints hints;
683 uint64_t timestamp = RTTimeMilliTS();
684 BaseMetricList toBeCollected;
685 BaseMetricList::iterator it;
686 /* Compose the list of metrics being collected at this moment */
687 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
688 if ((*it)->collectorBeat(timestamp))
689 {
690 (*it)->preCollect(hints, iTick);
691 toBeCollected.push_back(*it);
692 }
693
694 if (toBeCollected.size() == 0)
695 {
696 Log4Func(("{%p}: LEAVE (nothing to collect)\n", this));
697 return;
698 }
699
700 /* Let know the platform specific code what is being collected */
701 m.hal->preCollect(hints, iTick);
702#if 0
703 /* Guest stats are now pushed by guests themselves */
704 /* Collect the data in bulk from all hinted guests */
705 m.gm->preCollect(hints, iTick);
706#endif
707
708 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
709 /*
710 * Before we can collect data we need to go through both lists
711 * again to see if any base metrics are marked as unregistered.
712 * Those should be destroyed now.
713 */
714 Log7Func(("{%p}: before remove_if: toBeCollected.size()=%d\n", this, toBeCollected.size()));
715#if RT_CPLUSPLUS_PREREQ(201100) /* mem_fun is deprecated in C++11 and removed in C++17 */
716 toBeCollected.remove_if(std::mem_fn(&pm::BaseMetric::isUnregistered));
717#else
718 toBeCollected.remove_if(std::mem_fun(&pm::BaseMetric::isUnregistered));
719#endif
720 Log7Func(("{%p}: after remove_if: toBeCollected.size()=%d\n", this, toBeCollected.size()));
721 Log7Func(("{%p}: before remove_if: m.baseMetrics.size()=%d\n", this, m.baseMetrics.size()));
722 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end();)
723 if ((*it)->isUnregistered())
724 {
725 delete *it;
726 it = m.baseMetrics.erase(it);
727 }
728 else
729 ++it;
730 Log7Func(("{%p}: after remove_if: m.baseMetrics.size()=%d\n", this, m.baseMetrics.size()));
731 /*
732 * Now when we have destroyed all base metrics that could
733 * try to pull data from unregistered CollectorGuest objects
734 * it is safe to destroy them as well.
735 */
736 m.gm->destroyUnregistered();
737
738 /* Finally, collect the data */
739#if RT_CPLUSPLUS_PREREQ(201100) /* mem_fun is deprecated in C++11 and removed in C++17 */
740 std::for_each(toBeCollected.begin(), toBeCollected.end(), std::mem_fn(&pm::BaseMetric::collect));
741#else
742 std::for_each(toBeCollected.begin(), toBeCollected.end(), std::mem_fun(&pm::BaseMetric::collect));
743#endif
744 Log4Func(("{%p}: LEAVE\n", this));
745}
746
747////////////////////////////////////////////////////////////////////////////////
748// PerformanceMetric class
749////////////////////////////////////////////////////////////////////////////////
750
751// constructor / destructor
752////////////////////////////////////////////////////////////////////////////////
753
754PerformanceMetric::PerformanceMetric()
755{
756}
757
758PerformanceMetric::~PerformanceMetric()
759{
760}
761
762HRESULT PerformanceMetric::FinalConstruct()
763{
764 LogFlowThisFunc(("\n"));
765
766 return BaseFinalConstruct();
767}
768
769void PerformanceMetric::FinalRelease()
770{
771 LogFlowThisFunc(("\n"));
772
773 uninit();
774
775 BaseFinalRelease();
776}
777
778// public initializer/uninitializer for internal purposes only
779////////////////////////////////////////////////////////////////////////////////
780
781HRESULT PerformanceMetric::init(pm::Metric *aMetric)
782{
783 /* Enclose the state transition NotReady->InInit->Ready */
784 AutoInitSpan autoInitSpan(this);
785 AssertReturn(autoInitSpan.isOk(), E_FAIL);
786
787 m.name = aMetric->getName();
788 m.object = aMetric->getObject();
789 m.description = aMetric->getDescription();
790 m.period = aMetric->getPeriod();
791 m.count = aMetric->getLength();
792 m.unit = aMetric->getUnit();
793 /** @todo r=bird: LONG/ULONG mixup. */
794 m.min = (LONG)aMetric->getMinValue();
795 m.max = (LONG)aMetric->getMaxValue();
796
797 autoInitSpan.setSucceeded();
798 return S_OK;
799}
800
801HRESULT PerformanceMetric::init(pm::BaseMetric *aMetric)
802{
803 /* Enclose the state transition NotReady->InInit->Ready */
804 AutoInitSpan autoInitSpan(this);
805 AssertReturn(autoInitSpan.isOk(), E_FAIL);
806
807 m.name = aMetric->getName();
808 m.object = aMetric->getObject();
809 m.description = "";
810 m.period = aMetric->getPeriod();
811 m.count = aMetric->getLength();
812 m.unit = aMetric->getUnit();
813 /** @todo r=bird: LONG/ULONG mixup. */
814 m.min = (LONG)aMetric->getMinValue();
815 m.max = (LONG)aMetric->getMaxValue();
816
817 autoInitSpan.setSucceeded();
818 return S_OK;
819}
820
821void PerformanceMetric::uninit()
822{
823 /* Enclose the state transition Ready->InUninit->NotReady */
824 AutoUninitSpan autoUninitSpan(this);
825 if (autoUninitSpan.uninitDone())
826 {
827 LogFlowThisFunc(("Already uninitialized.\n"));
828 LogFlowThisFuncLeave();
829 return;
830 }
831}
832
833HRESULT PerformanceMetric::getMetricName(com::Utf8Str &aMetricName)
834{
835 /* this is const, no need to lock */
836 aMetricName = m.name;
837 return S_OK;
838}
839
840HRESULT PerformanceMetric::getObject(ComPtr<IUnknown> &aObject)
841{
842 /* this is const, no need to lock */
843 aObject = m.object;
844 return S_OK;
845}
846
847HRESULT PerformanceMetric::getDescription(com::Utf8Str &aDescription)
848{
849 /* this is const, no need to lock */
850 aDescription = m.description;
851 return S_OK;
852}
853
854HRESULT PerformanceMetric::getPeriod(ULONG *aPeriod)
855{
856 /* this is const, no need to lock */
857 *aPeriod = m.period;
858 return S_OK;
859}
860
861HRESULT PerformanceMetric::getCount(ULONG *aCount)
862{
863 /* this is const, no need to lock */
864 *aCount = m.count;
865 return S_OK;
866}
867
868HRESULT PerformanceMetric::getUnit(com::Utf8Str &aUnit)
869{
870 /* this is const, no need to lock */
871 aUnit = m.unit;
872 return S_OK;
873}
874
875HRESULT PerformanceMetric::getMinimumValue(LONG *aMinimumValue)
876{
877 /* this is const, no need to lock */
878 *aMinimumValue = m.min;
879 return S_OK;
880}
881
882HRESULT PerformanceMetric::getMaximumValue(LONG *aMaximumValue)
883{
884 /* this is const, no need to lock */
885 *aMaximumValue = m.max;
886 return S_OK;
887}
888/* 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