Установка Общего экземпляра для Счетчиков производительности

Это решение было вдохновлено решением Marcelo с некоторыми изменениями:

#include <iostream>
#include <iterator>
#include <type_traits>
#include <vector>
#include <algorithm>

// This works similar to ostream_iterator, but doesn't print a delimiter after the final item
template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar> >
class pretty_ostream_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
    typedef TChar char_type;
    typedef TCharTraits traits_type;
    typedef std::basic_ostream<TChar, TCharTraits> ostream_type;

    pretty_ostream_iterator(ostream_type &stream, const char_type *delim = NULL)
        : _stream(&stream), _delim(delim), _insertDelim(false)
    {
    }

    pretty_ostream_iterator<T, TChar, TCharTraits>& operator=(const T &value)
    {
        if( _delim != NULL )
        {
            // Don't insert a delimiter if this is the first time the function is called
            if( _insertDelim )
                (*_stream) << _delim;
            else
                _insertDelim = true;
        }
        (*_stream) << value;
        return *this;
    }

    pretty_ostream_iterator<T, TChar, TCharTraits>& operator*()
    {
        return *this;
    }

    pretty_ostream_iterator<T, TChar, TCharTraits>& operator++()
    {
        return *this;
    }

    pretty_ostream_iterator<T, TChar, TCharTraits>& operator++(int)
    {
        return *this;
    }
private:
    ostream_type *_stream;
    const char_type *_delim;
    bool _insertDelim;
};

#if _MSC_VER >= 1400

// Declare pretty_ostream_iterator as checked
template<typename T, typename TChar, typename TCharTraits>
struct std::_Is_checked_helper<pretty_ostream_iterator<T, TChar, TCharTraits> > : public std::tr1::true_type
{
};

#endif // _MSC_VER >= 1400

namespace std
{
    // Pre-declarations of container types so we don't actually have to include the relevant headers if not needed, speeding up compilation time.
    // These aren't necessary if you do actually include the headers.
    template<typename T, typename TAllocator> class vector;
    template<typename T, typename TAllocator> class list;
    template<typename T, typename TTraits, typename TAllocator> class set;
    template<typename TKey, typename TValue, typename TTraits, typename TAllocator> class map;
}

// Basic is_container template; specialize to derive from std::true_type for all desired container types
template<typename T> struct is_container : public std::false_type { };

// Mark vector as a container
template<typename T, typename TAllocator> struct is_container<std::vector<T, TAllocator> > : public std::true_type { };

// Mark list as a container
template<typename T, typename TAllocator> struct is_container<std::list<T, TAllocator> > : public std::true_type { };

// Mark set as a container
template<typename T, typename TTraits, typename TAllocator> struct is_container<std::set<T, TTraits, TAllocator> > : public std::true_type { };

// Mark map as a container
template<typename TKey, typename TValue, typename TTraits, typename TAllocator> struct is_container<std::map<TKey, TValue, TTraits, TAllocator> > : public std::true_type { };

// Holds the delimiter values for a specific character type
template<typename TChar>
struct delimiters_values
{
    typedef TChar char_type;
    const TChar *prefix;
    const TChar *delimiter;
    const TChar *postfix;
};

// Defines the delimiter values for a specific container and character type
template<typename T, typename TChar>
struct delimiters
{
    static const delimiters_values<TChar> values; 
};

// Default delimiters
template<typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template<typename T> const delimiters_values<char> delimiters<T, char>::values = { "{ ", ", ", " }" };
template<typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"{ ", L", ", L" }" };

// Delimiters for set
template<typename T, typename TTraits, typename TAllocator> struct delimiters<std::set<T, TTraits, TAllocator>, char> { static const delimiters_values<char> values; };
template<typename T, typename TTraits, typename TAllocator> const delimiters_values<char> delimiters<std::set<T, TTraits, TAllocator>, char>::values = { "[ ", ", ", " ]" };
template<typename T, typename TTraits, typename TAllocator> struct delimiters<std::set<T, TTraits, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T, typename TTraits, typename TAllocator> const delimiters_values<wchar_t> delimiters<std::set<T, TTraits, TAllocator>, wchar_t>::values = { L"[ ", L", ", L" ]" };

// Delimiters for pair
template<typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template<typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template<typename T1, typename T2> struct delimiters<std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T1, typename T2> const delimiters_values<wchar_t> delimiters<std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };

// Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type.
template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar>, typename TDelimiters = delimiters<T, TChar> >
struct print_container_helper
{
    typedef TChar char_type;
    typedef TDelimiters delimiters_type;
    typedef std::basic_ostream<TChar, TCharTraits>& ostream_type;

    print_container_helper(const T &container)
        : _container(&container)
    {
    }

    void operator()(ostream_type &stream) const
    {
        if( delimiters_type::values.prefix != NULL )
            stream << delimiters_type::values.prefix;
        std::copy(_container->begin(), _container->end(), pretty_ostream_iterator<typename T::value_type, TChar, TCharTraits>(stream, delimiters_type::values.delimiter));
        if( delimiters_type::values.postfix != NULL )
            stream << delimiters_type::values.postfix;
    }
private:
    const T *_container;
};

// Prints a print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
std::basic_ostream<TChar, TCharTraits>& operator<<(std::basic_ostream<TChar, TCharTraits> &stream, const print_container_helper<T, TChar, TDelimiters> &helper)
{
    helper(stream);
    return stream;
}

// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
typename std::enable_if<is_container<T>::value, std::basic_ostream<TChar, TCharTraits>&>::type
    operator<<(std::basic_ostream<TChar, TCharTraits> &stream, const T &container)
{
    stream << print_container_helper<T, TChar, TCharTraits>(container);
    return stream;
}

// Prints a pair to the stream using delimiters from delimiters<std::pair<T1, T2>>.
template<typename T1, typename T2, typename TChar, typename TCharTraits>
std::basic_ostream<TChar, TCharTraits>& operator<<(std::basic_ostream<TChar, TCharTraits> &stream, const std::pair<T1, T2> &value)
{
    if( delimiters<std::pair<T1, T2>, TChar>::values.prefix != NULL )
        stream << delimiters<std::pair<T1, T2>, TChar>::values.prefix;

    stream << value.first;

    if( delimiters<std::pair<T1, T2>, TChar>::values.delimiter != NULL )
        stream << delimiters<std::pair<T1, T2>, TChar>::values.delimiter;

    stream << value.second;

    if( delimiters<std::pair<T1, T2>, TChar>::values.postfix != NULL )
        stream << delimiters<std::pair<T1, T2>, TChar>::values.postfix;
    return stream;    
}

// Used by the sample below to generate some values
struct fibonacci
{
    fibonacci() : f1(0), f2(1) { }
    int operator()()
    {
        int r = f1 + f2;
        f1 = f2;
        f2 = r;
        return f1;
    }
private:
    int f1;
    int f2;
};

int main()
{
    std::vector<int> v;
    std::generate_n(std::back_inserter(v), 10, fibonacci());

    std::cout << v << std::endl;

    // Example of using pretty_ostream_iterator directly
    std::generate_n(pretty_ostream_iterator<int>(std::cout, ";"), 20, fibonacci());
    std::cout << std::endl;
}

Как и версия Marcelo, она использует черту типа is_container, которая должна быть специализированной для всех поддерживаемых контейнеров. Может быть возможно использовать черту для проверки value_type, const_iterator, begin() / end(), но я не уверен, что рекомендую, поскольку она может соответствовать вещам, которые соответствуют этим критериям, но не ' т на самом деле контейнеры, как std::basic_string. Также, как и в версии Marcelo, в ней используются шаблоны, которые могут быть специализированы для указания используемых разделителей.

Основное отличие заключается в том, что я построил свою версию на pretty_ostream_iterator, которая работает аналогично std::ostream_iterator, но не печатает разделитель после последнего элемента. Форматирование контейнеров выполняется с помощью print_container_helper, который может использоваться непосредственно для печати контейнеров без черты is_container или для указания другого типа разделителей.

Я также определил is_container и разделители, чтобы он работал для контейнеров с нестандартными предикатами или распределителями, а также для char и wchar_t. Оператор < < Сама функция также определена для работы с потоками char и wchar_t.

Наконец, я использовал std::enable_if, который доступен как часть C ++ 0x и работает в Visual C ++ 2010 и g ++ 4.3 (требуется флаг -std = c ++ 0x) и позже. Таким образом, нет никакой зависимости от Boost.

6
задан Alan McBee - MSFT 27 June 2009 в 01:21
поделиться

4 ответа

Некоторый код должен активно поддерживать счетчик. Во всех примерах, которые вы можете себе представить, например в ASP.Net, существует служба, поддерживающая счетчик.

Поскольку вас не устраивает, что экземпляр _Total активен только во время работы какого-то экземпляра вашего приложения, , вам нужно написать код, который будет поддерживать счетчик производительности вне вашего приложения. В этом нет никакого волшебства.

Вы можете написать небольшую службу, которая будет вам нужна для мониторинга. Это будет поддерживать счетчик _Total. Вам необходимо определиться с режимом обновления. Самый простой - сделать так, чтобы каждый экземпляр вашего приложения обновлял оба экземпляра (свой собственный и _Total).

Немного предыстории о счетчиках производительности - главное понять, что обычно существует общая область памяти, совместно используемая между процессами, которая обновляется посредством взаимосвязанных операций. Такой инструмент, как PerfMon (или любое другое приложение), в конечном итоге подключается к общей области памяти, чтобы получить текущие значения. Таким образом, у какого-то процесса должна быть открыта эта разделяемая область памяти и ей принадлежит. Итак, зачем вам нужен запущенный код. PerfMon не создает для вас экземпляр _Total (у него есть несколько довольно запутанных комбинаций счетчиков, позволяющих использовать средние значения и скорости, но не сумму для создания экземпляра сводки).

7
ответ дан 16 December 2019 в 21:45
поделиться

Попробуйте создать категорию с "PerformanceCounterCategoryType.SingleInstance".

0
ответ дан 16 December 2019 в 21:45
поделиться

Просто предложение, но попробуйте сделать

Counter.ReadOnly = true;

первым проходом и установить его только на False, когда вам нужно увеличить счетчик.

А также, если вы сделаете счетчик Readonly, вам явно нужно закомментировать строку:

Counter.RawData = 0;

Я считаю, что он установлен в 0 по умолчанию в любом случае при первом проходе.

Надеюсь, это поможет ...

0
ответ дан 16 December 2019 в 21:45
поделиться

AFAIK категория глобального счетчика производительности будет оставаться активной до тех пор, пока любой процесс имеет активный дескриптор, ссылающийся на нее. Системные счетчики достигают этого, сохраняя дескриптор экземпляра общего счетчика в некоторой службе.

1
ответ дан 16 December 2019 в 21:45
поделиться