VirtualBox

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

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

PerfAPI: Removed Darwin-specific stub for CPU/MHz

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