VirtualBox

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

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

Moved annoying log messages to either level4 or private logging. Added private logging macro LogAleksey.

  • 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 11391 2008-08-13 14:48:53Z 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 Log4(("{%p} " LOG_FN_FMT ": Collecting data for obj(%p)...\n", this, __PRETTY_FUNCTION__, (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 LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
440 for (it = mElements.begin(); it != mElements.end(); it++)
441 {
442 LogAleksey(("...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 LogAleksey(("...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