VirtualBox

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

Last change on this file since 10801 was 10779, checked in by vboxsync, 17 years ago

Locking. Enabled tests in tstAPI.

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