VirtualBox

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

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

RTMpIsCpuOnline() for Darwin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/* $Id: Performance.cpp 11810 2008-08-29 11:52:39Z 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
24/*
25 * @todo list:
26 *
27 * 1) Detection of erroneous metric names
28 */
29
30#include <VBox/com/array.h>
31#include <VBox/com/ptr.h>
32#include <VBox/com/string.h>
33#include <VBox/err.h>
34#include <iprt/string.h>
35#include <iprt/mem.h>
36#include <iprt/cpuset.h>
37
38#include "Logging.h"
39#include "Performance.h"
40
41using namespace pm;
42
43// Default factory
44
45BaseMetric *MetricFactory::createHostCpuLoad(ComPtr<IUnknown> object, SubMetric *user, SubMetric *kernel, SubMetric *idle)
46{
47 Assert(mHAL);
48 return new HostCpuLoadRaw(mHAL, object, user, kernel, idle);
49}
50BaseMetric *MetricFactory::createHostCpuMHz(ComPtr<IUnknown> object, SubMetric *mhz)
51{
52 Assert(mHAL);
53 return new HostCpuMhz(mHAL, object, mhz);
54}
55BaseMetric *MetricFactory::createHostRamUsage(ComPtr<IUnknown> object, SubMetric *total, SubMetric *used, SubMetric *available)
56{
57 Assert(mHAL);
58 return new HostRamUsage(mHAL, object, total, used, available);
59}
60BaseMetric *MetricFactory::createMachineCpuLoad(ComPtr<IUnknown> object, RTPROCESS process, SubMetric *user, SubMetric *kernel)
61{
62 Assert(mHAL);
63 return new MachineCpuLoadRaw(mHAL, object, process, user, kernel);
64}
65BaseMetric *MetricFactory::createMachineRamUsage(ComPtr<IUnknown> object, RTPROCESS process, SubMetric *used)
66{
67 Assert(mHAL);
68 return new MachineRamUsage(mHAL, object, process, used);
69}
70
71// Stubs for non-pure virtual methods
72
73int CollectorHAL::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
74{
75 return E_NOTIMPL;
76}
77
78int CollectorHAL::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
79{
80 return E_NOTIMPL;
81}
82
83int CollectorHAL::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
84{
85 return E_NOTIMPL;
86}
87
88int CollectorHAL::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
89{
90 return E_NOTIMPL;
91}
92
93/* Generic implementations */
94
95int CollectorHAL::getHostCpuMHz(ULONG *mhz)
96{
97 unsigned cCpus = 0;
98 uint64_t u64TotalMHz = 0;
99 RTCPUSET OnlineSet;
100 RTMpGetOnlineSet(&OnlineSet);
101 for (RTCPUID iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
102 {
103 LogAleksey(("{%p} " LOG_FN_FMT ": Checking if CPU %d is member of online set...\n",
104 this, __PRETTY_FUNCTION__, (int)iCpu));
105 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
106 {
107 LogAleksey(("{%p} " LOG_FN_FMT ": Getting frequency for CPU %d...\n",
108 this, __PRETTY_FUNCTION__, (int)iCpu));
109 uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
110 if (uMHz != 0)
111 {
112 LogAleksey(("{%p} " LOG_FN_FMT ": CPU %d %u MHz\n",
113 this, __PRETTY_FUNCTION__, (int)iCpu, uMHz));
114 u64TotalMHz += uMHz;
115 cCpus++;
116 }
117 }
118 }
119
120 AssertReturn(cCpus, VERR_NOT_IMPLEMENTED);
121 *mhz = (ULONG)(u64TotalMHz / cCpus);
122
123 return VINF_SUCCESS;
124}
125
126void BaseMetric::collectorBeat(uint64_t nowAt)
127{
128 if (isEnabled())
129 {
130 if (nowAt - mLastSampleTaken >= mPeriod * 1000)
131 {
132 mLastSampleTaken = nowAt;
133 Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
134 this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
135 collect();
136 }
137 }
138}
139
140/*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
141{
142 LogFlowThisFunc (("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
143 return mObject == object;
144}*/
145
146void HostCpuLoad::init(ULONG period, ULONG length)
147{
148 mPeriod = period;
149 mLength = length;
150 mUser->init(mLength);
151 mKernel->init(mLength);
152 mIdle->init(mLength);
153}
154
155void HostCpuLoad::collect()
156{
157 ULONG user, kernel, idle;
158 int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
159 if (RT_SUCCESS(rc))
160 {
161 mUser->put(user);
162 mKernel->put(kernel);
163 mIdle->put(idle);
164 }
165}
166
167void HostCpuLoadRaw::collect()
168{
169 uint64_t user, kernel, idle;
170 uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
171
172 int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
173 if (RT_SUCCESS(rc))
174 {
175 userDiff = user - mUserPrev;
176 kernelDiff = kernel - mKernelPrev;
177 idleDiff = idle - mIdlePrev;
178 totalDiff = userDiff + kernelDiff + idleDiff;
179
180 if (totalDiff == 0)
181 {
182 /* This is only possible if none of counters has changed! */
183 LogFlowThisFunc (("Impossible! User, kernel and idle raw "
184 "counters has not changed since last sample.\n" ));
185 mUser->put(0);
186 mKernel->put(0);
187 mIdle->put(0);
188 }
189 else
190 {
191 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
192 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
193 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
194 }
195
196 mUserPrev = user;
197 mKernelPrev = kernel;
198 mIdlePrev = idle;
199 }
200}
201
202void HostCpuMhz::init(ULONG period, ULONG length)
203{
204 mPeriod = period;
205 mLength = length;
206 mMHz->init(mLength);
207}
208
209void HostCpuMhz::collect()
210{
211 ULONG mhz;
212 int rc = mHAL->getHostCpuMHz(&mhz);
213 if (RT_SUCCESS(rc))
214 mMHz->put(mhz);
215}
216
217void HostRamUsage::init(ULONG period, ULONG length)
218{
219 mPeriod = period;
220 mLength = length;
221 mTotal->init(mLength);
222 mUsed->init(mLength);
223 mAvailable->init(mLength);
224}
225
226void HostRamUsage::collect()
227{
228 ULONG total, used, available;
229 int rc = mHAL->getHostMemoryUsage(&total, &used, &available);
230 if (RT_SUCCESS(rc))
231 {
232 mTotal->put(total);
233 mUsed->put(used);
234 mAvailable->put(available);
235 }
236}
237
238
239
240void MachineCpuLoad::init(ULONG period, ULONG length)
241{
242 mPeriod = period;
243 mLength = length;
244 mUser->init(mLength);
245 mKernel->init(mLength);
246}
247
248void MachineCpuLoad::collect()
249{
250 ULONG user, kernel;
251 int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
252 if (RT_SUCCESS(rc))
253 {
254 mUser->put(user);
255 mKernel->put(kernel);
256 }
257}
258
259void MachineCpuLoadRaw::collect()
260{
261 uint64_t processUser, processKernel, hostTotal;
262
263 int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
264 if (RT_SUCCESS(rc))
265 {
266 if (hostTotal == mHostTotalPrev)
267 {
268 /* Nearly impossible, but... */
269 mUser->put(0);
270 mKernel->put(0);
271 }
272 else
273 {
274 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
275 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
276 }
277
278 mHostTotalPrev = hostTotal;
279 mProcessUserPrev = processUser;
280 mProcessKernelPrev = processKernel;
281 }
282}
283
284void MachineRamUsage::init(ULONG period, ULONG length)
285{
286 mPeriod = period;
287 mLength = length;
288 mUsed->init(mLength);
289}
290
291void MachineRamUsage::collect()
292{
293 ULONG used;
294 int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
295 if (RT_SUCCESS(rc))
296 mUsed->put(used);
297}
298
299void CircularBuffer::init(ULONG length)
300{
301 if (mData)
302 RTMemFree(mData);
303 mLength = length;
304 if (mLength)
305 mData = (ULONG *)RTMemAllocZ(length * sizeof(ULONG));
306 else
307 mData = NULL;
308 mWrapped = false;
309 mEnd = 0;
310}
311
312ULONG CircularBuffer::length()
313{
314 return mWrapped ? mLength : mEnd;
315}
316
317void CircularBuffer::put(ULONG value)
318{
319 if (mData)
320 {
321 mData[mEnd++] = value;
322 if (mEnd >= mLength)
323 {
324 mEnd = 0;
325 mWrapped = true;
326 }
327 }
328}
329
330void CircularBuffer::copyTo(ULONG *data)
331{
332 if (mWrapped)
333 {
334 memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
335 // Copy the wrapped part
336 if (mEnd)
337 memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
338 }
339 else
340 memcpy(data, mData, mEnd * sizeof(ULONG));
341}
342
343void SubMetric::query(ULONG *data)
344{
345 copyTo(data);
346}
347
348void Metric::query(ULONG **data, ULONG *count)
349{
350 ULONG length;
351 ULONG *tmpData;
352
353 length = mSubMetric->length();
354 if (length)
355 {
356 tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
357 mSubMetric->query(tmpData);
358 if (mAggregate)
359 {
360 *count = 1;
361 *data = (ULONG*)RTMemAlloc(sizeof(**data));
362 **data = mAggregate->compute(tmpData, length);
363 RTMemFree(tmpData);
364 }
365 else
366 {
367 *count = length;
368 *data = tmpData;
369 }
370 }
371 else
372 {
373 *count = 0;
374 *data = 0;
375 }
376}
377
378ULONG AggregateAvg::compute(ULONG *data, ULONG length)
379{
380 uint64_t tmp = 0;
381 for (ULONG i = 0; i < length; ++i)
382 tmp += data[i];
383 return (ULONG)(tmp / length);
384}
385
386const char * AggregateAvg::getName()
387{
388 return "avg";
389}
390
391ULONG AggregateMin::compute(ULONG *data, ULONG length)
392{
393 ULONG tmp = *data;
394 for (ULONG i = 0; i < length; ++i)
395 if (data[i] < tmp)
396 tmp = data[i];
397 return tmp;
398}
399
400const char * AggregateMin::getName()
401{
402 return "min";
403}
404
405ULONG AggregateMax::compute(ULONG *data, ULONG length)
406{
407 ULONG tmp = *data;
408 for (ULONG i = 0; i < length; ++i)
409 if (data[i] > tmp)
410 tmp = data[i];
411 return tmp;
412}
413
414const char * AggregateMax::getName()
415{
416 return "max";
417}
418
419Filter::Filter(ComSafeArrayIn(INPTR BSTR, metricNames),
420 ComSafeArrayIn(IUnknown *, objects))
421{
422 com::SafeArray <INPTR BSTR> nameArray(ComSafeArrayInArg(metricNames));
423
424 if (ComSafeArrayInIsNull(objects))
425 {
426 if (nameArray.size())
427 {
428 for (size_t i = 0; i < nameArray.size(); ++i)
429 processMetricList(std::string(com::Utf8Str(nameArray[i])), ComPtr<IUnknown>());
430 }
431 else
432 processMetricList(std::string("*"), ComPtr<IUnknown>());
433 }
434 else
435 {
436 com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
437
438 for (size_t i = 0; i < objectArray.size(); ++i)
439 switch (nameArray.size())
440 {
441 case 0:
442 processMetricList(std::string("*"), objectArray[i]);
443 break;
444 case 1:
445 processMetricList(std::string(com::Utf8Str(nameArray[0])), objectArray[i]);
446 break;
447 default:
448 processMetricList(std::string(com::Utf8Str(nameArray[i])), objectArray[i]);
449 break;
450 }
451 }
452}
453
454void Filter::processMetricList(const std::string &name, const ComPtr<IUnknown> object)
455{
456 std::string::size_type startPos = 0;
457
458 for (std::string::size_type pos = name.find(",");
459 pos != std::string::npos;
460 pos = name.find(",", startPos))
461 {
462 mElements.push_back(std::make_pair(object, name.substr(startPos, pos - startPos)));
463 startPos = pos + 1;
464 }
465 mElements.push_back(std::make_pair(object, name.substr(startPos)));
466}
467
468/* The following method was borrowed from VMM/STAM.cpp */
469bool Filter::patternMatch(const char *pszPat, const char *pszName)
470{
471 /* ASSUMES ASCII */
472 for (;;)
473 {
474 char chPat = *pszPat;
475 switch (chPat)
476 {
477 default:
478 if (*pszName != chPat)
479 return false;
480 break;
481
482 case '*':
483 {
484 while ((chPat = *++pszPat) == '*' || chPat == '?')
485 /* nothing */;
486
487 for (;;)
488 {
489 char ch = *pszName++;
490 if ( ch == chPat
491 && ( !chPat
492 || patternMatch(pszPat + 1, pszName)))
493 return true;
494 if (!ch)
495 return false;
496 }
497 /* won't ever get here */
498 break;
499 }
500
501 case '?':
502 if (!*pszName)
503 return false;
504 break;
505
506 case '\0':
507 return !*pszName;
508 }
509 pszName++;
510 pszPat++;
511 }
512 return true;
513}
514
515bool Filter::match(const ComPtr<IUnknown> object, const std::string &name) const
516{
517 ElementList::const_iterator it;
518
519 LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
520 for (it = mElements.begin(); it != mElements.end(); it++)
521 {
522 LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
523 if ((*it).first.isNull() || (*it).first == object)
524 {
525 // Objects match, compare names
526 if (patternMatch((*it).second.c_str(), name.c_str()))
527 {
528 LogFlowThisFunc(("...found!\n"));
529 return true;
530 }
531 }
532 }
533 LogAleksey(("...no matches!\n"));
534 return false;
535}
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