VirtualBox

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

Last change on this file since 11458 was 11391, checked in by vboxsync, 17 years ago

Moved annoying log messages to either level4 or private logging. Added private logging macro LogAleksey.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 KB
Line 
1/* $Id: PerformanceImpl.cpp 11391 2008-08-13 14:48:53Z 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 /* @todo Obviously other platforms must be added as well. */
111#ifdef RT_OS_SOLARIS
112 m.factory = new pm::MetricFactorySolaris();
113#endif
114#ifdef RT_OS_LINUX
115 m.factory = new pm::MetricFactoryLinux();
116#endif
117#ifdef RT_OS_WINDOWS
118 m.factory = new pm::MetricFactoryWin();
119#endif
120#ifdef RT_OS_OS2
121 m.factory = new pm::MetricFactoryOS2();
122#endif
123#ifdef RT_OS_DARWIN
124 m.factory = new pm::MetricFactoryDarwin();
125#endif
126
127 /* Let the sampler know it gets a valid collector. */
128 mMagic = MAGIC;
129
130 /* Start resource usage sampler */
131 int vrc = RTTimerLRCreate (&m.sampler, VBOX_USAGE_SAMPLER_MIN_INTERVAL,
132 &PerformanceCollector::staticSamplerCallback, this);
133 AssertMsgRC (vrc, ("Failed to create resource usage "
134 "sampling timer(%Rra)\n", vrc));
135 if (RT_FAILURE (vrc))
136 rc = E_FAIL;
137
138 if (SUCCEEDED (rc))
139 autoInitSpan.setSucceeded();
140
141 LogFlowThisFuncLeave();
142
143 return rc;
144}
145
146/**
147 * Uninitializes the PerformanceCollector object.
148 *
149 * Called either from FinalRelease() or by the parent when it gets destroyed.
150 */
151void PerformanceCollector::uninit()
152{
153 LogFlowThisFuncEnter();
154
155 /* Enclose the state transition Ready->InUninit->NotReady */
156 AutoUninitSpan autoUninitSpan (this);
157 if (autoUninitSpan.uninitDone())
158 {
159 LogFlowThisFunc (("Already uninitialized.\n"));
160 LogFlowThisFuncLeave();
161 return;
162 }
163
164 mMagic = 0;
165
166 /* Destroy resource usage sampler */
167 int vrc = RTTimerLRDestroy (m.sampler);
168 AssertMsgRC (vrc, ("Failed to destroy resource usage "
169 "sampling timer (%Rra)\n", vrc));
170 m.sampler = NULL;
171
172 delete m.factory;
173 m.factory = NULL;
174
175 LogFlowThisFuncLeave();
176}
177
178// IPerformanceCollector properties
179////////////////////////////////////////////////////////////////////////////////
180
181STDMETHODIMP
182PerformanceCollector::COMGETTER(MetricNames) (ComSafeArrayOut (BSTR, theMetricNames))
183{
184 if (ComSafeArrayOutIsNull (theMetricNames))
185 return E_POINTER;
186
187 AutoCaller autoCaller (this);
188 CheckComRCReturnRC (autoCaller.rc());
189
190 AutoReadLock alock (this);
191
192 com::SafeArray <BSTR> metricNames(RT_ELEMENTS(gMetricNames));
193 for (size_t i = 0; i < RT_ELEMENTS(gMetricNames); i++)
194 {
195 gMetricNames[i].detachTo(&metricNames[i]);
196 }
197 //gMetricNames.detachTo(ComSafeArrayOutArg (theMetricNames));
198 metricNames.detachTo (ComSafeArrayOutArg (theMetricNames));
199
200 return S_OK;
201}
202
203// IPerformanceCollector methods
204////////////////////////////////////////////////////////////////////////////////
205
206STDMETHODIMP
207PerformanceCollector::GetMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
208 ComSafeArrayIn (IUnknown *, objects),
209 ComSafeArrayOut (IPerformanceMetric *, outMetrics))
210{
211 LogFlowThisFuncEnter();
212 //LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
213
214 HRESULT rc = S_OK;
215
216 AutoCaller autoCaller (this);
217 CheckComRCReturnRC (autoCaller.rc());
218
219 pm::Filter filter (ComSafeArrayInArg (metricNames),
220 ComSafeArrayInArg (objects));
221
222 AutoReadLock alock (this);
223
224 MetricList filteredMetrics;
225 MetricList::iterator it;
226 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
227 if (filter.match ((*it)->getObject(), (*it)->getName()))
228 filteredMetrics.push_back (*it);
229
230 com::SafeIfaceArray<IPerformanceMetric> retMetrics (filteredMetrics.size());
231 int i = 0;
232 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
233 {
234 ComObjPtr <PerformanceMetric> metric;
235 rc = metric.createObject();
236 if (SUCCEEDED (rc))
237 rc = metric->init (*it);
238 AssertComRCReturnRC (rc);
239 LogFlow (("PerformanceCollector::GetMetrics() store a metric at "
240 "retMetrics[%d]...\n", i));
241 metric.queryInterfaceTo (&retMetrics [i++]);
242 }
243 retMetrics.detachTo (ComSafeArrayOutArg(outMetrics));
244 LogFlowThisFuncLeave();
245 return rc;
246}
247
248STDMETHODIMP
249PerformanceCollector::SetupMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
250 ComSafeArrayIn (IUnknown *, objects),
251 ULONG aPeriod, ULONG aCount)
252{
253 AutoCaller autoCaller (this);
254 CheckComRCReturnRC (autoCaller.rc());
255
256 pm::Filter filter (ComSafeArrayInArg (metricNames),
257 ComSafeArrayInArg (objects));
258
259 AutoWriteLock alock (this);
260
261 BaseMetricList::iterator it;
262 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
263 if (filter.match((*it)->getObject(), (*it)->getName()))
264 {
265 LogFlow (("PerformanceCollector::SetupMetrics() setting period to %u,"
266 " count to %u for %s\n", aPeriod, aCount, (*it)->getName()));
267 (*it)->init(aPeriod, aCount);
268 LogFlow (("PerformanceCollector::SetupMetrics() enabling %s\n",
269 aPeriod, aCount, (*it)->getName()));
270 (*it)->enable();
271 }
272
273 return S_OK;
274}
275
276STDMETHODIMP
277PerformanceCollector::EnableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
278 ComSafeArrayIn (IUnknown *, objects))
279{
280 AutoCaller autoCaller (this);
281 CheckComRCReturnRC (autoCaller.rc());
282
283 pm::Filter filter (ComSafeArrayInArg (metricNames),
284 ComSafeArrayInArg (objects));
285
286 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
287 /* fiddling with enable bit only, but we */
288 /* care for those who come next :-). */
289
290 BaseMetricList::iterator it;
291 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
292 if (filter.match((*it)->getObject(), (*it)->getName()))
293 (*it)->enable();
294
295 return S_OK;
296}
297
298STDMETHODIMP
299PerformanceCollector::DisableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
300 ComSafeArrayIn (IUnknown *, objects))
301{
302 AutoCaller autoCaller (this);
303 CheckComRCReturnRC (autoCaller.rc());
304
305 pm::Filter filter (ComSafeArrayInArg (metricNames),
306 ComSafeArrayInArg (objects));
307
308 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
309 /* fiddling with enable bit only, but we */
310 /* care for those who come next :-). */
311
312 BaseMetricList::iterator it;
313 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
314 if (filter.match((*it)->getObject(), (*it)->getName()))
315 (*it)->disable();
316
317 return S_OK;
318}
319
320STDMETHODIMP
321PerformanceCollector::QueryMetricsData (ComSafeArrayIn (INPTR BSTR, metricNames),
322 ComSafeArrayIn (IUnknown *, objects),
323 ComSafeArrayOut (BSTR, outMetricNames),
324 ComSafeArrayOut (IUnknown *, outObjects),
325 ComSafeArrayOut (ULONG, outDataIndices),
326 ComSafeArrayOut (ULONG, outDataLengths),
327 ComSafeArrayOut (LONG, outData))
328{
329 AutoCaller autoCaller (this);
330 CheckComRCReturnRC (autoCaller.rc());
331
332 pm::Filter filter (ComSafeArrayInArg (metricNames),
333 ComSafeArrayInArg (objects));
334
335 AutoReadLock alock (this);
336
337 /* Let's compute the size of the resulting flat array */
338 size_t flatSize = 0;
339 MetricList filteredMetrics;
340 MetricList::iterator it;
341 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
342 if (filter.match ((*it)->getObject(), (*it)->getName()))
343 {
344 filteredMetrics.push_back (*it);
345 flatSize += (*it)->getLength();
346 }
347
348 int i = 0;
349 size_t flatIndex = 0;
350 size_t numberOfMetrics = filteredMetrics.size();
351 com::SafeArray <BSTR> retNames (numberOfMetrics);
352 com::SafeIfaceArray <IUnknown> retObjects (numberOfMetrics);
353 com::SafeArray <ULONG> retIndices (numberOfMetrics);
354 com::SafeArray <ULONG> retLengths (numberOfMetrics);
355 com::SafeArray <LONG> retData (flatSize);
356
357 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it, ++i)
358 {
359 /* @todo Filtering goes here! */
360 ULONG *values, length;
361 /* @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
362 (*it)->query(&values, &length);
363 LogFlow (("PerformanceCollector::QueryMetricsData() querying metric %s "
364 "returned %d values.\n", (*it)->getName(), length));
365 memcpy(retData.raw() + flatIndex, values, length * sizeof(*values));
366 Bstr tmp((*it)->getName());
367 tmp.detachTo(&retNames[i]);
368 (*it)->getObject().queryInterfaceTo (&retObjects[i]);
369 retLengths[i] = length;
370 retIndices[i] = flatIndex;
371 flatIndex += length;
372 }
373
374 retNames.detachTo (ComSafeArrayOutArg (outMetricNames));
375 retObjects.detachTo (ComSafeArrayOutArg (outObjects));
376 retIndices.detachTo (ComSafeArrayOutArg (outDataIndices));
377 retLengths.detachTo (ComSafeArrayOutArg (outDataLengths));
378 retData.detachTo (ComSafeArrayOutArg (outData));
379 return S_OK;
380}
381
382// public methods for internal purposes
383///////////////////////////////////////////////////////////////////////////////
384
385void PerformanceCollector::registerBaseMetric (pm::BaseMetric *baseMetric)
386{
387 //LogFlowThisFuncEnter();
388 AutoCaller autoCaller (this);
389 if (!SUCCEEDED (autoCaller.rc())) return;
390
391 AutoWriteLock alock (this);
392 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)baseMetric->getObject(), baseMetric->getName()));
393 m.baseMetrics.push_back (baseMetric);
394 //LogFlowThisFuncLeave();
395}
396
397void PerformanceCollector::registerMetric (pm::Metric *metric)
398{
399 //LogFlowThisFuncEnter();
400 AutoCaller autoCaller (this);
401 if (!SUCCEEDED (autoCaller.rc())) return;
402
403 AutoWriteLock alock (this);
404 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p name=%s\n", this, __PRETTY_FUNCTION__, (void *)metric->getObject(), metric->getName()));
405 m.metrics.push_back (metric);
406 //LogFlowThisFuncLeave();
407}
408
409void PerformanceCollector::unregisterBaseMetricsFor (const ComPtr <IUnknown> &aObject)
410{
411 //LogFlowThisFuncEnter();
412 AutoCaller autoCaller (this);
413 if (!SUCCEEDED (autoCaller.rc())) return;
414
415 AutoWriteLock alock (this);
416 LogAleksey(("{%p} " LOG_FN_FMT ": before remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
417 BaseMetricList::iterator it = std::remove_if (
418 m.baseMetrics.begin(), m.baseMetrics.end(), std::bind2nd (
419 std::mem_fun (&pm::BaseMetric::associatedWith), aObject));
420 m.baseMetrics.erase(it, m.baseMetrics.end());
421 LogAleksey(("{%p} " LOG_FN_FMT ": after remove_if: m.baseMetrics.size()=%d\n", this, __PRETTY_FUNCTION__, m.baseMetrics.size()));
422 //LogFlowThisFuncLeave();
423}
424
425void PerformanceCollector::unregisterMetricsFor (const ComPtr <IUnknown> &aObject)
426{
427 //LogFlowThisFuncEnter();
428 AutoCaller autoCaller (this);
429 if (!SUCCEEDED (autoCaller.rc())) return;
430
431 AutoWriteLock alock (this);
432 LogAleksey(("{%p} " LOG_FN_FMT ": obj=%p\n", this, __PRETTY_FUNCTION__, (void *)aObject));
433 MetricList::iterator it = std::remove_if (
434 m.metrics.begin(), m.metrics.end(), std::bind2nd (
435 std::mem_fun (&pm::Metric::associatedWith), aObject));
436 m.metrics.erase(it, m.metrics.end());
437 //LogFlowThisFuncLeave();
438}
439
440// private methods
441///////////////////////////////////////////////////////////////////////////////
442
443/* static */
444void PerformanceCollector::staticSamplerCallback (RTTIMERLR hTimerLR, void *pvUser,
445 uint64_t iTick)
446{
447 AssertReturnVoid (pvUser != NULL);
448 PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
449 Assert (collector->mMagic == MAGIC);
450 if (collector->mMagic == MAGIC)
451 {
452 collector->samplerCallback();
453 }
454 NOREF (hTimerLR);
455}
456
457void PerformanceCollector::samplerCallback()
458{
459 Log4(("{%p} " LOG_FN_FMT ": ENTER\n", this, __PRETTY_FUNCTION__));
460 AutoWriteLock alock (this);
461
462 uint64_t timestamp = RTTimeMilliTS();
463 std::for_each (m.baseMetrics.begin(), m.baseMetrics.end(),
464 std::bind2nd (std::mem_fun (&pm::BaseMetric::collectorBeat),
465 timestamp));
466 Log4(("{%p} " LOG_FN_FMT ": LEAVE\n", this, __PRETTY_FUNCTION__));
467}
468
469////////////////////////////////////////////////////////////////////////////////
470// PerformanceMetric class
471////////////////////////////////////////////////////////////////////////////////
472
473// constructor / destructor
474////////////////////////////////////////////////////////////////////////////////
475
476PerformanceMetric::PerformanceMetric()
477{
478}
479
480PerformanceMetric::~PerformanceMetric()
481{
482}
483
484HRESULT PerformanceMetric::FinalConstruct()
485{
486 LogFlowThisFunc (("\n"));
487
488 return S_OK;
489}
490
491void PerformanceMetric::FinalRelease()
492{
493 LogFlowThisFunc (("\n"));
494
495 uninit ();
496}
497
498// public initializer/uninitializer for internal purposes only
499////////////////////////////////////////////////////////////////////////////////
500
501HRESULT PerformanceMetric::init (pm::Metric *aMetric)
502{
503 m.name = aMetric->getName();
504 m.object = aMetric->getObject();
505 m.period = aMetric->getPeriod();
506 m.count = aMetric->getLength();
507 m.unit = aMetric->getUnit();
508 m.min = aMetric->getMinValue();
509 m.max = aMetric->getMaxValue();
510 return S_OK;
511}
512
513void PerformanceMetric::uninit()
514{
515}
516
517STDMETHODIMP PerformanceMetric::COMGETTER(MetricName) (BSTR *aMetricName)
518{
519 /// @todo (r=dmik) why do all these getters not do AutoCaller and
520 /// AutoReadLock? Is the underlying metric a constant object?
521
522 m.name.cloneTo (aMetricName);
523 return S_OK;
524}
525
526STDMETHODIMP PerformanceMetric::COMGETTER(Object) (IUnknown **anObject)
527{
528 m.object.queryInterfaceTo(anObject);
529 return S_OK;
530}
531
532STDMETHODIMP PerformanceMetric::COMGETTER(Period) (ULONG *aPeriod)
533{
534 *aPeriod = m.period;
535 return S_OK;
536}
537
538STDMETHODIMP PerformanceMetric::COMGETTER(Count) (ULONG *aCount)
539{
540 *aCount = m.count;
541 return S_OK;
542}
543
544STDMETHODIMP PerformanceMetric::COMGETTER(Unit) (BSTR *aUnit)
545{
546 m.unit.cloneTo(aUnit);
547 return S_OK;
548}
549
550STDMETHODIMP PerformanceMetric::COMGETTER(MinimumValue) (LONG *aMinValue)
551{
552 *aMinValue = m.min;
553 return S_OK;
554}
555
556STDMETHODIMP PerformanceMetric::COMGETTER(MaximumValue) (LONG *aMaxValue)
557{
558 *aMaxValue = m.max;
559 return S_OK;
560}
561
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