VirtualBox

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

Last change on this file since 40358 was 40358, checked in by vboxsync, 13 years ago

Main/Metrics: All calls to VM processes are done in separate thread (#6029)

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