VirtualBox

source: vbox/trunk/src/VBox/Main/PerformanceImpl.cpp@ 12610

Last change on this file since 12610 was 12461, checked in by vboxsync, 17 years ago

PerfAPI: Do not call preCollect if no metrics are to be collected. Could this help with memory leak problem?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.7 KB
Line 
1/* $Id: PerformanceImpl.cpp 12461 2008-09-15 13:05:51Z vboxsync $ */
2
3/** @file
4 *
5 * VBox Performance API COM Classes implementation
6 */
7
8/*
9 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#if defined(RT_OS_WINDOWS)
25#elif defined(RT_OS_LINUX)
26#endif
27
28#include "PerformanceImpl.h"
29
30#include "Logging.h"
31
32#include <VBox/err.h>
33#include <iprt/process.h>
34
35#include <vector>
36#include <algorithm>
37#include <functional>
38
39static Bstr gMetricNames[] =
40{
41 "CPU/Load/User",
42 "CPU/Load/User:avg",
43 "CPU/Load/User:min",
44 "CPU/Load/User:max",
45 "CPU/Load/Kernel",
46 "CPU/Load/Kernel:avg",
47 "CPU/Load/Kernel:min",
48 "CPU/Load/Kernel:max",
49 "CPU/Load/Idle",
50 "CPU/Load/Idle:avg",
51 "CPU/Load/Idle:min",
52 "CPU/Load/Idle:max",
53 "CPU/MHz",
54 "CPU/MHz:avg",
55 "CPU/MHz:min",
56 "CPU/MHz:max",
57 "RAM/Usage/Total",
58 "RAM/Usage/Total:avg",
59 "RAM/Usage/Total:min",
60 "RAM/Usage/Total:max",
61 "RAM/Usage/Used",
62 "RAM/Usage/Used:avg",
63 "RAM/Usage/Used:min",
64 "RAM/Usage/Used:max",
65 "RAM/Usage/Free",
66 "RAM/Usage/Free:avg",
67 "RAM/Usage/Free:min",
68 "RAM/Usage/Free:max",
69};
70
71////////////////////////////////////////////////////////////////////////////////
72// PerformanceCollector class
73////////////////////////////////////////////////////////////////////////////////
74
75// constructor / destructor
76////////////////////////////////////////////////////////////////////////////////
77
78PerformanceCollector::PerformanceCollector() : mMagic(0) {}
79
80PerformanceCollector::~PerformanceCollector() {}
81
82HRESULT PerformanceCollector::FinalConstruct()
83{
84 LogFlowThisFunc (("\n"));
85
86 return S_OK;
87}
88
89void PerformanceCollector::FinalRelease()
90{
91 LogFlowThisFunc (("\n"));
92}
93
94// public initializer/uninitializer for internal purposes only
95////////////////////////////////////////////////////////////////////////////////
96
97/**
98 * Initializes the PerformanceCollector object.
99 */
100HRESULT PerformanceCollector::init()
101{
102 /* Enclose the state transition NotReady->InInit->Ready */
103 AutoInitSpan autoInitSpan (this);
104 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
105
106 LogFlowThisFuncEnter();
107
108 HRESULT rc = S_OK;
109
110 m.hal = pm::createHAL();
111
112 /* Let the sampler know it gets a valid collector. */
113 mMagic = MAGIC;
114
115 /* Start resource usage sampler */
116 int vrc = RTTimerLRCreate (&m.sampler, VBOX_USAGE_SAMPLER_MIN_INTERVAL,
117 &PerformanceCollector::staticSamplerCallback, this);
118 AssertMsgRC (vrc, ("Failed to create resource usage "
119 "sampling timer(%Rra)\n", vrc));
120 if (RT_FAILURE (vrc))
121 rc = E_FAIL;
122
123 if (SUCCEEDED (rc))
124 autoInitSpan.setSucceeded();
125
126 LogFlowThisFuncLeave();
127
128 return rc;
129}
130
131/**
132 * Uninitializes the PerformanceCollector object.
133 *
134 * Called either from FinalRelease() or by the parent when it gets destroyed.
135 */
136void PerformanceCollector::uninit()
137{
138 LogFlowThisFuncEnter();
139
140 /* Enclose the state transition Ready->InUninit->NotReady */
141 AutoUninitSpan autoUninitSpan (this);
142 if (autoUninitSpan.uninitDone())
143 {
144 LogFlowThisFunc (("Already uninitialized.\n"));
145 LogFlowThisFuncLeave();
146 return;
147 }
148
149 mMagic = 0;
150
151 /* Destroy resource usage sampler */
152 int vrc = RTTimerLRDestroy (m.sampler);
153 AssertMsgRC (vrc, ("Failed to destroy resource usage "
154 "sampling timer (%Rra)\n", vrc));
155 m.sampler = NULL;
156
157 //delete m.factory;
158 //m.factory = NULL;
159
160 delete m.hal;
161 m.hal = NULL;
162
163 LogFlowThisFuncLeave();
164}
165
166// IPerformanceCollector properties
167////////////////////////////////////////////////////////////////////////////////
168
169STDMETHODIMP
170PerformanceCollector::COMGETTER(MetricNames) (ComSafeArrayOut (BSTR, theMetricNames))
171{
172 if (ComSafeArrayOutIsNull (theMetricNames))
173 return E_POINTER;
174
175 AutoCaller autoCaller (this);
176 CheckComRCReturnRC (autoCaller.rc());
177
178 AutoReadLock alock (this);
179
180 com::SafeArray <BSTR> metricNames(RT_ELEMENTS(gMetricNames));
181 for (size_t i = 0; i < RT_ELEMENTS(gMetricNames); i++)
182 {
183 gMetricNames[i].detachTo(&metricNames[i]);
184 }
185 //gMetricNames.detachTo(ComSafeArrayOutArg (theMetricNames));
186 metricNames.detachTo (ComSafeArrayOutArg (theMetricNames));
187
188 return S_OK;
189}
190
191// IPerformanceCollector methods
192////////////////////////////////////////////////////////////////////////////////
193
194STDMETHODIMP
195PerformanceCollector::GetMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
196 ComSafeArrayIn (IUnknown *, objects),
197 ComSafeArrayOut (IPerformanceMetric *, outMetrics))
198{
199 LogFlowThisFuncEnter();
200 //LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
201
202 HRESULT rc = S_OK;
203
204 AutoCaller autoCaller (this);
205 CheckComRCReturnRC (autoCaller.rc());
206
207 pm::Filter filter (ComSafeArrayInArg (metricNames),
208 ComSafeArrayInArg (objects));
209
210 AutoReadLock alock (this);
211
212 MetricList filteredMetrics;
213 MetricList::iterator it;
214 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
215 if (filter.match ((*it)->getObject(), (*it)->getName()))
216 filteredMetrics.push_back (*it);
217
218 com::SafeIfaceArray<IPerformanceMetric> retMetrics (filteredMetrics.size());
219 int i = 0;
220 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
221 {
222 ComObjPtr <PerformanceMetric> metric;
223 rc = metric.createObject();
224 if (SUCCEEDED (rc))
225 rc = metric->init (*it);
226 AssertComRCReturnRC (rc);
227 LogFlow (("PerformanceCollector::GetMetrics() store a metric at "
228 "retMetrics[%d]...\n", i));
229 metric.queryInterfaceTo (&retMetrics [i++]);
230 }
231 retMetrics.detachTo (ComSafeArrayOutArg(outMetrics));
232 LogFlowThisFuncLeave();
233 return rc;
234}
235
236STDMETHODIMP
237PerformanceCollector::SetupMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
238 ComSafeArrayIn (IUnknown *, objects),
239 ULONG aPeriod, ULONG aCount)
240{
241 AutoCaller autoCaller (this);
242 CheckComRCReturnRC (autoCaller.rc());
243
244 pm::Filter filter (ComSafeArrayInArg (metricNames),
245 ComSafeArrayInArg (objects));
246
247 AutoWriteLock alock (this);
248
249 BaseMetricList::iterator it;
250 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
251 if (filter.match((*it)->getObject(), (*it)->getName()))
252 {
253 LogFlow (("PerformanceCollector::SetupMetrics() setting period to %u,"
254 " count to %u for %s\n", aPeriod, aCount, (*it)->getName()));
255 (*it)->init(aPeriod, aCount);
256 if (aPeriod == 0 || aCount == 0)
257 {
258 LogFlow (("PerformanceCollector::SetupMetrics() disabling %s\n",
259 (*it)->getName()));
260 (*it)->disable();
261 }
262 else
263 {
264 LogFlow (("PerformanceCollector::SetupMetrics() enabling %s\n",
265 (*it)->getName()));
266 (*it)->enable();
267 }
268 }
269
270 return S_OK;
271}
272
273STDMETHODIMP
274PerformanceCollector::EnableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
275 ComSafeArrayIn (IUnknown *, objects))
276{
277 AutoCaller autoCaller (this);
278 CheckComRCReturnRC (autoCaller.rc());
279
280 pm::Filter filter (ComSafeArrayInArg (metricNames),
281 ComSafeArrayInArg (objects));
282
283 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
284 /* fiddling with enable bit only, but we */
285 /* care for those who come next :-). */
286
287 BaseMetricList::iterator it;
288 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
289 if (filter.match((*it)->getObject(), (*it)->getName()))
290 (*it)->enable();
291
292 return S_OK;
293}
294
295STDMETHODIMP
296PerformanceCollector::DisableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
297 ComSafeArrayIn (IUnknown *, objects))
298{
299 AutoCaller autoCaller (this);
300 CheckComRCReturnRC (autoCaller.rc());
301
302 pm::Filter filter (ComSafeArrayInArg (metricNames),
303 ComSafeArrayInArg (objects));
304
305 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
306 /* fiddling with enable bit only, but we */
307 /* care for those who come next :-). */
308
309 BaseMetricList::iterator it;
310 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
311 if (filter.match((*it)->getObject(), (*it)->getName()))
312 (*it)->disable();
313
314 return S_OK;
315}
316
317STDMETHODIMP
318PerformanceCollector::QueryMetricsData (ComSafeArrayIn (INPTR BSTR, metricNames),
319 ComSafeArrayIn (IUnknown *, objects),
320 ComSafeArrayOut (BSTR, outMetricNames),
321 ComSafeArrayOut (IUnknown *, outObjects),
322 ComSafeArrayOut (ULONG, outDataIndices),
323 ComSafeArrayOut (ULONG, outDataLengths),
324 ComSafeArrayOut (LONG, outData))
325{
326 AutoCaller autoCaller (this);
327 CheckComRCReturnRC (autoCaller.rc());
328
329 pm::Filter filter (ComSafeArrayInArg (metricNames),
330 ComSafeArrayInArg (objects));
331
332 AutoReadLock alock (this);
333
334 /* Let's compute the size of the resulting flat array */
335 size_t flatSize = 0;
336 MetricList filteredMetrics;
337 MetricList::iterator it;
338 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
339 if (filter.match ((*it)->getObject(), (*it)->getName()))
340 {
341 filteredMetrics.push_back (*it);
342 flatSize += (*it)->getLength();
343 }
344
345 int i = 0;
346 size_t flatIndex = 0;
347 size_t numberOfMetrics = filteredMetrics.size();
348 com::SafeArray <BSTR> retNames (numberOfMetrics);
349 com::SafeIfaceArray <IUnknown> retObjects (numberOfMetrics);
350 com::SafeArray <ULONG> retIndices (numberOfMetrics);
351 com::SafeArray <ULONG> retLengths (numberOfMetrics);
352 com::SafeArray <LONG> retData (flatSize);
353
354 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it, ++i)
355 {
356 /* @todo Filtering goes here! */
357 ULONG *values, length;
358 /* @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
359 (*it)->query(&values, &length);
360 LogFlow (("PerformanceCollector::QueryMetricsData() querying metric %s "
361 "returned %d values.\n", (*it)->getName(), length));
362 memcpy(retData.raw() + flatIndex, values, length * sizeof(*values));
363 Bstr tmp((*it)->getName());
364 tmp.detachTo(&retNames[i]);
365 (*it)->getObject().queryInterfaceTo (&retObjects[i]);
366 retLengths[i] = length;
367 retIndices[i] = flatIndex;
368 flatIndex += length;
369 }
370
371 retNames.detachTo (ComSafeArrayOutArg (outMetricNames));
372 retObjects.detachTo (ComSafeArrayOutArg (outObjects));
373 retIndices.detachTo (ComSafeArrayOutArg (outDataIndices));
374 retLengths.detachTo (ComSafeArrayOutArg (outDataLengths));
375 retData.detachTo (ComSafeArrayOutArg (outData));
376 return S_OK;
377}
378
379// public methods for internal purposes
380///////////////////////////////////////////////////////////////////////////////
381
382void PerformanceCollector::registerBaseMetric (pm::BaseMetric *baseMetric)
383{
384 //LogFlowThisFuncEnter();
385 AutoCaller autoCaller (this);
386 if (!SUCCEEDED (autoCaller.rc())) return;
387
388 AutoWriteLock alock (this);
389 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)baseMetric->getObject(), baseMetric->getName()));
390 m.baseMetrics.push_back (baseMetric);
391 //LogFlowThisFuncLeave();
392}
393
394void PerformanceCollector::registerMetric (pm::Metric *metric)
395{
396 //LogFlowThisFuncEnter();
397 AutoCaller autoCaller (this);
398 if (!SUCCEEDED (autoCaller.rc())) return;
399
400 AutoWriteLock alock (this);
401 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)metric->getObject(), metric->getName()));
402 m.metrics.push_back (metric);
403 //LogFlowThisFuncLeave();
404}
405
406void PerformanceCollector::unregisterBaseMetricsFor (const ComPtr <IUnknown> &aObject)
407{
408 //LogFlowThisFuncEnter();
409 AutoCaller autoCaller (this);
410 if (!SUCCEEDED (autoCaller.rc())) return;
411
412 AutoWriteLock alock (this);
413 LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
414 BaseMetricList::iterator it = std::remove_if (
415 m.baseMetrics.begin(), m.baseMetrics.end(), std::bind2nd (
416 std::mem_fun (&pm::BaseMetric::associatedWith), aObject));
417 m.baseMetrics.erase(it, m.baseMetrics.end());
418 LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
419 //LogFlowThisFuncLeave();
420}
421
422void PerformanceCollector::unregisterMetricsFor (const ComPtr <IUnknown> &aObject)
423{
424 //LogFlowThisFuncEnter();
425 AutoCaller autoCaller (this);
426 if (!SUCCEEDED (autoCaller.rc())) return;
427
428 AutoWriteLock alock (this);
429 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p\n", this, __PRETTY_FUNCTION__, (void *)aObject));
430 MetricList::iterator it = std::remove_if (
431 m.metrics.begin(), m.metrics.end(), std::bind2nd (
432 std::mem_fun (&pm::Metric::associatedWith), aObject));
433 m.metrics.erase(it, m.metrics.end());
434 //LogFlowThisFuncLeave();
435}
436
437// private methods
438///////////////////////////////////////////////////////////////////////////////
439
440/* static */
441void PerformanceCollector::staticSamplerCallback (RTTIMERLR hTimerLR, void *pvUser,
442 uint64_t iTick)
443{
444 AssertReturnVoid (pvUser != NULL);
445 PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
446 Assert (collector->mMagic == MAGIC);
447 if (collector->mMagic == MAGIC)
448 {
449 collector->samplerCallback();
450 }
451 NOREF (hTimerLR);
452}
453
454void PerformanceCollector::samplerCallback()
455{
456 Log4(("{%p} " LOG_FN_FMT ": ENTER\n", this, __PRETTY_FUNCTION__));
457 AutoWriteLock alock (this);
458
459 pm::CollectorHints hints;
460 uint64_t timestamp = RTTimeMilliTS();
461 BaseMetricList toBeCollected;
462 BaseMetricList::iterator it;
463 /* Compose the list of metrics being collected at this moment */
464 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); it++)
465 if ((*it)->collectorBeat(timestamp))
466 {
467 (*it)->preCollect(hints);
468 toBeCollected.push_back(*it);
469 }
470
471 if (toBeCollected.size() == 0)
472 return;
473
474 /* Let know the platform specific code what is being collected */
475 m.hal->preCollect(hints);
476
477 /* Finally, collect the data */
478 std::for_each (toBeCollected.begin(), toBeCollected.end(),
479 std::mem_fun (&pm::BaseMetric::collect));
480 Log4(("{%p} " LOG_FN_FMT ": LEAVE\n", this, __PRETTY_FUNCTION__));
481}
482
483////////////////////////////////////////////////////////////////////////////////
484// PerformanceMetric class
485////////////////////////////////////////////////////////////////////////////////
486
487// constructor / destructor
488////////////////////////////////////////////////////////////////////////////////
489
490PerformanceMetric::PerformanceMetric()
491{
492}
493
494PerformanceMetric::~PerformanceMetric()
495{
496}
497
498HRESULT PerformanceMetric::FinalConstruct()
499{
500 LogFlowThisFunc (("\n"));
501
502 return S_OK;
503}
504
505void PerformanceMetric::FinalRelease()
506{
507 LogFlowThisFunc (("\n"));
508
509 uninit ();
510}
511
512// public initializer/uninitializer for internal purposes only
513////////////////////////////////////////////////////////////////////////////////
514
515HRESULT PerformanceMetric::init (pm::Metric *aMetric)
516{
517 m.name = aMetric->getName();
518 m.object = aMetric->getObject();
519 m.description = aMetric->getDescription();
520 m.period = aMetric->getPeriod();
521 m.count = aMetric->getLength();
522 m.unit = aMetric->getUnit();
523 m.min = aMetric->getMinValue();
524 m.max = aMetric->getMaxValue();
525 return S_OK;
526}
527
528void PerformanceMetric::uninit()
529{
530}
531
532STDMETHODIMP PerformanceMetric::COMGETTER(MetricName) (BSTR *aMetricName)
533{
534 /// @todo (r=dmik) why do all these getters not do AutoCaller and
535 /// AutoReadLock? Is the underlying metric a constant object?
536
537 m.name.cloneTo (aMetricName);
538 return S_OK;
539}
540
541STDMETHODIMP PerformanceMetric::COMGETTER(Object) (IUnknown **anObject)
542{
543 m.object.queryInterfaceTo(anObject);
544 return S_OK;
545}
546
547STDMETHODIMP PerformanceMetric::COMGETTER(Description) (BSTR *aDescription)
548{
549 m.description.cloneTo (aDescription);
550 return S_OK;
551}
552
553STDMETHODIMP PerformanceMetric::COMGETTER(Period) (ULONG *aPeriod)
554{
555 *aPeriod = m.period;
556 return S_OK;
557}
558
559STDMETHODIMP PerformanceMetric::COMGETTER(Count) (ULONG *aCount)
560{
561 *aCount = m.count;
562 return S_OK;
563}
564
565STDMETHODIMP PerformanceMetric::COMGETTER(Unit) (BSTR *aUnit)
566{
567 m.unit.cloneTo(aUnit);
568 return S_OK;
569}
570
571STDMETHODIMP PerformanceMetric::COMGETTER(MinimumValue) (LONG *aMinValue)
572{
573 *aMinValue = m.min;
574 return S_OK;
575}
576
577STDMETHODIMP PerformanceMetric::COMGETTER(MaximumValue) (LONG *aMaxValue)
578{
579 *aMaxValue = m.max;
580 return S_OK;
581}
582
Note: See TracBrowser for help on using the repository browser.

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