VirtualBox

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

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

PerfAPI: Moved linux implementation of CPU/MHz to CollectorHAL since it is generic. Windows implementation needs to be moved to RTMpGetCurFrequency.

  • 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 11498 2008-08-19 18:50:33Z 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.215389.xyz. 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 data for obj(%p)...\n", this, __PRETTY_FUNCTION__, (void *)mObject));
122 collect();
123 }
124 }
125}
126
127/*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
128{
129 LogFlowThisFunc (("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
130 return mObject == object;
131}*/
132
133void HostCpuLoad::init(ULONG period, ULONG length)
134{
135 mPeriod = period;
136 mLength = length;
137 mUser->init(mLength);
138 mKernel->init(mLength);
139 mIdle->init(mLength);
140}
141
142void HostCpuLoad::collect()
143{
144 ULONG user, kernel, idle;
145 int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
146 if (RT_SUCCESS(rc))
147 {
148 mUser->put(user);
149 mKernel->put(kernel);
150 mIdle->put(idle);
151 }
152}
153
154void HostCpuLoadRaw::collect()
155{
156 uint64_t user, kernel, idle;
157 uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
158
159 int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
160 if (RT_SUCCESS(rc))
161 {
162 userDiff = user - mUserPrev;
163 kernelDiff = kernel - mKernelPrev;
164 idleDiff = idle - mIdlePrev;
165 totalDiff = userDiff + kernelDiff + idleDiff;
166
167 if (totalDiff == 0)
168 {
169 /* This is only possible if none of counters has changed! */
170 LogFlowThisFunc (("Impossible! User, kernel and idle raw "
171 "counters has not changed since last sample.\n" ));
172 mUser->put(0);
173 mKernel->put(0);
174 mIdle->put(0);
175 }
176 else
177 {
178 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
179 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
180 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
181 }
182
183 mUserPrev = user;
184 mKernelPrev = kernel;
185 mIdlePrev = idle;
186 }
187}
188
189void HostCpuMhz::init(ULONG period, ULONG length)
190{
191 mPeriod = period;
192 mLength = length;
193 mMHz->init(mLength);
194}
195
196void HostCpuMhz::collect()
197{
198 ULONG mhz;
199 int rc = mHAL->getHostCpuMHz(&mhz);
200 if (RT_SUCCESS(rc))
201 mMHz->put(mhz);
202}
203
204void HostRamUsage::init(ULONG period, ULONG length)
205{
206 mPeriod = period;
207 mLength = length;
208 mTotal->init(mLength);
209 mUsed->init(mLength);
210 mAvailable->init(mLength);
211}
212
213void HostRamUsage::collect()
214{
215 ULONG total, used, available;
216 int rc = mHAL->getHostMemoryUsage(&total, &used, &available);
217 if (RT_SUCCESS(rc))
218 {
219 mTotal->put(total);
220 mUsed->put(used);
221 mAvailable->put(available);
222 }
223}
224
225
226
227void MachineCpuLoad::init(ULONG period, ULONG length)
228{
229 mPeriod = period;
230 mLength = length;
231 mUser->init(mLength);
232 mKernel->init(mLength);
233}
234
235void MachineCpuLoad::collect()
236{
237 ULONG user, kernel;
238 int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
239 if (RT_SUCCESS(rc))
240 {
241 mUser->put(user);
242 mKernel->put(kernel);
243 }
244}
245
246void MachineCpuLoadRaw::collect()
247{
248 uint64_t processUser, processKernel, hostTotal;
249
250 int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
251 if (RT_SUCCESS(rc))
252 {
253 if (hostTotal == mHostTotalPrev)
254 {
255 /* Nearly impossible, but... */
256 mUser->put(0);
257 mKernel->put(0);
258 }
259 else
260 {
261 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
262 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
263 }
264
265 mHostTotalPrev = hostTotal;
266 mProcessUserPrev = processUser;
267 mProcessKernelPrev = processKernel;
268 }
269}
270
271void MachineRamUsage::init(ULONG period, ULONG length)
272{
273 mPeriod = period;
274 mLength = length;
275 mUsed->init(mLength);
276}
277
278void MachineRamUsage::collect()
279{
280 ULONG used;
281 int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
282 if (RT_SUCCESS(rc))
283 mUsed->put(used);
284}
285
286void CircularBuffer::init(ULONG length)
287{
288 if (mData)
289 RTMemFree(mData);
290 mLength = length;
291 if (mLength)
292 mData = (ULONG *)RTMemAllocZ(length * sizeof(ULONG));
293 else
294 mData = NULL;
295 mWrapped = false;
296 mEnd = 0;
297}
298
299ULONG CircularBuffer::length()
300{
301 return mWrapped ? mLength : mEnd;
302}
303
304void CircularBuffer::put(ULONG value)
305{
306 if (mData)
307 {
308 mData[mEnd++] = value;
309 if (mEnd >= mLength)
310 {
311 mEnd = 0;
312 mWrapped = true;
313 }
314 }
315}
316
317void CircularBuffer::copyTo(ULONG *data)
318{
319 if (mWrapped)
320 {
321 memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
322 // Copy the wrapped part
323 if (mEnd)
324 memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
325 }
326 else
327 memcpy(data, mData, mEnd * sizeof(ULONG));
328}
329
330void SubMetric::query(ULONG *data)
331{
332 copyTo(data);
333}
334
335void Metric::query(ULONG **data, ULONG *count)
336{
337 ULONG length;
338 ULONG *tmpData;
339
340 length = mSubMetric->length();
341 if (length)
342 {
343 tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
344 mSubMetric->query(tmpData);
345 if (mAggregate)
346 {
347 *count = 1;
348 *data = (ULONG*)RTMemAlloc(sizeof(**data));
349 **data = mAggregate->compute(tmpData, length);
350 RTMemFree(tmpData);
351 }
352 else
353 {
354 *count = length;
355 *data = tmpData;
356 }
357 }
358 else
359 {
360 *count = 0;
361 *data = 0;
362 }
363}
364
365ULONG AggregateAvg::compute(ULONG *data, ULONG length)
366{
367 uint64_t tmp = 0;
368 for (ULONG i = 0; i < length; ++i)
369 tmp += data[i];
370 return (ULONG)(tmp / length);
371}
372
373const char * AggregateAvg::getName()
374{
375 return "avg";
376}
377
378ULONG AggregateMin::compute(ULONG *data, ULONG length)
379{
380 ULONG tmp = *data;
381 for (ULONG i = 0; i < length; ++i)
382 if (data[i] < tmp)
383 tmp = data[i];
384 return tmp;
385}
386
387const char * AggregateMin::getName()
388{
389 return "min";
390}
391
392ULONG AggregateMax::compute(ULONG *data, ULONG length)
393{
394 ULONG tmp = *data;
395 for (ULONG i = 0; i < length; ++i)
396 if (data[i] > tmp)
397 tmp = data[i];
398 return tmp;
399}
400
401const char * AggregateMax::getName()
402{
403 return "max";
404}
405
406Filter::Filter(ComSafeArrayIn(INPTR BSTR, metricNames),
407 ComSafeArrayIn(IUnknown *, objects))
408{
409 com::SafeArray <INPTR BSTR> nameArray(ComSafeArrayInArg(metricNames));
410
411 if (ComSafeArrayInIsNull(objects))
412 {
413 if (nameArray.size())
414 {
415 for (size_t i = 0; i < nameArray.size(); ++i)
416 processMetricList(std::string(com::Utf8Str(nameArray[i])), ComPtr<IUnknown>());
417 }
418 else
419 processMetricList(std::string("*"), ComPtr<IUnknown>());
420 }
421 else
422 {
423 com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
424
425 for (size_t i = 0; i < objectArray.size(); ++i)
426 switch (nameArray.size())
427 {
428 case 0:
429 processMetricList(std::string("*"), objectArray[i]);
430 break;
431 case 1:
432 processMetricList(std::string(com::Utf8Str(nameArray[0])), objectArray[i]);
433 break;
434 default:
435 processMetricList(std::string(com::Utf8Str(nameArray[i])), objectArray[i]);
436 break;
437 }
438 }
439}
440
441void Filter::processMetricList(const std::string &name, const ComPtr<IUnknown> object)
442{
443 std::string::size_type startPos = 0;
444
445 for (std::string::size_type pos = name.find(",");
446 pos != std::string::npos;
447 pos = name.find(",", startPos))
448 {
449 mElements.push_back(std::make_pair(object, name.substr(startPos, pos - startPos)));
450 startPos = pos + 1;
451 }
452 mElements.push_back(std::make_pair(object, name.substr(startPos)));
453}
454
455bool Filter::match(const ComPtr<IUnknown> object, const std::string &name) const
456{
457 ElementList::const_iterator it;
458
459 LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
460 for (it = mElements.begin(); it != mElements.end(); it++)
461 {
462 LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
463 if ((*it).first.isNull() || (*it).first == object)
464 {
465 // Objects match, compare names
466 if ((*it).second == "*" || (*it).second == name)
467 {
468 LogFlowThisFunc(("...found!\n"));
469 return true;
470 }
471 }
472 }
473 LogAleksey(("...no matches!\n"));
474 return false;
475}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette