VirtualBox

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

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

PerfAPI: Null IN array handling changed.

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