VirtualBox

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

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

Try fix the logging crashes because of ComPtr being passed through '...' instead of the pointer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1/* $Id: PerformanceImpl.cpp 10871 2008-07-24 20:25:14Z 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 LogFlowThisFuncEnter();
205 //LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
206
207 HRESULT rc = S_OK;
208
209 AutoCaller autoCaller (this);
210 CheckComRCReturnRC (autoCaller.rc());
211
212 pm::Filter filter (ComSafeArrayInArg (metricNames),
213 ComSafeArrayInArg (objects));
214
215 AutoReadLock alock (this);
216
217 MetricList filteredMetrics;
218 MetricList::iterator it;
219 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
220 if (filter.match ((*it)->getObject(), (*it)->getName()))
221 filteredMetrics.push_back (*it);
222
223 com::SafeIfaceArray<IPerformanceMetric> retMetrics (filteredMetrics.size());
224 int i = 0;
225 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it)
226 {
227 ComObjPtr <PerformanceMetric> metric;
228 rc = metric.createObject();
229 if (SUCCEEDED (rc))
230 rc = metric->init (*it);
231 AssertComRCReturnRC (rc);
232 LogFlow (("PerformanceCollector::GetMetrics() store a metric at "
233 "retMetrics[%d]...\n", i));
234 metric.queryInterfaceTo (&retMetrics [i++]);
235 }
236 retMetrics.detachTo (ComSafeArrayOutArg(outMetrics));
237 LogFlowThisFuncLeave();
238 return rc;
239}
240
241STDMETHODIMP
242PerformanceCollector::SetupMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
243 ComSafeArrayIn (IUnknown *, objects),
244 ULONG aPeriod, ULONG aCount)
245{
246 AutoCaller autoCaller (this);
247 CheckComRCReturnRC (autoCaller.rc());
248
249 pm::Filter filter (ComSafeArrayInArg (metricNames),
250 ComSafeArrayInArg (objects));
251
252 AutoWriteLock alock (this);
253
254 BaseMetricList::iterator it;
255 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
256 if (filter.match((*it)->getObject(), (*it)->getName()))
257 {
258 (*it)->init(aPeriod, aCount);
259 (*it)->enable();
260 }
261
262 return S_OK;
263}
264
265STDMETHODIMP
266PerformanceCollector::EnableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
267 ComSafeArrayIn (IUnknown *, objects))
268{
269 AutoCaller autoCaller (this);
270 CheckComRCReturnRC (autoCaller.rc());
271
272 pm::Filter filter (ComSafeArrayInArg (metricNames),
273 ComSafeArrayInArg (objects));
274
275 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
276 /* fiddling with enable bit only, but we */
277 /* care for those who come next :-). */
278
279 BaseMetricList::iterator it;
280 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
281 if (filter.match((*it)->getObject(), (*it)->getName()))
282 (*it)->enable();
283
284 return S_OK;
285}
286
287STDMETHODIMP
288PerformanceCollector::DisableMetrics (ComSafeArrayIn (INPTR BSTR, metricNames),
289 ComSafeArrayIn (IUnknown *, objects))
290{
291 AutoCaller autoCaller (this);
292 CheckComRCReturnRC (autoCaller.rc());
293
294 pm::Filter filter (ComSafeArrayInArg (metricNames),
295 ComSafeArrayInArg (objects));
296
297 AutoWriteLock alock (this); /* Write lock is not needed atm since we are */
298 /* fiddling with enable bit only, but we */
299 /* care for those who come next :-). */
300
301 BaseMetricList::iterator it;
302 for (it = m.baseMetrics.begin(); it != m.baseMetrics.end(); ++it)
303 if (filter.match((*it)->getObject(), (*it)->getName()))
304 (*it)->disable();
305
306 return S_OK;
307}
308
309STDMETHODIMP
310PerformanceCollector::QueryMetricsData (ComSafeArrayIn (INPTR BSTR, metricNames),
311 ComSafeArrayIn (IUnknown *, objects),
312 ComSafeArrayOut (BSTR, outMetricNames),
313 ComSafeArrayOut (IUnknown *, outObjects),
314 ComSafeArrayOut (ULONG, outDataIndices),
315 ComSafeArrayOut (ULONG, outDataLengths),
316 ComSafeArrayOut (LONG, outData))
317{
318 AutoCaller autoCaller (this);
319 CheckComRCReturnRC (autoCaller.rc());
320
321 pm::Filter filter (ComSafeArrayInArg (metricNames),
322 ComSafeArrayInArg (objects));
323
324 AutoReadLock alock (this);
325
326 /* Let's compute the size of the resulting flat array */
327 size_t flatSize = 0;
328 MetricList filteredMetrics;
329 MetricList::iterator it;
330 for (it = m.metrics.begin(); it != m.metrics.end(); ++it)
331 if (filter.match ((*it)->getObject(), (*it)->getName()))
332 {
333 filteredMetrics.push_back (*it);
334 flatSize += (*it)->getLength();
335 }
336
337 int i = 0;
338 size_t flatIndex = 0;
339 size_t numberOfMetrics = filteredMetrics.size();
340 com::SafeArray <BSTR> retNames (numberOfMetrics);
341 com::SafeIfaceArray <IUnknown> retObjects (numberOfMetrics);
342 com::SafeArray <ULONG> retIndices (numberOfMetrics);
343 com::SafeArray <ULONG> retLengths (numberOfMetrics);
344 com::SafeArray <LONG> retData (flatSize);
345
346 for (it = filteredMetrics.begin(); it != filteredMetrics.end(); ++it, ++i)
347 {
348 /* @todo Filtering goes here! */
349 unsigned long *values, length;
350 /* @todo We may want to revise the query method to get rid of excessive alloc/memcpy calls. */
351 (*it)->query(&values, &length);
352 memcpy(retData.raw() + flatIndex, values, length * sizeof(*values));
353 Bstr tmp((*it)->getName());
354 tmp.detachTo(&retNames[i]);
355 (*it)->getObject().queryInterfaceTo (&retObjects[i]);
356 retLengths[i] = length;
357 retIndices[i] = flatIndex;
358 flatIndex += length;
359 }
360
361 retNames.detachTo (ComSafeArrayOutArg (outMetricNames));
362 retObjects.detachTo (ComSafeArrayOutArg (outObjects));
363 retIndices.detachTo (ComSafeArrayOutArg (outDataIndices));
364 retLengths.detachTo (ComSafeArrayOutArg (outDataLengths));
365 retData.detachTo (ComSafeArrayOutArg (outData));
366 return S_OK;
367}
368
369// public methods for internal purposes
370///////////////////////////////////////////////////////////////////////////////
371
372void PerformanceCollector::registerBaseMetric (pm::BaseMetric *baseMetric)
373{
374 LogFlowThisFuncEnter();
375 AutoCaller autoCaller (this);
376 if (!SUCCEEDED (autoCaller.rc())) return;
377
378 AutoWriteLock alock (this);
379 LogFlowThisFunc (("obj=%p name=%s\n", (void *)baseMetric->getObject(), baseMetric->getName()));
380 m.baseMetrics.push_back (baseMetric);
381 LogFlowThisFuncLeave();
382}
383
384void PerformanceCollector::registerMetric (pm::Metric *metric)
385{
386 LogFlowThisFuncEnter();
387 AutoCaller autoCaller (this);
388 if (!SUCCEEDED (autoCaller.rc())) return;
389
390 AutoWriteLock alock (this);
391 LogFlowThisFunc (("obj=%p name=%s\n", (void *)metric->getObject(), metric->getName()));
392 m.metrics.push_back (metric);
393 LogFlowThisFuncLeave();
394}
395
396void PerformanceCollector::unregisterBaseMetricsFor (const ComPtr <IUnknown> &aObject)
397{
398 LogFlowThisFuncEnter();
399 AutoCaller autoCaller (this);
400 if (!SUCCEEDED (autoCaller.rc())) return;
401
402 AutoWriteLock alock (this);
403 LogFlowThisFunc (("before remove_if: m.baseMetrics.size()=%d, obj=%p\n", m.baseMetrics.size(), (void *)aObject));
404 BaseMetricList::iterator it = std::remove_if (
405 m.baseMetrics.begin(), m.baseMetrics.end(), std::bind2nd (
406 std::mem_fun (&pm::BaseMetric::associatedWith), aObject));
407 m.baseMetrics.erase(it, m.baseMetrics.end());
408 LogFlowThisFunc (("after remove_if: m.baseMetrics.size()=%d\n", m.baseMetrics.size()));
409 LogFlowThisFuncLeave();
410}
411
412void PerformanceCollector::unregisterMetricsFor (const ComPtr <IUnknown> &aObject)
413{
414 LogFlowThisFuncEnter();
415 AutoCaller autoCaller (this);
416 if (!SUCCEEDED (autoCaller.rc())) return;
417
418 AutoWriteLock alock (this);
419 LogFlowThisFunc (("obj=%p\n", (void *)aObject));
420 MetricList::iterator it = std::remove_if (
421 m.metrics.begin(), m.metrics.end(), std::bind2nd (
422 std::mem_fun (&pm::Metric::associatedWith), aObject));
423 m.metrics.erase(it, m.metrics.end());
424 LogFlowThisFuncLeave();
425}
426
427// private methods
428///////////////////////////////////////////////////////////////////////////////
429
430/* static */
431void PerformanceCollector::staticSamplerCallback (PRTTIMER pTimer, void *pvUser,
432 uint64_t iTick)
433{
434 AssertReturnVoid (pvUser != NULL);
435 PerformanceCollector *collector = static_cast <PerformanceCollector *> (pvUser);
436 Assert (collector->mMagic == MAGIC);
437 if (collector->mMagic == MAGIC)
438 {
439 collector->samplerCallback();
440 }
441}
442
443void PerformanceCollector::samplerCallback()
444{
445 LogFlowThisFuncEnter();
446 AutoWriteLock alock (this);
447
448 uint64_t timestamp = RTTimeMilliTS();
449 std::for_each (m.baseMetrics.begin(), m.baseMetrics.end(),
450 std::bind2nd (std::mem_fun (&pm::BaseMetric::collectorBeat),
451 timestamp));
452 LogFlowThisFuncLeave();
453}
454
455////////////////////////////////////////////////////////////////////////////////
456// PerformanceMetric class
457////////////////////////////////////////////////////////////////////////////////
458
459// constructor / destructor
460////////////////////////////////////////////////////////////////////////////////
461
462PerformanceMetric::PerformanceMetric()
463{
464}
465
466PerformanceMetric::~PerformanceMetric()
467{
468}
469
470HRESULT PerformanceMetric::FinalConstruct()
471{
472 LogFlowThisFunc (("\n"));
473
474 return S_OK;
475}
476
477void PerformanceMetric::FinalRelease()
478{
479 LogFlowThisFunc (("\n"));
480
481 uninit ();
482}
483
484// public initializer/uninitializer for internal purposes only
485////////////////////////////////////////////////////////////////////////////////
486
487HRESULT PerformanceMetric::init (pm::Metric *aMetric)
488{
489 m.name = aMetric->getName();
490 m.object = aMetric->getObject();
491 m.period = aMetric->getPeriod();
492 m.count = aMetric->getLength();
493 m.unit = aMetric->getUnit();
494 m.min = aMetric->getMinValue();
495 m.max = aMetric->getMaxValue();
496 return S_OK;
497}
498
499void PerformanceMetric::uninit()
500{
501}
502
503STDMETHODIMP PerformanceMetric::COMGETTER(MetricName) (BSTR *aMetricName)
504{
505 /// @todo (r=dmik) why do all these getters not do AutoCaller and
506 /// AutoReadLock? Is the underlying metric a constant object?
507
508 m.name.cloneTo (aMetricName);
509 return S_OK;
510}
511
512STDMETHODIMP PerformanceMetric::COMGETTER(Object) (IUnknown **anObject)
513{
514 m.object.queryInterfaceTo(anObject);
515 return S_OK;
516}
517
518STDMETHODIMP PerformanceMetric::COMGETTER(Period) (ULONG *aPeriod)
519{
520 *aPeriod = m.period;
521 return S_OK;
522}
523
524STDMETHODIMP PerformanceMetric::COMGETTER(Count) (ULONG *aCount)
525{
526 *aCount = m.count;
527 return S_OK;
528}
529
530STDMETHODIMP PerformanceMetric::COMGETTER(Unit) (BSTR *aUnit)
531{
532 m.unit.cloneTo(aUnit);
533 return S_OK;
534}
535
536STDMETHODIMP PerformanceMetric::COMGETTER(MinimumValue) (LONG *aMinValue)
537{
538 *aMinValue = m.min;
539 return S_OK;
540}
541
542STDMETHODIMP PerformanceMetric::COMGETTER(MaximumValue) (LONG *aMaxValue)
543{
544 *aMaxValue = m.max;
545 return S_OK;
546}
547
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