Подтвердить что ты не робот

Linux С++: как профилировать время, потраченное впустую из-за промахов в кеше?

Я знаю, что я могу использовать gprof для сравнения моего кода.

Однако у меня есть эта проблема - у меня есть умный указатель, который имеет дополнительный уровень косвенности (думайте об этом как прокси-объект).

В результате у меня есть этот дополнительный слой, который выполняет практически все функции, а также винты с кешированием.

Есть ли способ измерить время, затрачиваемое моим процессором из-за промахов в кеше?

Спасибо!

4b9b3361

Ответ 1

Вы можете попробовать cachegrind, а он - интерфейс kcachegrind.

Ответ 2

Вы можете найти инструмент, который обращается к счетчикам производительности процессора. Вероятно, в каждом ядре есть регистр, который учитывает пропуски L1, L2 и т.д. В качестве альтернативы Cachegrind выполняет циклическое моделирование.

Однако я не думаю, что это было бы проницательно. Ваши объекты-посредники, по-видимому, модифицируются собственными методами. Обычный профилировщик расскажет вам, сколько времени эти методы принимают. Ни один инструмент профиля не расскажет вам, как производительность будет улучшаться без этого источника загрязнения кэша. Это вопрос уменьшения размера и структуры рабочего набора программ, что нелегко экстраполировать.

Быстрый поиск в Google boost::intrusive_ptr, который может вас заинтересовать. Он, похоже, не поддерживает что-то вроде weak_ptr, но преобразование вашей программы может быть тривиальным, и тогда вы точно знаете стоимость неинтрузивных ссылок ref.

Ответ 3

Linux поддерживает perf от версии 2.6.31. Это позволяет сделать следующее:

  • скомпилируйте свой код с -g, чтобы включить отладочную информацию.
  • запустите свой код, например. используя счетчики промахов последнего уровня: perf record -e LLC-loads,LLC-load-misses yourExecutable
  • выполнить perf report
    • после подтверждения исходного сообщения выберите строку LLC-load-misses,
    • то, например, первая функция и
    • затем annotate. Вы должны увидеть строки (в коде сборки, в окружении исходного исходного кода) и номер, указывающий, какая часть промахов последнего уровня промахивается для строк, в которых произошли промахи в кеше.

Ответ 4

Это зависит от того, какую ОС и ЦП вы используете. Например. для Mac OS X и x86 или ppc, Shark будет выполнять профилирование пропущенных кешей. То же самое для Увеличить в Linux.

Ответ 5

Если вы используете процессор AMD, вы можете получить CodeAnalyst, очевидно свободный, как в пиве.

Ответ 6

Продолжая строки @Mike_Dunlavey, ответьте:

Сначала получите профиль, основанный на времени, используя ваш любимый инструмент: VTune или PTU или OProf.

Затем получите профиль промаха в кеше. Промахи кеша L1 или пропуски кэша L2 или...

т.е. первый профиль связывает "время, проведенное" с каждым счетчиком программы. Второй ассоциирует значение "количество промахов в кеше" с каждым счетчиком программы.

Примечание. Я часто "уменьшаю" данные, суммируя их по функциям или (если у меня есть технология) по циклу. Или в бункерах, скажем, 64 байта. Сравнение отдельных счетчиков программ часто бывает нецелесообразным, поскольку счетчики производительности нечеткие - место, где вы видите сообщение о пропущенном кэше, часто содержит несколько инструкций, отличных от того, где это произошло.

ОК, поэтому теперь сопоставьте эти два профиля, чтобы сравнить их. Вот некоторые графики, которые я считаю полезными:

Диаграммы "Айсберг": ось X - ПК, положительная ось Y - время, отрицательный Y - промахи в кеше. Ищите места, которые идут вверх и вниз.

( "чередующиеся" диаграммы также полезны: одна и та же идея, ось X - это ПК, график времени и оси пропускания оси Y, но с узкими вертикальными линиями разных цветов, обычно красными и синими. Места, где много время и кеш-промахи будут иметь мелко чередующиеся красные и синие линии, почти выглядящие фиолетовыми. Это распространяется на пропуски кеша L2 и L3, все на одном графике. Кстати, вы, вероятно, хотите "нормализовать" числа, либо на% возраст общего времени или промахов в кеше, или, что еще лучше,% возраста максимальной точки данных времени или промахов в кеше. Если вы ошиблись в масштабе, вы ничего не увидите.)

графики XY: для каждого буфера выборки (ПК, или функция, или цикл или...) выведите точку, чья координата X является нормированным временем, а координата Y которой нормализованный кэш пропускает. Если вы получаете много точек данных в правом верхнем углу - большое процентное время и большие проценты кэш-времени в процентах - это интересное доказательство. Или, забудьте количество очков - если сумма всех процентов в верхнем углу большая...

Обратите внимание, к сожалению, что вам часто приходится выполнять эти анализы самостоятельно. Последнее, что я проверил, VTune не делает этого для вас. Я использовал gnuplot и Excel. (Предупреждение: Excel умирает выше 64 тысяч точек данных.)


Дополнительные советы:

Если ваш умный указатель встроен, вы можете получить подсчеты по всему месту. В идеальном мире вы сможете отследить ПК до исходной строки исходного кода. В этом случае вам может потребоваться отложить сокращение немного: посмотрите на все персональные компьютеры; верните их обратно в строки исходного кода; а затем сопоставить их с исходной функцией. Многие компиляторы, например. GCC, есть опции таблицы символов, которые позволяют вам это делать.

Кстати, я подозреваю, что ваша проблема НЕ с умным указателем, вызывающим переполнение кэша. Если вы не делаете smart_ptr <int> повсюду. Если вы делаете smart_ptr <Obj> и sizeof (Obj) + больше, чем скажем, 4 * sizeof (Obj *) (и если сам smart_ptr не огромен), то это не так много.

Скорее всего, это дополнительный уровень косвенности, который вызывает интеллектуальный указатель, который вызывает проблему yor.

Кстати, я разговаривал с парнем за обедом, у которого была ссылка, подсчитанная умным указателем, который использовал дескриптор, т.е. уровень косвенности, что-то вроде

template<typename T> class refcntptr {
    refcnt_handle<T> handle;
public:
    refcntptr(T*obj) {
        this->handle = new refcnt_handle<T>();
        this->handle->ptr = obj;
        this->handle->count = 1;
    }
};
template<typename T> class refcnt_handle {
    T* ptr;
    int count;
    friend refcnt_ptr<T>;
};

(я бы не кодировал его таким образом, но он служит для изложения.)

Двойное косвенное обозначение this- > handle- > ptr может быть большой проблемой с производительностью. Или даже поле тройной косвенности, this- > handle- > ptr- > . По крайней мере, на машине с 5-мя циклами кеша L1 каждое поле this- > handle- > ptr- > занимает 10 циклов. И будет намного сложнее перекрыться, чем однократное преследование. Но, что еще хуже, если каждый из них является пропуском кеша L1, даже если он был всего 20 циклов для L2... ну, гораздо труднее скрыть 2 * 20 = 40 циклов латентности промаха кеша, чем один промах L1.

В общем, рекомендуется избегать уровней косвенности в интеллектуальных указателях. Вместо указания на дескриптор, на который указывают все умные указатели, который сам указывает на объект, вы можете сделать умный указатель большим, указав на объект, а также на дескриптор. (Который уже не является тем, что обычно называют дескриптором, но больше похоже на информационный объект.)

например.

template<typename T> class refcntptr {
    refcnt_info<T> info;
    T* ptr;
public:
    refcntptr(T*obj) {
        this->ptr = obj;
        this->info = new refcnt_handle<T>();
        this->info->count = 1;
    }
};
template<typename T> class refcnt_info {
    T* ptr; // perhaps not necessary, but useful.
    int count;
    friend refcnt_ptr<T>;
};

В любом случае - профиль времени - ваш лучший друг.


О, да, оборудование Intel EMON также может рассказать вам, сколько циклов вы ждали на ПК. Это может отличить большое количество промахов L1 от небольшого количества промахов L2.

Ответ 7

Мой совет: использовать PTU (Утилита настройки производительности) от Intel.

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

Ответ 8

Другим инструментом для профилирования производительности на основе производительности процессора является oprofile. Вы можете просмотреть его результаты с помощью kcachegrind.

Ответ 9

Вот общий общий ответ.

Например, если ваша программа тратит, скажем, 50% времени на пропуски в кеше, то в 50% случаев, когда вы приостанавливаете ее, счетчик программ будет находиться в точном месте, где он ждет, когда извлечет память которые вызывают промахи кэша.