[10641] | 1 | /* $Id: Performance.cpp 15051 2008-12-05 17:20:00Z 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 |
|
---|
[10868] | 24 | /*
|
---|
| 25 | * @todo list:
|
---|
| 26 | *
|
---|
[11498] | 27 | * 1) Detection of erroneous metric names
|
---|
[10868] | 28 | */
|
---|
| 29 |
|
---|
[13915] | 30 | #include "Performance.h"
|
---|
| 31 |
|
---|
[10679] | 32 | #include <VBox/com/array.h>
|
---|
[10641] | 33 | #include <VBox/com/ptr.h>
|
---|
[10679] | 34 | #include <VBox/com/string.h>
|
---|
[10641] | 35 | #include <VBox/err.h>
|
---|
| 36 | #include <iprt/string.h>
|
---|
| 37 | #include <iprt/mem.h>
|
---|
[11689] | 38 | #include <iprt/cpuset.h>
|
---|
[10641] | 39 |
|
---|
[12400] | 40 | #include <algorithm>
|
---|
| 41 |
|
---|
[10868] | 42 | #include "Logging.h"
|
---|
[10641] | 43 |
|
---|
| 44 | using namespace pm;
|
---|
| 45 |
|
---|
| 46 | // Stubs for non-pure virtual methods
|
---|
| 47 |
|
---|
[11180] | 48 | int CollectorHAL::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
|
---|
[10641] | 49 | {
|
---|
| 50 | return E_NOTIMPL;
|
---|
| 51 | }
|
---|
| 52 |
|
---|
[11180] | 53 | int CollectorHAL::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
|
---|
[10641] | 54 | {
|
---|
| 55 | return E_NOTIMPL;
|
---|
| 56 | }
|
---|
| 57 |
|
---|
[10868] | 58 | int CollectorHAL::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
|
---|
[10641] | 59 | {
|
---|
| 60 | return E_NOTIMPL;
|
---|
| 61 | }
|
---|
| 62 |
|
---|
[10868] | 63 | int CollectorHAL::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
|
---|
[10641] | 64 | {
|
---|
| 65 | return E_NOTIMPL;
|
---|
| 66 | }
|
---|
| 67 |
|
---|
[11498] | 68 | /* Generic implementations */
|
---|
| 69 |
|
---|
| 70 | int CollectorHAL::getHostCpuMHz(ULONG *mhz)
|
---|
| 71 | {
|
---|
[11591] | 72 | unsigned cCpus = 0;
|
---|
| 73 | uint64_t u64TotalMHz = 0;
|
---|
| 74 | RTCPUSET OnlineSet;
|
---|
| 75 | RTMpGetOnlineSet(&OnlineSet);
|
---|
| 76 | for (RTCPUID iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
|
---|
[11810] | 77 | {
|
---|
| 78 | LogAleksey(("{%p} " LOG_FN_FMT ": Checking if CPU %d is member of online set...\n",
|
---|
[11689] | 79 | this, __PRETTY_FUNCTION__, (int)iCpu));
|
---|
[11591] | 80 | if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
|
---|
| 81 | {
|
---|
[11810] | 82 | LogAleksey(("{%p} " LOG_FN_FMT ": Getting frequency for CPU %d...\n",
|
---|
[11689] | 83 | this, __PRETTY_FUNCTION__, (int)iCpu));
|
---|
[11591] | 84 | uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
|
---|
| 85 | if (uMHz != 0)
|
---|
| 86 | {
|
---|
[11810] | 87 | LogAleksey(("{%p} " LOG_FN_FMT ": CPU %d %u MHz\n",
|
---|
[11689] | 88 | this, __PRETTY_FUNCTION__, (int)iCpu, uMHz));
|
---|
[11591] | 89 | u64TotalMHz += uMHz;
|
---|
| 90 | cCpus++;
|
---|
| 91 | }
|
---|
| 92 | }
|
---|
[11810] | 93 | }
|
---|
[11591] | 94 |
|
---|
[12024] | 95 | // @todo Replace 'if' with 'AssertReturn' when done debugging
|
---|
| 96 | //AssertReturn(cCpus, VERR_NOT_IMPLEMENTED);
|
---|
| 97 | if (cCpus == 0) return VERR_NOT_IMPLEMENTED;
|
---|
| 98 | *mhz = (ULONG)(u64TotalMHz / cCpus);
|
---|
[11591] | 99 |
|
---|
[11498] | 100 | return VINF_SUCCESS;
|
---|
| 101 | }
|
---|
| 102 |
|
---|
[12400] | 103 | bool BaseMetric::collectorBeat(uint64_t nowAt)
|
---|
[10713] | 104 | {
|
---|
| 105 | if (isEnabled())
|
---|
| 106 | {
|
---|
| 107 | if (nowAt - mLastSampleTaken >= mPeriod * 1000)
|
---|
| 108 | {
|
---|
| 109 | mLastSampleTaken = nowAt;
|
---|
[11591] | 110 | Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
|
---|
[11501] | 111 | this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
|
---|
[12400] | 112 | return true;
|
---|
[10713] | 113 | }
|
---|
| 114 | }
|
---|
[12400] | 115 | return false;
|
---|
[10713] | 116 | }
|
---|
| 117 |
|
---|
[10868] | 118 | /*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
|
---|
| 119 | {
|
---|
| 120 | LogFlowThisFunc (("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
|
---|
| 121 | return mObject == object;
|
---|
| 122 | }*/
|
---|
| 123 |
|
---|
[11180] | 124 | void HostCpuLoad::init(ULONG period, ULONG length)
|
---|
[10641] | 125 | {
|
---|
| 126 | mPeriod = period;
|
---|
| 127 | mLength = length;
|
---|
| 128 | mUser->init(mLength);
|
---|
| 129 | mKernel->init(mLength);
|
---|
| 130 | mIdle->init(mLength);
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | void HostCpuLoad::collect()
|
---|
| 134 | {
|
---|
[11180] | 135 | ULONG user, kernel, idle;
|
---|
[10753] | 136 | int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
|
---|
| 137 | if (RT_SUCCESS(rc))
|
---|
| 138 | {
|
---|
| 139 | mUser->put(user);
|
---|
| 140 | mKernel->put(kernel);
|
---|
| 141 | mIdle->put(idle);
|
---|
| 142 | }
|
---|
[10641] | 143 | }
|
---|
| 144 |
|
---|
[12400] | 145 | void HostCpuLoadRaw::preCollect(CollectorHints& hints)
|
---|
| 146 | {
|
---|
| 147 | hints.collectHostCpuLoad();
|
---|
| 148 | }
|
---|
| 149 |
|
---|
[10641] | 150 | void HostCpuLoadRaw::collect()
|
---|
| 151 | {
|
---|
[10868] | 152 | uint64_t user, kernel, idle;
|
---|
| 153 | uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
|
---|
[10641] | 154 |
|
---|
[10713] | 155 | int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
|
---|
| 156 | if (RT_SUCCESS(rc))
|
---|
| 157 | {
|
---|
| 158 | userDiff = user - mUserPrev;
|
---|
| 159 | kernelDiff = kernel - mKernelPrev;
|
---|
| 160 | idleDiff = idle - mIdlePrev;
|
---|
| 161 | totalDiff = userDiff + kernelDiff + idleDiff;
|
---|
[10868] | 162 |
|
---|
| 163 | if (totalDiff == 0)
|
---|
| 164 | {
|
---|
| 165 | /* This is only possible if none of counters has changed! */
|
---|
| 166 | LogFlowThisFunc (("Impossible! User, kernel and idle raw "
|
---|
| 167 | "counters has not changed since last sample.\n" ));
|
---|
| 168 | mUser->put(0);
|
---|
| 169 | mKernel->put(0);
|
---|
| 170 | mIdle->put(0);
|
---|
| 171 | }
|
---|
| 172 | else
|
---|
| 173 | {
|
---|
[11180] | 174 | mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
|
---|
| 175 | mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
|
---|
| 176 | mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
|
---|
[10868] | 177 | }
|
---|
[11591] | 178 |
|
---|
[10713] | 179 | mUserPrev = user;
|
---|
| 180 | mKernelPrev = kernel;
|
---|
| 181 | mIdlePrev = idle;
|
---|
| 182 | }
|
---|
[10641] | 183 | }
|
---|
| 184 |
|
---|
[11180] | 185 | void HostCpuMhz::init(ULONG period, ULONG length)
|
---|
[10679] | 186 | {
|
---|
| 187 | mPeriod = period;
|
---|
| 188 | mLength = length;
|
---|
| 189 | mMHz->init(mLength);
|
---|
| 190 | }
|
---|
| 191 |
|
---|
[10641] | 192 | void HostCpuMhz::collect()
|
---|
| 193 | {
|
---|
[11180] | 194 | ULONG mhz;
|
---|
[10713] | 195 | int rc = mHAL->getHostCpuMHz(&mhz);
|
---|
| 196 | if (RT_SUCCESS(rc))
|
---|
| 197 | mMHz->put(mhz);
|
---|
[10641] | 198 | }
|
---|
| 199 |
|
---|
[11180] | 200 | void HostRamUsage::init(ULONG period, ULONG length)
|
---|
[10679] | 201 | {
|
---|
| 202 | mPeriod = period;
|
---|
| 203 | mLength = length;
|
---|
| 204 | mTotal->init(mLength);
|
---|
| 205 | mUsed->init(mLength);
|
---|
| 206 | mAvailable->init(mLength);
|
---|
| 207 | }
|
---|
| 208 |
|
---|
[12400] | 209 | void HostRamUsage::preCollect(CollectorHints& hints)
|
---|
| 210 | {
|
---|
| 211 | hints.collectHostRamUsage();
|
---|
| 212 | }
|
---|
| 213 |
|
---|
[10641] | 214 | void HostRamUsage::collect()
|
---|
| 215 | {
|
---|
[11180] | 216 | ULONG total, used, available;
|
---|
[10713] | 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 | }
|
---|
[10641] | 224 | }
|
---|
| 225 |
|
---|
| 226 |
|
---|
[10679] | 227 |
|
---|
[11180] | 228 | void MachineCpuLoad::init(ULONG period, ULONG length)
|
---|
[10679] | 229 | {
|
---|
| 230 | mPeriod = period;
|
---|
| 231 | mLength = length;
|
---|
| 232 | mUser->init(mLength);
|
---|
| 233 | mKernel->init(mLength);
|
---|
| 234 | }
|
---|
| 235 |
|
---|
[10641] | 236 | void MachineCpuLoad::collect()
|
---|
| 237 | {
|
---|
[11180] | 238 | ULONG user, kernel;
|
---|
[10713] | 239 | int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
|
---|
| 240 | if (RT_SUCCESS(rc))
|
---|
| 241 | {
|
---|
| 242 | mUser->put(user);
|
---|
| 243 | mKernel->put(kernel);
|
---|
| 244 | }
|
---|
[10641] | 245 | }
|
---|
| 246 |
|
---|
[12400] | 247 | void MachineCpuLoadRaw::preCollect(CollectorHints& hints)
|
---|
| 248 | {
|
---|
| 249 | hints.collectProcessCpuLoad(mProcess);
|
---|
| 250 | }
|
---|
| 251 |
|
---|
[10641] | 252 | void MachineCpuLoadRaw::collect()
|
---|
| 253 | {
|
---|
[10868] | 254 | uint64_t processUser, processKernel, hostTotal;
|
---|
[10641] | 255 |
|
---|
[10868] | 256 | int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
|
---|
[10713] | 257 | if (RT_SUCCESS(rc))
|
---|
| 258 | {
|
---|
[10868] | 259 | if (hostTotal == mHostTotalPrev)
|
---|
[10713] | 260 | {
|
---|
[10868] | 261 | /* Nearly impossible, but... */
|
---|
| 262 | mUser->put(0);
|
---|
| 263 | mKernel->put(0);
|
---|
[10713] | 264 | }
|
---|
[10868] | 265 | else
|
---|
| 266 | {
|
---|
[11180] | 267 | mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
|
---|
| 268 | mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
|
---|
[10868] | 269 | }
|
---|
[11591] | 270 |
|
---|
[10868] | 271 | mHostTotalPrev = hostTotal;
|
---|
| 272 | mProcessUserPrev = processUser;
|
---|
| 273 | mProcessKernelPrev = processKernel;
|
---|
[10713] | 274 | }
|
---|
[10641] | 275 | }
|
---|
| 276 |
|
---|
[11180] | 277 | void MachineRamUsage::init(ULONG period, ULONG length)
|
---|
[10679] | 278 | {
|
---|
| 279 | mPeriod = period;
|
---|
| 280 | mLength = length;
|
---|
| 281 | mUsed->init(mLength);
|
---|
| 282 | }
|
---|
| 283 |
|
---|
[12400] | 284 | void MachineRamUsage::preCollect(CollectorHints& hints)
|
---|
| 285 | {
|
---|
| 286 | hints.collectProcessRamUsage(mProcess);
|
---|
| 287 | }
|
---|
| 288 |
|
---|
[10641] | 289 | void MachineRamUsage::collect()
|
---|
| 290 | {
|
---|
[11180] | 291 | ULONG used;
|
---|
[10713] | 292 | int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
|
---|
| 293 | if (RT_SUCCESS(rc))
|
---|
| 294 | mUsed->put(used);
|
---|
[10641] | 295 | }
|
---|
| 296 |
|
---|
[11180] | 297 | void CircularBuffer::init(ULONG length)
|
---|
[10641] | 298 | {
|
---|
| 299 | if (mData)
|
---|
| 300 | RTMemFree(mData);
|
---|
| 301 | mLength = length;
|
---|
[11481] | 302 | if (mLength)
|
---|
| 303 | mData = (ULONG *)RTMemAllocZ(length * sizeof(ULONG));
|
---|
| 304 | else
|
---|
| 305 | mData = NULL;
|
---|
[10713] | 306 | mWrapped = false;
|
---|
| 307 | mEnd = 0;
|
---|
[12973] | 308 | mSequenceNumber = 0;
|
---|
[10641] | 309 | }
|
---|
| 310 |
|
---|
[11180] | 311 | ULONG CircularBuffer::length()
|
---|
[10641] | 312 | {
|
---|
[10713] | 313 | return mWrapped ? mLength : mEnd;
|
---|
[10641] | 314 | }
|
---|
| 315 |
|
---|
[11180] | 316 | void CircularBuffer::put(ULONG value)
|
---|
[10641] | 317 | {
|
---|
[10713] | 318 | if (mData)
|
---|
| 319 | {
|
---|
| 320 | mData[mEnd++] = value;
|
---|
| 321 | if (mEnd >= mLength)
|
---|
| 322 | {
|
---|
| 323 | mEnd = 0;
|
---|
| 324 | mWrapped = true;
|
---|
| 325 | }
|
---|
[12973] | 326 | ++mSequenceNumber;
|
---|
[10713] | 327 | }
|
---|
[10641] | 328 | }
|
---|
| 329 |
|
---|
[11180] | 330 | void CircularBuffer::copyTo(ULONG *data)
|
---|
[10641] | 331 | {
|
---|
[10713] | 332 | if (mWrapped)
|
---|
| 333 | {
|
---|
[11180] | 334 | memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
|
---|
[10713] | 335 | // Copy the wrapped part
|
---|
| 336 | if (mEnd)
|
---|
[11180] | 337 | memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
|
---|
[10713] | 338 | }
|
---|
| 339 | else
|
---|
[11180] | 340 | memcpy(data, mData, mEnd * sizeof(ULONG));
|
---|
[10641] | 341 | }
|
---|
| 342 |
|
---|
[11180] | 343 | void SubMetric::query(ULONG *data)
|
---|
[10641] | 344 | {
|
---|
[10713] | 345 | copyTo(data);
|
---|
[10641] | 346 | }
|
---|
[11591] | 347 |
|
---|
[12973] | 348 | void Metric::query(ULONG **data, ULONG *count, ULONG *sequenceNumber)
|
---|
[10641] | 349 | {
|
---|
[11180] | 350 | ULONG length;
|
---|
| 351 | ULONG *tmpData;
|
---|
[10641] | 352 |
|
---|
| 353 | length = mSubMetric->length();
|
---|
[12973] | 354 | *sequenceNumber = mSubMetric->getSequenceNumber() - length;
|
---|
[10641] | 355 | if (length)
|
---|
| 356 | {
|
---|
[11180] | 357 | tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
|
---|
[10713] | 358 | mSubMetric->query(tmpData);
|
---|
[10641] | 359 | if (mAggregate)
|
---|
| 360 | {
|
---|
| 361 | *count = 1;
|
---|
[11180] | 362 | *data = (ULONG*)RTMemAlloc(sizeof(**data));
|
---|
[10641] | 363 | **data = mAggregate->compute(tmpData, length);
|
---|
[10713] | 364 | RTMemFree(tmpData);
|
---|
[10641] | 365 | }
|
---|
| 366 | else
|
---|
| 367 | {
|
---|
| 368 | *count = length;
|
---|
| 369 | *data = tmpData;
|
---|
| 370 | }
|
---|
| 371 | }
|
---|
| 372 | else
|
---|
| 373 | {
|
---|
| 374 | *count = 0;
|
---|
| 375 | *data = 0;
|
---|
| 376 | }
|
---|
| 377 | }
|
---|
| 378 |
|
---|
[11180] | 379 | ULONG AggregateAvg::compute(ULONG *data, ULONG length)
|
---|
[10641] | 380 | {
|
---|
[10713] | 381 | uint64_t tmp = 0;
|
---|
[11180] | 382 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 383 | tmp += data[i];
|
---|
[11180] | 384 | return (ULONG)(tmp / length);
|
---|
[10641] | 385 | }
|
---|
| 386 |
|
---|
| 387 | const char * AggregateAvg::getName()
|
---|
| 388 | {
|
---|
| 389 | return "avg";
|
---|
| 390 | }
|
---|
| 391 |
|
---|
[11180] | 392 | ULONG AggregateMin::compute(ULONG *data, ULONG length)
|
---|
[10641] | 393 | {
|
---|
[11180] | 394 | ULONG tmp = *data;
|
---|
| 395 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 396 | if (data[i] < tmp)
|
---|
| 397 | tmp = data[i];
|
---|
| 398 | return tmp;
|
---|
[10641] | 399 | }
|
---|
| 400 |
|
---|
| 401 | const char * AggregateMin::getName()
|
---|
| 402 | {
|
---|
| 403 | return "min";
|
---|
| 404 | }
|
---|
| 405 |
|
---|
[11180] | 406 | ULONG AggregateMax::compute(ULONG *data, ULONG length)
|
---|
[10641] | 407 | {
|
---|
[11180] | 408 | ULONG tmp = *data;
|
---|
| 409 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 410 | if (data[i] > tmp)
|
---|
| 411 | tmp = data[i];
|
---|
| 412 | return tmp;
|
---|
[10641] | 413 | }
|
---|
| 414 |
|
---|
| 415 | const char * AggregateMax::getName()
|
---|
| 416 | {
|
---|
| 417 | return "max";
|
---|
| 418 | }
|
---|
| 419 |
|
---|
[15051] | 420 | Filter::Filter(ComSafeArrayIn(IN_BSTR, metricNames),
|
---|
[10679] | 421 | ComSafeArrayIn(IUnknown *, objects))
|
---|
| 422 | {
|
---|
[12942] | 423 | /*
|
---|
| 424 | * Let's work around null/empty safe array mess. I am not sure there is
|
---|
| 425 | * a way to pass null arrays via webservice, I haven't found one. So I
|
---|
| 426 | * guess the users will be forced to use empty arrays instead. Constructing
|
---|
| 427 | * an empty SafeArray is a bit awkward, so what we do in this method is
|
---|
| 428 | * actually convert null arrays to empty arrays and pass them down to
|
---|
| 429 | * init() method. If someone knows how to do it better, please be my guest,
|
---|
| 430 | * fix it.
|
---|
| 431 | */
|
---|
| 432 | if (ComSafeArrayInIsNull(metricNames))
|
---|
| 433 | {
|
---|
| 434 | com::SafeArray <BSTR> nameArray;
|
---|
| 435 | if (ComSafeArrayInIsNull(objects))
|
---|
| 436 | {
|
---|
| 437 | com::SafeIfaceArray <IUnknown> objectArray;
|
---|
| 438 | objectArray.reset(0);
|
---|
| 439 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 440 | ComSafeArrayAsInParam(objectArray));
|
---|
| 441 | }
|
---|
| 442 | else
|
---|
| 443 | {
|
---|
| 444 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
| 445 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 446 | ComSafeArrayAsInParam(objectArray));
|
---|
| 447 | }
|
---|
| 448 | }
|
---|
| 449 | else
|
---|
| 450 | {
|
---|
[15051] | 451 | com::SafeArray <IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
|
---|
[12942] | 452 | if (ComSafeArrayInIsNull(objects))
|
---|
| 453 | {
|
---|
| 454 | com::SafeIfaceArray <IUnknown> objectArray;
|
---|
| 455 | objectArray.reset(0);
|
---|
| 456 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 457 | ComSafeArrayAsInParam(objectArray));
|
---|
| 458 | }
|
---|
| 459 | else
|
---|
| 460 | {
|
---|
| 461 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
| 462 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 463 | ComSafeArrayAsInParam(objectArray));
|
---|
| 464 | }
|
---|
| 465 | }
|
---|
| 466 | }
|
---|
| 467 |
|
---|
[15051] | 468 | void Filter::init(ComSafeArrayIn(IN_BSTR, metricNames),
|
---|
[12942] | 469 | ComSafeArrayIn(IUnknown *, objects))
|
---|
| 470 | {
|
---|
[15051] | 471 | com::SafeArray <IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
|
---|
[12942] | 472 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
[11383] | 473 |
|
---|
[12942] | 474 | if (!objectArray.size())
|
---|
[10725] | 475 | {
|
---|
| 476 | if (nameArray.size())
|
---|
| 477 | {
|
---|
| 478 | for (size_t i = 0; i < nameArray.size(); ++i)
|
---|
| 479 | processMetricList(std::string(com::Utf8Str(nameArray[i])), ComPtr<IUnknown>());
|
---|
| 480 | }
|
---|
| 481 | else
|
---|
| 482 | processMetricList(std::string("*"), ComPtr<IUnknown>());
|
---|
| 483 | }
|
---|
| 484 | else
|
---|
| 485 | {
|
---|
| 486 | for (size_t i = 0; i < objectArray.size(); ++i)
|
---|
| 487 | switch (nameArray.size())
|
---|
| 488 | {
|
---|
| 489 | case 0:
|
---|
| 490 | processMetricList(std::string("*"), objectArray[i]);
|
---|
| 491 | break;
|
---|
| 492 | case 1:
|
---|
| 493 | processMetricList(std::string(com::Utf8Str(nameArray[0])), objectArray[i]);
|
---|
| 494 | break;
|
---|
| 495 | default:
|
---|
| 496 | processMetricList(std::string(com::Utf8Str(nameArray[i])), objectArray[i]);
|
---|
| 497 | break;
|
---|
| 498 | }
|
---|
| 499 | }
|
---|
[10679] | 500 | }
|
---|
| 501 |
|
---|
[10713] | 502 | void Filter::processMetricList(const std::string &name, const ComPtr<IUnknown> object)
|
---|
[10679] | 503 | {
|
---|
| 504 | std::string::size_type startPos = 0;
|
---|
| 505 |
|
---|
| 506 | for (std::string::size_type pos = name.find(",");
|
---|
| 507 | pos != std::string::npos;
|
---|
| 508 | pos = name.find(",", startPos))
|
---|
| 509 | {
|
---|
| 510 | mElements.push_back(std::make_pair(object, name.substr(startPos, pos - startPos)));
|
---|
| 511 | startPos = pos + 1;
|
---|
| 512 | }
|
---|
| 513 | mElements.push_back(std::make_pair(object, name.substr(startPos)));
|
---|
| 514 | }
|
---|
| 515 |
|
---|
[12802] | 516 | /**
|
---|
| 517 | * The following method was borrowed from stamR3Match (VMM/STAM.cpp) and
|
---|
| 518 | * modified to handle the special case of trailing colon in the pattern.
|
---|
| 519 | *
|
---|
| 520 | * @returns True if matches, false if not.
|
---|
| 521 | * @param pszPat Pattern.
|
---|
| 522 | * @param pszName Name to match against the pattern.
|
---|
| 523 | * @param fSeenColon Seen colon (':').
|
---|
[12678] | 524 | */
|
---|
| 525 | bool Filter::patternMatch(const char *pszPat, const char *pszName,
|
---|
| 526 | bool fSeenColon)
|
---|
[11571] | 527 | {
|
---|
| 528 | /* ASSUMES ASCII */
|
---|
| 529 | for (;;)
|
---|
| 530 | {
|
---|
| 531 | char chPat = *pszPat;
|
---|
| 532 | switch (chPat)
|
---|
| 533 | {
|
---|
| 534 | default:
|
---|
| 535 | if (*pszName != chPat)
|
---|
| 536 | return false;
|
---|
| 537 | break;
|
---|
| 538 |
|
---|
| 539 | case '*':
|
---|
| 540 | {
|
---|
| 541 | while ((chPat = *++pszPat) == '*' || chPat == '?')
|
---|
| 542 | /* nothing */;
|
---|
| 543 |
|
---|
[12802] | 544 | /* Handle a special case, the mask terminating with a colon. */
|
---|
[12678] | 545 | if (chPat == ':')
|
---|
| 546 | {
|
---|
[12802] | 547 | if (!fSeenColon && !pszPat[1])
|
---|
[12678] | 548 | return !strchr(pszName, ':');
|
---|
[12802] | 549 | fSeenColon = true;
|
---|
[12678] | 550 | }
|
---|
[12802] | 551 |
|
---|
[11571] | 552 | for (;;)
|
---|
| 553 | {
|
---|
| 554 | char ch = *pszName++;
|
---|
| 555 | if ( ch == chPat
|
---|
| 556 | && ( !chPat
|
---|
[12802] | 557 | || patternMatch(pszPat + 1, pszName, fSeenColon)))
|
---|
[11571] | 558 | return true;
|
---|
| 559 | if (!ch)
|
---|
| 560 | return false;
|
---|
| 561 | }
|
---|
| 562 | /* won't ever get here */
|
---|
| 563 | break;
|
---|
| 564 | }
|
---|
| 565 |
|
---|
| 566 | case '?':
|
---|
| 567 | if (!*pszName)
|
---|
| 568 | return false;
|
---|
| 569 | break;
|
---|
| 570 |
|
---|
[12802] | 571 | /* Handle a special case, the mask terminating with a colon. */
|
---|
| 572 | case ':':
|
---|
| 573 | if (!fSeenColon && !pszPat[1])
|
---|
| 574 | return !*pszName;
|
---|
| 575 | if (*pszName != ':')
|
---|
| 576 | return false;
|
---|
| 577 | fSeenColon = true;
|
---|
| 578 | break;
|
---|
| 579 |
|
---|
[11571] | 580 | case '\0':
|
---|
| 581 | return !*pszName;
|
---|
| 582 | }
|
---|
| 583 | pszName++;
|
---|
| 584 | pszPat++;
|
---|
| 585 | }
|
---|
| 586 | return true;
|
---|
| 587 | }
|
---|
| 588 |
|
---|
[10713] | 589 | bool Filter::match(const ComPtr<IUnknown> object, const std::string &name) const
|
---|
[10679] | 590 | {
|
---|
[10725] | 591 | ElementList::const_iterator it;
|
---|
| 592 |
|
---|
[11391] | 593 | LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
|
---|
[10725] | 594 | for (it = mElements.begin(); it != mElements.end(); it++)
|
---|
| 595 | {
|
---|
[11391] | 596 | LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
|
---|
[10725] | 597 | if ((*it).first.isNull() || (*it).first == object)
|
---|
| 598 | {
|
---|
| 599 | // Objects match, compare names
|
---|
[11571] | 600 | if (patternMatch((*it).second.c_str(), name.c_str()))
|
---|
[10725] | 601 | {
|
---|
[11336] | 602 | LogFlowThisFunc(("...found!\n"));
|
---|
[10725] | 603 | return true;
|
---|
| 604 | }
|
---|
| 605 | }
|
---|
| 606 | }
|
---|
[11391] | 607 | LogAleksey(("...no matches!\n"));
|
---|
[10725] | 608 | return false;
|
---|
[10713] | 609 | }
|
---|
[14772] | 610 | /* vi: set tabstop=4 shiftwidth=4 expandtab: */
|
---|