VirtualBox

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

Last change on this file since 10753 was 10753, checked in by vboxsync, 16 years ago

Stubs for all platforms. Implementation of host CPU load and RAM usage counters for Windows. Locking. Fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1/* $Id: PerformanceImpl.cpp 10753 2008-07-18 19:22:21Z 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.mFactory = new pm::MetricFactorySolaris();
106#endif
107#ifdef RT_OS_LINUX
108 m.mFactory = new pm::MetricFactoryLinux();
109#endif
110#ifdef RT_OS_WINDOWS
111 m.mFactory = new pm::MetricFactoryWin();
112#endif
113#ifdef RT_OS_OS2
114 m.mFactory = new pm::MetricFactoryOS2();
115#endif
116#ifdef RT_OS_DARWIN
117 m.mFactory = 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.mSampler, 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.mSampler);
161 AssertMsgRC (vrc, ("Failed to destroy resource usage "
162 "sampling timer (%Rra)\n", vrc));
163 m.mSampler = NULL;
164
165 delete m.mFactory;
166 m.mFactory = 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 PerformanceCollector::GetMetrics(ComSafeArrayIn(INPTR BSTR, metricNames),
200 ComSafeArrayIn(IUnknown *, objects),
201 ComSafeArrayOut(IPerformanceMetric *, outMetrics))
202{
203 //LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
204
205 HRESULT rc = S_OK;
206
207 AutoCaller autoCaller (this);
208 CheckComRCReturnRC (autoCaller.rc());
209
210 pm::Filter filter(ComSafeArrayInArg(metricNames), ComSafeArrayInArg(objects));
211
212 AutoReadLock alock (this);
213
214 MetricList filteredMetrics;
215 MetricList::iterator it;
216 for (it = m.mMetrics.begin(); it != m.mMetrics.end(); ++it)
217 if (filter.match((*it)->getObject(), (*it)->getName()))
218 filteredMetrics.push_back(*it);
219
220 com::SafeIfaceArray<IPerformanceMetric> retMetrics(filteredMetrics.size());
221 int i = 0;
222 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
223 {
224 ComObjPtr<PerformanceMetric> metric;
225 rc = metric.createObject();
226 if (SUCCEEDED (rc))
227 rc = metric->init (*it);
228 ComAssertComRCThrowRC (rc);
229 LogFlow(("PerformanceCollector::GetMetrics() store a metric at retMetrics[%d]...\n", i));
230 metric.queryInterfaceTo(&retMetrics[i++]);
231 }
232 retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
233 return rc;
234}
235
236STDMETHODIMP PerformanceCollector::SetupMetrics (ComSafeArrayIn(INPTR BSTR, metricNames),
237 ComSafeArrayIn(IUnknown *, objects),
238 ULONG aPeriod, ULONG aCount)
239{
240 AutoCaller autoCaller (this);
241 CheckComRCReturnRC (autoCaller.rc());
242
243 pm::Filter filter(ComSafeArrayInArg(metricNames), ComSafeArrayInArg(objects));
244
245 AutoWriteLock alock (this);
246
247 BaseMetricList::iterator it;
248 for (it = m.mBaseMetrics.begin(); it != m.mBaseMetrics.end(); ++it)
249 if (filter.match((*it)->getObject(), (*it)->getName()))
250 {
251 (*it)->init(aPeriod, aCount);
252 (*it)->enable();
253 }
254
255 return S_OK;
256}
257
258STDMETHODIMP PerformanceCollector::EnableMetrics (ComSafeArrayIn(INPTR BSTR, metricNames),
259 ComSafeArrayIn(IUnknown *, objects))
260{
261 AutoCaller autoCaller (this);
262 CheckComRCReturnRC (autoCaller.rc());
263
264 pm::Filter filter(ComSafeArrayInArg(metricNames), ComSafeArrayInArg(objects));
265
266 AutoReadLock alock (this); /* Need a read lock to access mBaseMetrics */
267
268 BaseMetricList::iterator it;
269 for (it = m.mBaseMetrics.begin(); it != m.mBaseMetrics.end(); ++it)
270 if (filter.match((*it)->getObject(), (*it)->getName()))
271 (*it)->enable();
272
273 return S_OK;
274}
275
276STDMETHODIMP PerformanceCollector::DisableMetrics (ComSafeArrayIn(INPTR BSTR, metricNames),
277 ComSafeArrayIn(IUnknown *, objects))
278{
279 AutoCaller autoCaller (this);
280 CheckComRCReturnRC (autoCaller.rc());
281
282 pm::Filter filter(ComSafeArrayInArg(metricNames), ComSafeArrayInArg(objects));
283
284 AutoReadLock alock (this);
285
286 BaseMetricList::iterator it;
287 for (it = m.mBaseMetrics.begin(); it != m.mBaseMetrics.end(); ++it)
288 if (filter.match((*it)->getObject(), (*it)->getName()))
289 (*it)->disable();
290
291 return S_OK;
292}
293
294STDMETHODIMP PerformanceCollector::QueryMetricsData (ComSafeArrayIn(INPTR BSTR, metricNames),
295 ComSafeArrayIn(IUnknown *, objects),
296 ComSafeArrayOut(BSTR, outMetricNames),
297 ComSafeArrayOut(IUnknown *, outObjects),
298 ComSafeArrayOut(ULONG, outDataIndices),
299 ComSafeArrayOut(ULONG, outDataLengths),
300 ComSafeArrayOut(LONG, outData))
301{
302 AutoCaller autoCaller (this);
303 CheckComRCReturnRC (autoCaller.rc());
304
305 AutoReadLock alock (this);
306
307 int i;
308 MetricList::const_iterator it;
309 /* Let's compute the size of the resulting flat array */
310 size_t flatSize = 0, numberOfMetrics = 0;
311 for (it = m.mMetrics.begin(); it != m.mMetrics.end(); ++it)
312 {
313 /* @todo Filtering goes here! */
314 flatSize += (*it)->getLength();
315 ++numberOfMetrics;
316 }
317 size_t flatIndex = 0;
318 com::SafeArray<BSTR> retNames(numberOfMetrics);
319 com::SafeIfaceArray<IUnknown> retObjects(numberOfMetrics);
320 com::SafeArray<ULONG> retIndices(numberOfMetrics);
321 com::SafeArray<ULONG> retLengths(numberOfMetrics);
322 com::SafeArray<LONG> retData(flatSize);
323
324 for (it = m.mMetrics.begin(), i = 0; it != m.mMetrics.end(); ++it)
325 {
326 /* @todo Filtering goes here! */
327 unsigned long *values, length;
328 /* @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
329 (*it)->query(&values, &length);
330 memcpy(retData.raw() + flatIndex, values, length * sizeof(*values));
331 Bstr tmp((*it)->getName());
332 tmp.detachTo(&retNames[i]);
333 (*it)->getObject().queryInterfaceTo(&retObjects[i]);
334 retLengths[i] = length;
335 retIndices[i] = flatIndex;
336 ++i;
337 flatIndex += length;
338 }
339
340 retNames.detachTo(ComSafeArrayOutArg(outMetricNames));
341 retObjects.detachTo(ComSafeArrayOutArg(outObjects));
342 retIndices.detachTo(ComSafeArrayOutArg(outDataIndices));
343 retLengths.detachTo(ComSafeArrayOutArg(outDataLengths));
344 retData.detachTo(ComSafeArrayOutArg(outData));
345 return S_OK;
346}
347
348// public methods for internal purposes
349///////////////////////////////////////////////////////////////////////////////
350
351void PerformanceCollector::registerBaseMetric (pm::BaseMetric *baseMetric)
352{
353 AutoWriteLock alock (this);
354 m.mBaseMetrics.push_back (baseMetric);
355}
356
357void PerformanceCollector::registerMetric (pm::Metric *metric)
358{
359 AutoWriteLock alock (this);
360 m.mMetrics.push_back (metric);
361}
362
363void PerformanceCollector::unregisterBaseMetricsFor (const ComPtr <IUnknown> &aObject)
364{
365 AutoWriteLock alock (this);
366 std::remove_if (m.mBaseMetrics.begin(), m.mBaseMetrics.end(),
367 std::bind2nd (std::mem_fun (&pm::BaseMetric::associatedWith),
368 aObject));
369}
370
371void PerformanceCollector::unregisterMetricsFor (const ComPtr <IUnknown> &aObject)
372{
373 AutoWriteLock alock (this);
374 std::remove_if (m.mMetrics.begin(), m.mMetrics.end(),
375 std::bind2nd (std::mem_fun (&pm::Metric::associatedWith),
376 aObject));
377}
378
379// private methods
380///////////////////////////////////////////////////////////////////////////////
381
382/* static */
383void PerformanceCollector::staticSamplerCallback (PRTTIMER pTimer, void *pvUser,
384 uint64_t iTick)
385{
386 AssertReturnVoid (pvUser != NULL);
387 PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
388 Assert(collector->mMagic == MAGIC);
389 if (collector->mMagic == MAGIC)
390 {
391 collector->samplerCallback();
392 }
393}
394
395void PerformanceCollector::samplerCallback()
396{
397 AutoWriteLock alock (this);
398
399 uint64_t timestamp = RTTimeMilliTS();
400 std::for_each(m.mBaseMetrics.begin(), m.mBaseMetrics.end(),
401 std::bind2nd (std::mem_fun (&pm::BaseMetric::collectorBeat), timestamp));
402}
403
404////////////////////////////////////////////////////////////////////////////////
405// PerformanceMetric class
406////////////////////////////////////////////////////////////////////////////////
407
408// constructor / destructor
409////////////////////////////////////////////////////////////////////////////////
410
411PerformanceMetric::PerformanceMetric() : mMetric(0)
412{
413}
414
415PerformanceMetric::~PerformanceMetric()
416{
417}
418
419HRESULT PerformanceMetric::FinalConstruct()
420{
421 LogFlowThisFunc (("\n"));
422
423 return S_OK;
424}
425
426void PerformanceMetric::FinalRelease()
427{
428 LogFlowThisFunc (("\n"));
429
430 uninit ();
431}
432
433// public initializer/uninitializer for internal purposes only
434////////////////////////////////////////////////////////////////////////////////
435
436HRESULT PerformanceMetric::init (pm::Metric *aMetric)
437{
438 mMetric = aMetric;
439 return S_OK;
440}
441
442void PerformanceMetric::uninit()
443{
444}
445
446STDMETHODIMP PerformanceMetric::COMGETTER(MetricName) (BSTR *aMetricName)
447{
448 Bstr tmp (mMetric->getName());
449 tmp.detachTo (aMetricName);
450 return S_OK;
451}
452
453STDMETHODIMP PerformanceMetric::COMGETTER(Object) (IUnknown **anObject)
454{
455 *anObject = mMetric->getObject();
456 return S_OK;
457}
458
459STDMETHODIMP PerformanceMetric::COMGETTER(Period) (ULONG *aPeriod)
460{
461 *aPeriod = mMetric->getPeriod();
462 return S_OK;
463}
464
465STDMETHODIMP PerformanceMetric::COMGETTER(Count) (ULONG *aCount)
466{
467 *aCount = mMetric->getLength();
468 return S_OK;
469}
470
471STDMETHODIMP PerformanceMetric::COMGETTER(Unit) (BSTR *aUnit)
472{
473 Bstr tmp(mMetric->getUnit());
474 tmp.detachTo(aUnit);
475 return S_OK;
476}
477
478STDMETHODIMP PerformanceMetric::COMGETTER(MinimumValue) (LONG *aMinValue)
479{
480 *aMinValue = mMetric->getMinValue();
481 return S_OK;
482}
483
484STDMETHODIMP PerformanceMetric::COMGETTER(MaximumValue) (LONG *aMaxValue)
485{
486 *aMaxValue = mMetric->getMaxValue();
487 return S_OK;
488}
489
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