Пример #1
0
Status PerfCounterCollector::collect(BSONObjBuilder* builder) {
    // Ask PDH to collect the counters
    PDH_STATUS status = PdhCollectQueryData(_query);
    if (status != ERROR_SUCCESS) {
        return {ErrorCodes::WindowsPdhError,
                formatFunctionCallError("PdhCollectQueryData", status)};
    }

    // Output timebase
    // Counters that are based on time either use 100NS or System Ticks Per Second.
    // We only need to output system ticks per second once if any counter depends on it.
    // This is typically 3320310.
    if (_timeBaseTicksCounter) {
        int64_t timebase;

        status = PdhGetCounterTimeBase(_timeBaseTicksCounter->handle, &timebase);
        if (status != ERROR_SUCCESS) {
            return {ErrorCodes::WindowsPdhError,
                    formatFunctionCallError("PdhGetCounterTimeBase", status)};
        }

        builder->append("timebase", timebase);
    }

    // Retrieve all the values that PDH collected for us.
    for (const auto& counterGroup : _counters) {
        BSONObjBuilder subObjBuilder(builder->subobjStart(counterGroup.name));

        Status s = collectCounters(counterGroup.counters, &subObjBuilder);
        if (!s.isOK()) {
            return s;
        }

        subObjBuilder.doneFast();
    }

    for (const auto& counterGroup : _nestedCounters) {
        BSONObjBuilder subObjBuilder(builder->subobjStart(counterGroup.name));

        for (const auto& instanceNamePair : counterGroup.counters) {
            BSONObjBuilder instSubObjBuilder(builder->subobjStart(instanceNamePair.first));

            Status s = collectCounters(instanceNamePair.second, &instSubObjBuilder);
            if (!s.isOK()) {
                return s;
            }

            instSubObjBuilder.doneFast();
        }

        subObjBuilder.doneFast();
    }

    return Status::OK();
}
Пример #2
0
StatusWith<std::vector<PerfCounterCollector::CounterInfo>> PerfCounterCollector::addCounters(
    StringData path) {
    std::wstring pathWide = toNativeString(path.toString().c_str());
    DWORD pathListLength = 0;
    PDH_STATUS status = PdhExpandCounterPathW(pathWide.c_str(), nullptr, &pathListLength);

    if (status != PDH_MORE_DATA) {
        return {ErrorCodes::WindowsPdhError,
                str::stream() << formatFunctionCallError("PdhExpandCounterPathW", status)
                              << " for counter '"
                              << path
                              << "'"};
    }

    auto buf = stdx::make_unique<wchar_t[]>(pathListLength);

    status = PdhExpandCounterPathW(pathWide.c_str(), buf.get(), &pathListLength);

    if (status != ERROR_SUCCESS) {
        return {ErrorCodes::WindowsPdhError,
                formatFunctionCallError("PdhExpandCounterPathW", status)};
    }

    std::vector<CounterInfo> counters;

    // Windows' PdhExpandWildCardPathW returns a nullptr terminated array of nullptr separated
    // strings.
    std::vector<std::string> counterNames;

    const wchar_t* ptr = buf.get();
    while (ptr && *ptr) {
        counterNames.emplace_back(toUtf8String(ptr));
        ptr += wcslen(ptr) + 1;
    }

    // Sort to ensure we have a predictable ordering in the final BSON
    std::sort(counterNames.begin(), counterNames.end());

    for (const auto& name : counterNames) {

        auto swCounterInfo = addCounter(name);
        if (!swCounterInfo.isOK()) {
            return swCounterInfo.getStatus();
        }

        counters.emplace_back(std::move(swCounterInfo.getValue()));
    }

    return {std::move(counters)};
}
Пример #3
0
Status PerfCounterCollector::collectCounters(const std::vector<CounterInfo>& counters,
                                             BSONObjBuilder* builder) {
    for (const auto& counterInfo : counters) {

        DWORD dwType = 0;
        PDH_RAW_COUNTER rawCounter = {0};

        PDH_STATUS status = PdhGetRawCounterValue(counterInfo.handle, &dwType, &rawCounter);
        if (status != ERROR_SUCCESS) {
            return {ErrorCodes::WindowsPdhError,
                    formatFunctionCallError("PdhGetRawCounterValue", status)};
        }

        if (counterInfo.hasSecondValue) {
            // Delta, Rate, and Elapsed Time counters require the second value in the raw counter
            // information
            builder->append(counterInfo.firstName, rawCounter.FirstValue);
            builder->append(counterInfo.secondName, rawCounter.SecondValue);
        } else {
            builder->append(counterInfo.firstName, rawCounter.FirstValue);
        }
    }

    return Status::OK();
}
Пример #4
0
Status PerfCounterCollector::open() {

    PDH_STATUS status = PdhOpenQueryW(nullptr, NULL, &_query);
    if (status != ERROR_SUCCESS) {
        return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhOpenQueryW", status)};
    }

    return Status::OK();
}
Пример #5
0
Status PerfCounterCollector::collectCounters(const std::vector<CounterInfo>& counters,
                                             BSONObjBuilder* builder) {
    for (const auto& counterInfo : counters) {

        DWORD dwType = 0;

        // Elapsed Time is an unusual counter in that being able to control the sample period for
        // the counter is uninteresting even though it is computed from two values. Just return the
        // computed value instead.
        if (counterInfo.type == PERF_ELAPSED_TIME) {
            PDH_FMT_COUNTERVALUE counterValue = {0};
            PDH_STATUS status = PdhGetFormattedCounterValue(
                counterInfo.handle, PDH_FMT_DOUBLE, &dwType, &counterValue);
            if (status != ERROR_SUCCESS) {
                return {ErrorCodes::WindowsPdhError,
                        formatFunctionCallError("PdhGetFormattedCounterValue", status)};
            }

            builder->append(counterInfo.firstName, counterValue.doubleValue);

        } else {

            PDH_RAW_COUNTER rawCounter = {0};
            PDH_STATUS status = PdhGetRawCounterValue(counterInfo.handle, &dwType, &rawCounter);
            if (status != ERROR_SUCCESS) {
                return {ErrorCodes::WindowsPdhError,
                        formatFunctionCallError("PdhGetRawCounterValue", status)};
            }

            if (counterInfo.hasSecondValue) {
                // Precise counters require the second value in the raw counter information
                builder->append(counterInfo.firstName, rawCounter.FirstValue);
                builder->append(counterInfo.secondName, rawCounter.SecondValue);
            } else {
                builder->append(counterInfo.firstName, rawCounter.FirstValue);
            }
        }
    }

    return Status::OK();
}
Пример #6
0
StatusWith<PerfCounterCollector::CounterInfo> PerfCounterCollector::addCounter(StringData path) {

    PDH_HCOUNTER counter{0};

    PDH_STATUS status =
        PdhAddCounterW(_query, toNativeString(path.toString().c_str()).c_str(), NULL, &counter);

    if (status != ERROR_SUCCESS) {
        return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhAddCounterW", status)};
    }

    DWORD bufferSize = 0;

    status = PdhGetCounterInfoW(counter, false, &bufferSize, nullptr);

    if (status != PDH_MORE_DATA) {
        return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhGetCounterInfoW", status)};
    }

    auto buf = stdx::make_unique<char[]>(bufferSize);
    auto counterInfo = reinterpret_cast<PPDH_COUNTER_INFO>(buf.get());

    status = PdhGetCounterInfoW(counter, false, &bufferSize, counterInfo);

    if (status != ERROR_SUCCESS) {
        return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhGetCounterInfoW", status)};
    }

    // A full qualified path is as such:
    // "\\MYMACHINE\\Processor(0)\\% Idle Time"
    // MachineName \\ Object Name (Instance Name) \\ CounterName
    // Ex:
    //  MachineName: MYMACHINE
    //  Object Name: Processor
    //  InstanceName: 0
    //  CounterName: % Idle Time
    // We do not want to use Machine Name, but sometimes we want InstanceName
    //
    std::string firstName = str::stream() << '\\' << toUtf8String(counterInfo->szObjectName) << '\\'
                                          << toUtf8String(counterInfo->szCounterName);

    // Compute a second name
    std::string secondName(firstName);

    bool hasSecondValue = false;

    // Only include base for counters that need it
    if ((counterInfo->dwType & PERF_COUNTER_PRECISION) == PERF_COUNTER_PRECISION) {
        secondName += " Base";
        hasSecondValue = true;
    }

    // InstanceName is null for counters without instance names
    return {CounterInfo{std::move(firstName),
                        std::move(secondName),
                        hasSecondValue,
                        counterInfo->szInstanceName ? toUtf8String(counterInfo->szInstanceName)
                                                    : std::string(),
                        counterInfo->dwType,
                        counter}};
}