Вы пробовали развернуть петлю?
- Я бы не беспокоился о промахах L1 прямо сейчас. Также допустим один промах L2 из 1224, процессор должен в какой-то момент загрузить значения в кеш.
- Какой процент промахов L2 стоит для этого кода по сравнению с остальной частью программы?
- Используйте calloc(), если размер массива всегда один и тот же, и вы используете константы для размера, тогда компилятор может оптимизировать обнуление массива. Кроме того, единственное, что может повлиять на использование строк кэша, — это выравнивание, а не то, как оно было инициализировано.
изменить: число, которое трудно прочитать таким образом, и прочитать его неправильно в первый раз.
давайте удостоверимся, что я правильно читаю числа для строки 5:
Ir 146,880
I1mr 1,224
ILmr 1
Dr 48,960
D1mr 0
DLmr 0
Dw 24,480
D1mw 0
DLmw 0
Кэш L1 разделен на два кэша по 32 КБ: один для кода I1 и один для данных D1. IL и DL — это кеш L2 или L3, который используется как для данных, так и для инструкций.
Большое количество I1mr — это пропуски инструкций, а не пропуски данных, это означает, что код цикла выбрасывается из кэша инструкций I1.
I1 промахивается в строке 1 и 5, всего 3672, что составляет 3 раза по 1224, поэтому каждый раз, когда цикл запускается, вы получаете 3 промаха кеша I1 с 64-байтными строками кеша, что означает, что размер кода цикла составляет от 128 до 192 байтов, чтобы покрыть 3 строки кеша. Таким образом, I1 пропускает строку 5 потому, что код цикла пересекает последнюю строку кэша.
Я бы рекомендовал использовать KCachegrind для просмотра результатов от cachegrind
Изменить: Подробнее о строках кеша.
Этот код цикла не выглядит так, будто он вызывается сам по себе 1224 раза, так что это означает, что есть еще код, который выталкивает этот код из кеша I1.
Ваш 32-килобайтный кэш I1 разделен на 512 строк кэша (по 64 байта каждая). Часть «8-way set associative» означает, что каждый адрес памяти отображается только на 8 из этих 512 строк кэша. Если бы вся программа, которую вы профилируете, представляла собой один непрерывный блок из 32 Кбайт памяти, то вся она поместилась бы в кэш I1, и ни одна из них не была бы извлечена. Это, скорее всего, не так, и для тех же 8 строк кэша будет содержаться более 8 блоков кода по 64 байта. Предположим, что вся ваша программа имеет 1 Мбайт кода (включая библиотеки), тогда каждая группа из 8 строк кэша будет содержать около 32 (1 Мбайт/32 Кбайт) фрагментов кода, содержащихся в тех же 8 строках кэша.
Прочитайте эту статью lwn.net, чтобы узнать все кровавые подробности о кэшах ЦП
Компилятор не всегда может определить, какие функции программы будут активными (вызываются много раз), а какие — кодовыми точками (то есть кодом обработчика ошибок, который почти никогда не запускается). GCC имеет функциональные атрибуты горячий/холодный, которые позволяют чтобы пометить функции как горячие/холодные, это позволит компилятору сгруппировать горячие функции вместе в одном блоке памяти, чтобы лучше использовать кеш (т. е. холодный код не будет выталкивать горячий код из кешей).
В любом случае, эти промахи I1 действительно не стоят того, чтобы беспокоиться о них.
person
Neopallium
schedule
01.11.2010