VirtualBox

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

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

PerfAPI: no more solaris-specific stub for CPU/MHz; additional logging at level4

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