VirtualBox

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

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

PerfAPI: Windows collector re-worked to extract raw counters via WMI. Filtering for queries added. Security initialization is added to svcmain to access perf enumerators.

  • 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 10868 2008-07-24 18:34:35Z 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", 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", 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(), 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", 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