VirtualBox

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

Last change on this file since 73768 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use