VirtualBox

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

Last change on this file since 90441 was 85273, checked in by vboxsync, 4 years ago

Main/PerformanceImpl.cpp: C++11 deprecated std::mem_fun -> std::mem_fn, hoping that's the right conversion... Some signed/unsigned conversion issues. bugref:9790

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