VirtualBox

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

Last change on this file since 11352 was 11336, checked in by vboxsync, 17 years ago

Fixes in clienttest.java. Additional debug messages in Perf classes.

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