VirtualBox

source: vbox/trunk/src/VBox/Main/Performance.cpp@ 16560

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

Main: Cleaned up the long standing const BSTR = const (OLECHAR *) on WIn32 vs (const PRunichar) * on XPCOM clash. Cleaned up BSTR/GUID macros (IN_BSTR replaces INPTR BSTR, IN_GUID replaces INPTR GUIDPARAM, OUT_GUID replaces GUIDPARAMOUT).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
RevLine 
[10641]1/* $Id: Performance.cpp 15051 2008-12-05 17:20:00Z vboxsync $ */
2
3/** @file
4 *
5 * VBox Performance 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
[10868]24/*
25 * @todo list:
26 *
[11498]27 * 1) Detection of erroneous metric names
[10868]28 */
29
[13915]30#include "Performance.h"
31
[10679]32#include <VBox/com/array.h>
[10641]33#include <VBox/com/ptr.h>
[10679]34#include <VBox/com/string.h>
[10641]35#include <VBox/err.h>
36#include <iprt/string.h>
37#include <iprt/mem.h>
[11689]38#include <iprt/cpuset.h>
[10641]39
[12400]40#include <algorithm>
41
[10868]42#include "Logging.h"
[10641]43
44using namespace pm;
45
46// Stubs for non-pure virtual methods
47
[11180]48int CollectorHAL::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
[10641]49{
50 return E_NOTIMPL;
51}
52
[11180]53int CollectorHAL::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
[10641]54{
55 return E_NOTIMPL;
56}
57
[10868]58int CollectorHAL::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
[10641]59{
60 return E_NOTIMPL;
61}
62
[10868]63int CollectorHAL::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
[10641]64{
65 return E_NOTIMPL;
66}
67
[11498]68/* Generic implementations */
69
70int CollectorHAL::getHostCpuMHz(ULONG *mhz)
71{
[11591]72 unsigned cCpus = 0;
73 uint64_t u64TotalMHz = 0;
74 RTCPUSET OnlineSet;
75 RTMpGetOnlineSet(&OnlineSet);
76 for (RTCPUID iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
[11810]77 {
78 LogAleksey(("{%p} " LOG_FN_FMT ": Checking if CPU %d is member of online set...\n",
[11689]79 this, __PRETTY_FUNCTION__, (int)iCpu));
[11591]80 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
81 {
[11810]82 LogAleksey(("{%p} " LOG_FN_FMT ": Getting frequency for CPU %d...\n",
[11689]83 this, __PRETTY_FUNCTION__, (int)iCpu));
[11591]84 uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
85 if (uMHz != 0)
86 {
[11810]87 LogAleksey(("{%p} " LOG_FN_FMT ": CPU %d %u MHz\n",
[11689]88 this, __PRETTY_FUNCTION__, (int)iCpu, uMHz));
[11591]89 u64TotalMHz += uMHz;
90 cCpus++;
91 }
92 }
[11810]93 }
[11591]94
[12024]95 // @todo Replace 'if' with 'AssertReturn' when done debugging
96 //AssertReturn(cCpus, VERR_NOT_IMPLEMENTED);
97 if (cCpus == 0) return VERR_NOT_IMPLEMENTED;
98 *mhz = (ULONG)(u64TotalMHz / cCpus);
[11591]99
[11498]100 return VINF_SUCCESS;
101}
102
[12400]103bool BaseMetric::collectorBeat(uint64_t nowAt)
[10713]104{
105 if (isEnabled())
106 {
107 if (nowAt - mLastSampleTaken >= mPeriod * 1000)
108 {
109 mLastSampleTaken = nowAt;
[11591]110 Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
[11501]111 this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
[12400]112 return true;
[10713]113 }
114 }
[12400]115 return false;
[10713]116}
117
[10868]118/*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
119{
120 LogFlowThisFunc (("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
121 return mObject == object;
122}*/
123
[11180]124void HostCpuLoad::init(ULONG period, ULONG length)
[10641]125{
126 mPeriod = period;
127 mLength = length;
128 mUser->init(mLength);
129 mKernel->init(mLength);
130 mIdle->init(mLength);
131}
132
133void HostCpuLoad::collect()
134{
[11180]135 ULONG user, kernel, idle;
[10753]136 int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
137 if (RT_SUCCESS(rc))
138 {
139 mUser->put(user);
140 mKernel->put(kernel);
141 mIdle->put(idle);
142 }
[10641]143}
144
[12400]145void HostCpuLoadRaw::preCollect(CollectorHints& hints)
146{
147 hints.collectHostCpuLoad();
148}
149
[10641]150void HostCpuLoadRaw::collect()
151{
[10868]152 uint64_t user, kernel, idle;
153 uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
[10641]154
[10713]155 int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
156 if (RT_SUCCESS(rc))
157 {
158 userDiff = user - mUserPrev;
159 kernelDiff = kernel - mKernelPrev;
160 idleDiff = idle - mIdlePrev;
161 totalDiff = userDiff + kernelDiff + idleDiff;
[10868]162
163 if (totalDiff == 0)
164 {
165 /* This is only possible if none of counters has changed! */
166 LogFlowThisFunc (("Impossible! User, kernel and idle raw "
167 "counters has not changed since last sample.\n" ));
168 mUser->put(0);
169 mKernel->put(0);
170 mIdle->put(0);
171 }
172 else
173 {
[11180]174 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
175 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
176 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
[10868]177 }
[11591]178
[10713]179 mUserPrev = user;
180 mKernelPrev = kernel;
181 mIdlePrev = idle;
182 }
[10641]183}
184
[11180]185void HostCpuMhz::init(ULONG period, ULONG length)
[10679]186{
187 mPeriod = period;
188 mLength = length;
189 mMHz->init(mLength);
190}
191
[10641]192void HostCpuMhz::collect()
193{
[11180]194 ULONG mhz;
[10713]195 int rc = mHAL->getHostCpuMHz(&mhz);
196 if (RT_SUCCESS(rc))
197 mMHz->put(mhz);
[10641]198}
199
[11180]200void HostRamUsage::init(ULONG period, ULONG length)
[10679]201{
202 mPeriod = period;
203 mLength = length;
204 mTotal->init(mLength);
205 mUsed->init(mLength);
206 mAvailable->init(mLength);
207}
208
[12400]209void HostRamUsage::preCollect(CollectorHints& hints)
210{
211 hints.collectHostRamUsage();
212}
213
[10641]214void HostRamUsage::collect()
215{
[11180]216 ULONG total, used, available;
[10713]217 int rc = mHAL->getHostMemoryUsage(&total, &used, &available);
218 if (RT_SUCCESS(rc))
219 {
220 mTotal->put(total);
221 mUsed->put(used);
222 mAvailable->put(available);
223 }
[10641]224}
225
226
[10679]227
[11180]228void MachineCpuLoad::init(ULONG period, ULONG length)
[10679]229{
230 mPeriod = period;
231 mLength = length;
232 mUser->init(mLength);
233 mKernel->init(mLength);
234}
235
[10641]236void MachineCpuLoad::collect()
237{
[11180]238 ULONG user, kernel;
[10713]239 int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
240 if (RT_SUCCESS(rc))
241 {
242 mUser->put(user);
243 mKernel->put(kernel);
244 }
[10641]245}
246
[12400]247void MachineCpuLoadRaw::preCollect(CollectorHints& hints)
248{
249 hints.collectProcessCpuLoad(mProcess);
250}
251
[10641]252void MachineCpuLoadRaw::collect()
253{
[10868]254 uint64_t processUser, processKernel, hostTotal;
[10641]255
[10868]256 int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
[10713]257 if (RT_SUCCESS(rc))
258 {
[10868]259 if (hostTotal == mHostTotalPrev)
[10713]260 {
[10868]261 /* Nearly impossible, but... */
262 mUser->put(0);
263 mKernel->put(0);
[10713]264 }
[10868]265 else
266 {
[11180]267 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
268 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
[10868]269 }
[11591]270
[10868]271 mHostTotalPrev = hostTotal;
272 mProcessUserPrev = processUser;
273 mProcessKernelPrev = processKernel;
[10713]274 }
[10641]275}
276
[11180]277void MachineRamUsage::init(ULONG period, ULONG length)
[10679]278{
279 mPeriod = period;
280 mLength = length;
281 mUsed->init(mLength);
282}
283
[12400]284void MachineRamUsage::preCollect(CollectorHints& hints)
285{
286 hints.collectProcessRamUsage(mProcess);
287}
288
[10641]289void MachineRamUsage::collect()
290{
[11180]291 ULONG used;
[10713]292 int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
293 if (RT_SUCCESS(rc))
294 mUsed->put(used);
[10641]295}
296
[11180]297void CircularBuffer::init(ULONG length)
[10641]298{
299 if (mData)
300 RTMemFree(mData);
301 mLength = length;
[11481]302 if (mLength)
303 mData = (ULONG *)RTMemAllocZ(length * sizeof(ULONG));
304 else
305 mData = NULL;
[10713]306 mWrapped = false;
307 mEnd = 0;
[12973]308 mSequenceNumber = 0;
[10641]309}
310
[11180]311ULONG CircularBuffer::length()
[10641]312{
[10713]313 return mWrapped ? mLength : mEnd;
[10641]314}
315
[11180]316void CircularBuffer::put(ULONG value)
[10641]317{
[10713]318 if (mData)
319 {
320 mData[mEnd++] = value;
321 if (mEnd >= mLength)
322 {
323 mEnd = 0;
324 mWrapped = true;
325 }
[12973]326 ++mSequenceNumber;
[10713]327 }
[10641]328}
329
[11180]330void CircularBuffer::copyTo(ULONG *data)
[10641]331{
[10713]332 if (mWrapped)
333 {
[11180]334 memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
[10713]335 // Copy the wrapped part
336 if (mEnd)
[11180]337 memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
[10713]338 }
339 else
[11180]340 memcpy(data, mData, mEnd * sizeof(ULONG));
[10641]341}
342
[11180]343void SubMetric::query(ULONG *data)
[10641]344{
[10713]345 copyTo(data);
[10641]346}
[11591]347
[12973]348void Metric::query(ULONG **data, ULONG *count, ULONG *sequenceNumber)
[10641]349{
[11180]350 ULONG length;
351 ULONG *tmpData;
[10641]352
353 length = mSubMetric->length();
[12973]354 *sequenceNumber = mSubMetric->getSequenceNumber() - length;
[10641]355 if (length)
356 {
[11180]357 tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
[10713]358 mSubMetric->query(tmpData);
[10641]359 if (mAggregate)
360 {
361 *count = 1;
[11180]362 *data = (ULONG*)RTMemAlloc(sizeof(**data));
[10641]363 **data = mAggregate->compute(tmpData, length);
[10713]364 RTMemFree(tmpData);
[10641]365 }
366 else
367 {
368 *count = length;
369 *data = tmpData;
370 }
371 }
372 else
373 {
374 *count = 0;
375 *data = 0;
376 }
377}
378
[11180]379ULONG AggregateAvg::compute(ULONG *data, ULONG length)
[10641]380{
[10713]381 uint64_t tmp = 0;
[11180]382 for (ULONG i = 0; i < length; ++i)
[10713]383 tmp += data[i];
[11180]384 return (ULONG)(tmp / length);
[10641]385}
386
387const char * AggregateAvg::getName()
388{
389 return "avg";
390}
391
[11180]392ULONG AggregateMin::compute(ULONG *data, ULONG length)
[10641]393{
[11180]394 ULONG tmp = *data;
395 for (ULONG i = 0; i < length; ++i)
[10713]396 if (data[i] < tmp)
397 tmp = data[i];
398 return tmp;
[10641]399}
400
401const char * AggregateMin::getName()
402{
403 return "min";
404}
405
[11180]406ULONG AggregateMax::compute(ULONG *data, ULONG length)
[10641]407{
[11180]408 ULONG tmp = *data;
409 for (ULONG i = 0; i < length; ++i)
[10713]410 if (data[i] > tmp)
411 tmp = data[i];
412 return tmp;
[10641]413}
414
415const char * AggregateMax::getName()
416{
417 return "max";
418}
419
[15051]420Filter::Filter(ComSafeArrayIn(IN_BSTR, metricNames),
[10679]421 ComSafeArrayIn(IUnknown *, objects))
422{
[12942]423 /*
424 * Let's work around null/empty safe array mess. I am not sure there is
425 * a way to pass null arrays via webservice, I haven't found one. So I
426 * guess the users will be forced to use empty arrays instead. Constructing
427 * an empty SafeArray is a bit awkward, so what we do in this method is
428 * actually convert null arrays to empty arrays and pass them down to
429 * init() method. If someone knows how to do it better, please be my guest,
430 * fix it.
431 */
432 if (ComSafeArrayInIsNull(metricNames))
433 {
434 com::SafeArray <BSTR> nameArray;
435 if (ComSafeArrayInIsNull(objects))
436 {
437 com::SafeIfaceArray <IUnknown> objectArray;
438 objectArray.reset(0);
439 init(ComSafeArrayAsInParam(nameArray),
440 ComSafeArrayAsInParam(objectArray));
441 }
442 else
443 {
444 com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
445 init(ComSafeArrayAsInParam(nameArray),
446 ComSafeArrayAsInParam(objectArray));
447 }
448 }
449 else
450 {
[15051]451 com::SafeArray <IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
[12942]452 if (ComSafeArrayInIsNull(objects))
453 {
454 com::SafeIfaceArray <IUnknown> objectArray;
455 objectArray.reset(0);
456 init(ComSafeArrayAsInParam(nameArray),
457 ComSafeArrayAsInParam(objectArray));
458 }
459 else
460 {
461 com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
462 init(ComSafeArrayAsInParam(nameArray),
463 ComSafeArrayAsInParam(objectArray));
464 }
465 }
466}
467
[15051]468void Filter::init(ComSafeArrayIn(IN_BSTR, metricNames),
[12942]469 ComSafeArrayIn(IUnknown *, objects))
470{
[15051]471 com::SafeArray <IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
[12942]472 com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
[11383]473
[12942]474 if (!objectArray.size())
[10725]475 {
476 if (nameArray.size())
477 {
478 for (size_t i = 0; i < nameArray.size(); ++i)
479 processMetricList(std::string(com::Utf8Str(nameArray[i])), ComPtr<IUnknown>());
480 }
481 else
482 processMetricList(std::string("*"), ComPtr<IUnknown>());
483 }
484 else
485 {
486 for (size_t i = 0; i < objectArray.size(); ++i)
487 switch (nameArray.size())
488 {
489 case 0:
490 processMetricList(std::string("*"), objectArray[i]);
491 break;
492 case 1:
493 processMetricList(std::string(com::Utf8Str(nameArray[0])), objectArray[i]);
494 break;
495 default:
496 processMetricList(std::string(com::Utf8Str(nameArray[i])), objectArray[i]);
497 break;
498 }
499 }
[10679]500}
501
[10713]502void Filter::processMetricList(const std::string &name, const ComPtr<IUnknown> object)
[10679]503{
504 std::string::size_type startPos = 0;
505
506 for (std::string::size_type pos = name.find(",");
507 pos != std::string::npos;
508 pos = name.find(",", startPos))
509 {
510 mElements.push_back(std::make_pair(object, name.substr(startPos, pos - startPos)));
511 startPos = pos + 1;
512 }
513 mElements.push_back(std::make_pair(object, name.substr(startPos)));
514}
515
[12802]516/**
517 * The following method was borrowed from stamR3Match (VMM/STAM.cpp) and
518 * modified to handle the special case of trailing colon in the pattern.
519 *
520 * @returns True if matches, false if not.
521 * @param pszPat Pattern.
522 * @param pszName Name to match against the pattern.
523 * @param fSeenColon Seen colon (':').
[12678]524 */
525bool Filter::patternMatch(const char *pszPat, const char *pszName,
526 bool fSeenColon)
[11571]527{
528 /* ASSUMES ASCII */
529 for (;;)
530 {
531 char chPat = *pszPat;
532 switch (chPat)
533 {
534 default:
535 if (*pszName != chPat)
536 return false;
537 break;
538
539 case '*':
540 {
541 while ((chPat = *++pszPat) == '*' || chPat == '?')
542 /* nothing */;
543
[12802]544 /* Handle a special case, the mask terminating with a colon. */
[12678]545 if (chPat == ':')
546 {
[12802]547 if (!fSeenColon && !pszPat[1])
[12678]548 return !strchr(pszName, ':');
[12802]549 fSeenColon = true;
[12678]550 }
[12802]551
[11571]552 for (;;)
553 {
554 char ch = *pszName++;
555 if ( ch == chPat
556 && ( !chPat
[12802]557 || patternMatch(pszPat + 1, pszName, fSeenColon)))
[11571]558 return true;
559 if (!ch)
560 return false;
561 }
562 /* won't ever get here */
563 break;
564 }
565
566 case '?':
567 if (!*pszName)
568 return false;
569 break;
570
[12802]571 /* Handle a special case, the mask terminating with a colon. */
572 case ':':
573 if (!fSeenColon && !pszPat[1])
574 return !*pszName;
575 if (*pszName != ':')
576 return false;
577 fSeenColon = true;
578 break;
579
[11571]580 case '\0':
581 return !*pszName;
582 }
583 pszName++;
584 pszPat++;
585 }
586 return true;
587}
588
[10713]589bool Filter::match(const ComPtr<IUnknown> object, const std::string &name) const
[10679]590{
[10725]591 ElementList::const_iterator it;
592
[11391]593 LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
[10725]594 for (it = mElements.begin(); it != mElements.end(); it++)
595 {
[11391]596 LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
[10725]597 if ((*it).first.isNull() || (*it).first == object)
598 {
599 // Objects match, compare names
[11571]600 if (patternMatch((*it).second.c_str(), name.c_str()))
[10725]601 {
[11336]602 LogFlowThisFunc(("...found!\n"));
[10725]603 return true;
604 }
605 }
606 }
[11391]607 LogAleksey(("...no matches!\n"));
[10725]608 return false;
[10713]609}
[14772]610/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use