[10641] | 1 | /* $Id: Performance.cpp 12973 2008-10-03 17:46:19Z 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 |
|
---|
[10679] | 30 | #include <VBox/com/array.h>
|
---|
[10641] | 31 | #include <VBox/com/ptr.h>
|
---|
[10679] | 32 | #include <VBox/com/string.h>
|
---|
[10641] | 33 | #include <VBox/err.h>
|
---|
| 34 | #include <iprt/string.h>
|
---|
| 35 | #include <iprt/mem.h>
|
---|
[11689] | 36 | #include <iprt/cpuset.h>
|
---|
[10641] | 37 |
|
---|
[12400] | 38 | #include <algorithm>
|
---|
| 39 |
|
---|
[10868] | 40 | #include "Logging.h"
|
---|
[10641] | 41 | #include "Performance.h"
|
---|
| 42 |
|
---|
| 43 | using namespace pm;
|
---|
| 44 |
|
---|
| 45 | // Stubs for non-pure virtual methods
|
---|
| 46 |
|
---|
[11180] | 47 | int CollectorHAL::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
|
---|
[10641] | 48 | {
|
---|
| 49 | return E_NOTIMPL;
|
---|
| 50 | }
|
---|
| 51 |
|
---|
[11180] | 52 | int CollectorHAL::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
|
---|
[10641] | 53 | {
|
---|
| 54 | return E_NOTIMPL;
|
---|
| 55 | }
|
---|
| 56 |
|
---|
[10868] | 57 | int CollectorHAL::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
|
---|
[10641] | 58 | {
|
---|
| 59 | return E_NOTIMPL;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
[10868] | 62 | int CollectorHAL::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
|
---|
[10641] | 63 | {
|
---|
| 64 | return E_NOTIMPL;
|
---|
| 65 | }
|
---|
| 66 |
|
---|
[11498] | 67 | /* Generic implementations */
|
---|
| 68 |
|
---|
| 69 | int CollectorHAL::getHostCpuMHz(ULONG *mhz)
|
---|
| 70 | {
|
---|
[11591] | 71 | unsigned cCpus = 0;
|
---|
| 72 | uint64_t u64TotalMHz = 0;
|
---|
| 73 | RTCPUSET OnlineSet;
|
---|
| 74 | RTMpGetOnlineSet(&OnlineSet);
|
---|
| 75 | for (RTCPUID iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
|
---|
[11810] | 76 | {
|
---|
| 77 | LogAleksey(("{%p} " LOG_FN_FMT ": Checking if CPU %d is member of online set...\n",
|
---|
[11689] | 78 | this, __PRETTY_FUNCTION__, (int)iCpu));
|
---|
[11591] | 79 | if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
|
---|
| 80 | {
|
---|
[11810] | 81 | LogAleksey(("{%p} " LOG_FN_FMT ": Getting frequency for CPU %d...\n",
|
---|
[11689] | 82 | this, __PRETTY_FUNCTION__, (int)iCpu));
|
---|
[11591] | 83 | uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
|
---|
| 84 | if (uMHz != 0)
|
---|
| 85 | {
|
---|
[11810] | 86 | LogAleksey(("{%p} " LOG_FN_FMT ": CPU %d %u MHz\n",
|
---|
[11689] | 87 | this, __PRETTY_FUNCTION__, (int)iCpu, uMHz));
|
---|
[11591] | 88 | u64TotalMHz += uMHz;
|
---|
| 89 | cCpus++;
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
[11810] | 92 | }
|
---|
[11591] | 93 |
|
---|
[12024] | 94 | // @todo Replace 'if' with 'AssertReturn' when done debugging
|
---|
| 95 | //AssertReturn(cCpus, VERR_NOT_IMPLEMENTED);
|
---|
| 96 | if (cCpus == 0) return VERR_NOT_IMPLEMENTED;
|
---|
| 97 | *mhz = (ULONG)(u64TotalMHz / cCpus);
|
---|
[11591] | 98 |
|
---|
[11498] | 99 | return VINF_SUCCESS;
|
---|
| 100 | }
|
---|
| 101 |
|
---|
[12400] | 102 | bool BaseMetric::collectorBeat(uint64_t nowAt)
|
---|
[10713] | 103 | {
|
---|
| 104 | if (isEnabled())
|
---|
| 105 | {
|
---|
| 106 | if (nowAt - mLastSampleTaken >= mPeriod * 1000)
|
---|
| 107 | {
|
---|
| 108 | mLastSampleTaken = nowAt;
|
---|
[11591] | 109 | Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
|
---|
[11501] | 110 | this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
|
---|
[12400] | 111 | return true;
|
---|
[10713] | 112 | }
|
---|
| 113 | }
|
---|
[12400] | 114 | return false;
|
---|
[10713] | 115 | }
|
---|
| 116 |
|
---|
[10868] | 117 | /*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
|
---|
| 118 | {
|
---|
| 119 | LogFlowThisFunc (("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
|
---|
| 120 | return mObject == object;
|
---|
| 121 | }*/
|
---|
| 122 |
|
---|
[11180] | 123 | void HostCpuLoad::init(ULONG period, ULONG length)
|
---|
[10641] | 124 | {
|
---|
| 125 | mPeriod = period;
|
---|
| 126 | mLength = length;
|
---|
| 127 | mUser->init(mLength);
|
---|
| 128 | mKernel->init(mLength);
|
---|
| 129 | mIdle->init(mLength);
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | void HostCpuLoad::collect()
|
---|
| 133 | {
|
---|
[11180] | 134 | ULONG user, kernel, idle;
|
---|
[10753] | 135 | int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
|
---|
| 136 | if (RT_SUCCESS(rc))
|
---|
| 137 | {
|
---|
| 138 | mUser->put(user);
|
---|
| 139 | mKernel->put(kernel);
|
---|
| 140 | mIdle->put(idle);
|
---|
| 141 | }
|
---|
[10641] | 142 | }
|
---|
| 143 |
|
---|
[12400] | 144 | void HostCpuLoadRaw::preCollect(CollectorHints& hints)
|
---|
| 145 | {
|
---|
| 146 | hints.collectHostCpuLoad();
|
---|
| 147 | }
|
---|
| 148 |
|
---|
[10641] | 149 | void HostCpuLoadRaw::collect()
|
---|
| 150 | {
|
---|
[10868] | 151 | uint64_t user, kernel, idle;
|
---|
| 152 | uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
|
---|
[10641] | 153 |
|
---|
[10713] | 154 | int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
|
---|
| 155 | if (RT_SUCCESS(rc))
|
---|
| 156 | {
|
---|
| 157 | userDiff = user - mUserPrev;
|
---|
| 158 | kernelDiff = kernel - mKernelPrev;
|
---|
| 159 | idleDiff = idle - mIdlePrev;
|
---|
| 160 | totalDiff = userDiff + kernelDiff + idleDiff;
|
---|
[10868] | 161 |
|
---|
| 162 | if (totalDiff == 0)
|
---|
| 163 | {
|
---|
| 164 | /* This is only possible if none of counters has changed! */
|
---|
| 165 | LogFlowThisFunc (("Impossible! User, kernel and idle raw "
|
---|
| 166 | "counters has not changed since last sample.\n" ));
|
---|
| 167 | mUser->put(0);
|
---|
| 168 | mKernel->put(0);
|
---|
| 169 | mIdle->put(0);
|
---|
| 170 | }
|
---|
| 171 | else
|
---|
| 172 | {
|
---|
[11180] | 173 | mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
|
---|
| 174 | mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
|
---|
| 175 | mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
|
---|
[10868] | 176 | }
|
---|
[11591] | 177 |
|
---|
[10713] | 178 | mUserPrev = user;
|
---|
| 179 | mKernelPrev = kernel;
|
---|
| 180 | mIdlePrev = idle;
|
---|
| 181 | }
|
---|
[10641] | 182 | }
|
---|
| 183 |
|
---|
[11180] | 184 | void HostCpuMhz::init(ULONG period, ULONG length)
|
---|
[10679] | 185 | {
|
---|
| 186 | mPeriod = period;
|
---|
| 187 | mLength = length;
|
---|
| 188 | mMHz->init(mLength);
|
---|
| 189 | }
|
---|
| 190 |
|
---|
[10641] | 191 | void HostCpuMhz::collect()
|
---|
| 192 | {
|
---|
[11180] | 193 | ULONG mhz;
|
---|
[10713] | 194 | int rc = mHAL->getHostCpuMHz(&mhz);
|
---|
| 195 | if (RT_SUCCESS(rc))
|
---|
| 196 | mMHz->put(mhz);
|
---|
[10641] | 197 | }
|
---|
| 198 |
|
---|
[11180] | 199 | void HostRamUsage::init(ULONG period, ULONG length)
|
---|
[10679] | 200 | {
|
---|
| 201 | mPeriod = period;
|
---|
| 202 | mLength = length;
|
---|
| 203 | mTotal->init(mLength);
|
---|
| 204 | mUsed->init(mLength);
|
---|
| 205 | mAvailable->init(mLength);
|
---|
| 206 | }
|
---|
| 207 |
|
---|
[12400] | 208 | void HostRamUsage::preCollect(CollectorHints& hints)
|
---|
| 209 | {
|
---|
| 210 | hints.collectHostRamUsage();
|
---|
| 211 | }
|
---|
| 212 |
|
---|
[10641] | 213 | void HostRamUsage::collect()
|
---|
| 214 | {
|
---|
[11180] | 215 | ULONG total, used, available;
|
---|
[10713] | 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 | }
|
---|
[10641] | 223 | }
|
---|
| 224 |
|
---|
| 225 |
|
---|
[10679] | 226 |
|
---|
[11180] | 227 | void MachineCpuLoad::init(ULONG period, ULONG length)
|
---|
[10679] | 228 | {
|
---|
| 229 | mPeriod = period;
|
---|
| 230 | mLength = length;
|
---|
| 231 | mUser->init(mLength);
|
---|
| 232 | mKernel->init(mLength);
|
---|
| 233 | }
|
---|
| 234 |
|
---|
[10641] | 235 | void MachineCpuLoad::collect()
|
---|
| 236 | {
|
---|
[11180] | 237 | ULONG user, kernel;
|
---|
[10713] | 238 | int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
|
---|
| 239 | if (RT_SUCCESS(rc))
|
---|
| 240 | {
|
---|
| 241 | mUser->put(user);
|
---|
| 242 | mKernel->put(kernel);
|
---|
| 243 | }
|
---|
[10641] | 244 | }
|
---|
| 245 |
|
---|
[12400] | 246 | void MachineCpuLoadRaw::preCollect(CollectorHints& hints)
|
---|
| 247 | {
|
---|
| 248 | hints.collectProcessCpuLoad(mProcess);
|
---|
| 249 | }
|
---|
| 250 |
|
---|
[10641] | 251 | void MachineCpuLoadRaw::collect()
|
---|
| 252 | {
|
---|
[10868] | 253 | uint64_t processUser, processKernel, hostTotal;
|
---|
[10641] | 254 |
|
---|
[10868] | 255 | int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
|
---|
[10713] | 256 | if (RT_SUCCESS(rc))
|
---|
| 257 | {
|
---|
[10868] | 258 | if (hostTotal == mHostTotalPrev)
|
---|
[10713] | 259 | {
|
---|
[10868] | 260 | /* Nearly impossible, but... */
|
---|
| 261 | mUser->put(0);
|
---|
| 262 | mKernel->put(0);
|
---|
[10713] | 263 | }
|
---|
[10868] | 264 | else
|
---|
| 265 | {
|
---|
[11180] | 266 | mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
|
---|
| 267 | mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
|
---|
[10868] | 268 | }
|
---|
[11591] | 269 |
|
---|
[10868] | 270 | mHostTotalPrev = hostTotal;
|
---|
| 271 | mProcessUserPrev = processUser;
|
---|
| 272 | mProcessKernelPrev = processKernel;
|
---|
[10713] | 273 | }
|
---|
[10641] | 274 | }
|
---|
| 275 |
|
---|
[11180] | 276 | void MachineRamUsage::init(ULONG period, ULONG length)
|
---|
[10679] | 277 | {
|
---|
| 278 | mPeriod = period;
|
---|
| 279 | mLength = length;
|
---|
| 280 | mUsed->init(mLength);
|
---|
| 281 | }
|
---|
| 282 |
|
---|
[12400] | 283 | void MachineRamUsage::preCollect(CollectorHints& hints)
|
---|
| 284 | {
|
---|
| 285 | hints.collectProcessRamUsage(mProcess);
|
---|
| 286 | }
|
---|
| 287 |
|
---|
[10641] | 288 | void MachineRamUsage::collect()
|
---|
| 289 | {
|
---|
[11180] | 290 | ULONG used;
|
---|
[10713] | 291 | int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
|
---|
| 292 | if (RT_SUCCESS(rc))
|
---|
| 293 | mUsed->put(used);
|
---|
[10641] | 294 | }
|
---|
| 295 |
|
---|
[11180] | 296 | void CircularBuffer::init(ULONG length)
|
---|
[10641] | 297 | {
|
---|
| 298 | if (mData)
|
---|
| 299 | RTMemFree(mData);
|
---|
| 300 | mLength = length;
|
---|
[11481] | 301 | if (mLength)
|
---|
| 302 | mData = (ULONG *)RTMemAllocZ(length * sizeof(ULONG));
|
---|
| 303 | else
|
---|
| 304 | mData = NULL;
|
---|
[10713] | 305 | mWrapped = false;
|
---|
| 306 | mEnd = 0;
|
---|
[12973] | 307 | mSequenceNumber = 0;
|
---|
[10641] | 308 | }
|
---|
| 309 |
|
---|
[11180] | 310 | ULONG CircularBuffer::length()
|
---|
[10641] | 311 | {
|
---|
[10713] | 312 | return mWrapped ? mLength : mEnd;
|
---|
[10641] | 313 | }
|
---|
| 314 |
|
---|
[11180] | 315 | void CircularBuffer::put(ULONG value)
|
---|
[10641] | 316 | {
|
---|
[10713] | 317 | if (mData)
|
---|
| 318 | {
|
---|
| 319 | mData[mEnd++] = value;
|
---|
| 320 | if (mEnd >= mLength)
|
---|
| 321 | {
|
---|
| 322 | mEnd = 0;
|
---|
| 323 | mWrapped = true;
|
---|
| 324 | }
|
---|
[12973] | 325 | ++mSequenceNumber;
|
---|
[10713] | 326 | }
|
---|
[10641] | 327 | }
|
---|
| 328 |
|
---|
[11180] | 329 | void CircularBuffer::copyTo(ULONG *data)
|
---|
[10641] | 330 | {
|
---|
[10713] | 331 | if (mWrapped)
|
---|
| 332 | {
|
---|
[11180] | 333 | memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
|
---|
[10713] | 334 | // Copy the wrapped part
|
---|
| 335 | if (mEnd)
|
---|
[11180] | 336 | memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
|
---|
[10713] | 337 | }
|
---|
| 338 | else
|
---|
[11180] | 339 | memcpy(data, mData, mEnd * sizeof(ULONG));
|
---|
[10641] | 340 | }
|
---|
| 341 |
|
---|
[11180] | 342 | void SubMetric::query(ULONG *data)
|
---|
[10641] | 343 | {
|
---|
[10713] | 344 | copyTo(data);
|
---|
[10641] | 345 | }
|
---|
[11591] | 346 |
|
---|
[12973] | 347 | void Metric::query(ULONG **data, ULONG *count, ULONG *sequenceNumber)
|
---|
[10641] | 348 | {
|
---|
[11180] | 349 | ULONG length;
|
---|
| 350 | ULONG *tmpData;
|
---|
[10641] | 351 |
|
---|
| 352 | length = mSubMetric->length();
|
---|
[12973] | 353 | *sequenceNumber = mSubMetric->getSequenceNumber() - length;
|
---|
[10641] | 354 | if (length)
|
---|
| 355 | {
|
---|
[11180] | 356 | tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
|
---|
[10713] | 357 | mSubMetric->query(tmpData);
|
---|
[10641] | 358 | if (mAggregate)
|
---|
| 359 | {
|
---|
| 360 | *count = 1;
|
---|
[11180] | 361 | *data = (ULONG*)RTMemAlloc(sizeof(**data));
|
---|
[10641] | 362 | **data = mAggregate->compute(tmpData, length);
|
---|
[10713] | 363 | RTMemFree(tmpData);
|
---|
[10641] | 364 | }
|
---|
| 365 | else
|
---|
| 366 | {
|
---|
| 367 | *count = length;
|
---|
| 368 | *data = tmpData;
|
---|
| 369 | }
|
---|
| 370 | }
|
---|
| 371 | else
|
---|
| 372 | {
|
---|
| 373 | *count = 0;
|
---|
| 374 | *data = 0;
|
---|
| 375 | }
|
---|
| 376 | }
|
---|
| 377 |
|
---|
[11180] | 378 | ULONG AggregateAvg::compute(ULONG *data, ULONG length)
|
---|
[10641] | 379 | {
|
---|
[10713] | 380 | uint64_t tmp = 0;
|
---|
[11180] | 381 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 382 | tmp += data[i];
|
---|
[11180] | 383 | return (ULONG)(tmp / length);
|
---|
[10641] | 384 | }
|
---|
| 385 |
|
---|
| 386 | const char * AggregateAvg::getName()
|
---|
| 387 | {
|
---|
| 388 | return "avg";
|
---|
| 389 | }
|
---|
| 390 |
|
---|
[11180] | 391 | ULONG AggregateMin::compute(ULONG *data, ULONG length)
|
---|
[10641] | 392 | {
|
---|
[11180] | 393 | ULONG tmp = *data;
|
---|
| 394 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 395 | if (data[i] < tmp)
|
---|
| 396 | tmp = data[i];
|
---|
| 397 | return tmp;
|
---|
[10641] | 398 | }
|
---|
| 399 |
|
---|
| 400 | const char * AggregateMin::getName()
|
---|
| 401 | {
|
---|
| 402 | return "min";
|
---|
| 403 | }
|
---|
| 404 |
|
---|
[11180] | 405 | ULONG AggregateMax::compute(ULONG *data, ULONG length)
|
---|
[10641] | 406 | {
|
---|
[11180] | 407 | ULONG tmp = *data;
|
---|
| 408 | for (ULONG i = 0; i < length; ++i)
|
---|
[10713] | 409 | if (data[i] > tmp)
|
---|
| 410 | tmp = data[i];
|
---|
| 411 | return tmp;
|
---|
[10641] | 412 | }
|
---|
| 413 |
|
---|
| 414 | const char * AggregateMax::getName()
|
---|
| 415 | {
|
---|
| 416 | return "max";
|
---|
| 417 | }
|
---|
| 418 |
|
---|
[10713] | 419 | Filter::Filter(ComSafeArrayIn(INPTR BSTR, metricNames),
|
---|
[10679] | 420 | ComSafeArrayIn(IUnknown *, objects))
|
---|
| 421 | {
|
---|
[12942] | 422 | /*
|
---|
| 423 | * Let's work around null/empty safe array mess. I am not sure there is
|
---|
| 424 | * a way to pass null arrays via webservice, I haven't found one. So I
|
---|
| 425 | * guess the users will be forced to use empty arrays instead. Constructing
|
---|
| 426 | * an empty SafeArray is a bit awkward, so what we do in this method is
|
---|
| 427 | * actually convert null arrays to empty arrays and pass them down to
|
---|
| 428 | * init() method. If someone knows how to do it better, please be my guest,
|
---|
| 429 | * fix it.
|
---|
| 430 | */
|
---|
| 431 | if (ComSafeArrayInIsNull(metricNames))
|
---|
| 432 | {
|
---|
| 433 | com::SafeArray <BSTR> nameArray;
|
---|
| 434 | if (ComSafeArrayInIsNull(objects))
|
---|
| 435 | {
|
---|
| 436 | com::SafeIfaceArray <IUnknown> objectArray;
|
---|
| 437 | objectArray.reset(0);
|
---|
| 438 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 439 | ComSafeArrayAsInParam(objectArray));
|
---|
| 440 | }
|
---|
| 441 | else
|
---|
| 442 | {
|
---|
| 443 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
| 444 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 445 | ComSafeArrayAsInParam(objectArray));
|
---|
| 446 | }
|
---|
| 447 | }
|
---|
| 448 | else
|
---|
| 449 | {
|
---|
| 450 | com::SafeArray <INPTR BSTR> nameArray(ComSafeArrayInArg(metricNames));
|
---|
| 451 | if (ComSafeArrayInIsNull(objects))
|
---|
| 452 | {
|
---|
| 453 | com::SafeIfaceArray <IUnknown> objectArray;
|
---|
| 454 | objectArray.reset(0);
|
---|
| 455 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 456 | ComSafeArrayAsInParam(objectArray));
|
---|
| 457 | }
|
---|
| 458 | else
|
---|
| 459 | {
|
---|
| 460 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
| 461 | init(ComSafeArrayAsInParam(nameArray),
|
---|
| 462 | ComSafeArrayAsInParam(objectArray));
|
---|
| 463 | }
|
---|
| 464 | }
|
---|
| 465 | }
|
---|
| 466 |
|
---|
| 467 | void Filter::init(ComSafeArrayIn(INPTR BSTR, metricNames),
|
---|
| 468 | ComSafeArrayIn(IUnknown *, objects))
|
---|
| 469 | {
|
---|
[10713] | 470 | com::SafeArray <INPTR BSTR> nameArray(ComSafeArrayInArg(metricNames));
|
---|
[12942] | 471 | com::SafeIfaceArray <IUnknown> objectArray(ComSafeArrayInArg(objects));
|
---|
[11383] | 472 |
|
---|
[12942] | 473 | if (!objectArray.size())
|
---|
[10725] | 474 | {
|
---|
| 475 | if (nameArray.size())
|
---|
| 476 | {
|
---|
| 477 | for (size_t i = 0; i < nameArray.size(); ++i)
|
---|
| 478 | processMetricList(std::string(com::Utf8Str(nameArray[i])), ComPtr<IUnknown>());
|
---|
| 479 | }
|
---|
| 480 | else
|
---|
| 481 | processMetricList(std::string("*"), ComPtr<IUnknown>());
|
---|
| 482 | }
|
---|
| 483 | else
|
---|
| 484 | {
|
---|
[12942] | 485 |
|
---|
[10725] | 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 | }
|
---|