Pull to refresh

Comments 17

Отличная статья, спасибо за перевод. Думаю, много кто уже почитал в оригинале, но перевод точно лишним не будет)

Как добавить hw в /proc/sys? (Без этого не работают команды sysctl для кэша.)

не очень понятно, почему в заголовке статьи Go, вроде бы как ничего go-специфичного тут нет

Скорее всего потому, что ускоряли программы на Go.
Статься как-будто написана по мотивам U.Drepper «What every programmer should know about memory». Там есть и пример с матрицами и про false sharing и еще много чего интересного о кешах CPU.
есть же L2 и L3, оптимизация рассмотрена исключительно под L1

До кучи: Крис Касперски "Техника оптимизации программ. Эффективное использование памяти".

«Гонщику не обязательно быть инженером, но нужен интерес к механике»
— это из статьи про кеши с фотографией южного моста, браво!
Go — это удивительный язык, который можно легко улучшить.
Ну ключевое событие в жизни компилятора Go — самокомпиляция, судя по всему, состоялось 5 лет назад. Дальше — лучше.
UFO just landed and posted this here
Что нужно почитать, чтобы осилить данный материал?

а что именно вам непонятно? я пробежал по диагонали, конечно, но вроде бы написаны достаточно очевидные вещи

Я бы ещё про ассоциативность добавил.

У меня на «ПК getconf -a | grep CACHE» выводит это:
LEVEL1_ICACHE_SIZE 32768
LEVEL1_ICACHE_ASSOC 8
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_ASSOC 8
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 262144
LEVEL2_CACHE_ASSOC 4
LEVEL2_CACHE_LINESIZE 64
LEVEL3_CACHE_SIZE 6291456
LEVEL3_CACHE_ASSOC 12
LEVEL3_CACHE_LINESIZE 64

Как видно, у меня L1I и L1D — 8-ассоциативные.

При обращении к какому-либо адресу, скажем 0x12345678, поиск не будет осуществляться по всем 32кб L1D, а только к тем 8-ми к которым этот адрес может относиться.

Легко вычислить, что у меня количество Set'ов будет 32768 / (8 (ассоциативность) * 64 (кол-во байт кэш-строки)) = 64.
Можно нарисовать табличку 64 x 8 и сказать, что часть адресов будет относится к 8-мью кэш-строкам из одного Set'а, другие — к 8-мью из другого.

Номер Set'а с которым будет сравнение вычисляется из адреса.
В моём случае кэш-строка — 64 байта, соответственно биты 0..5 адреса отвечают за индекс байта внутри кэш-строки.
В моём случае количество Set'ов — 64, соответственно биты 6..11 адреса отвечают за выбор Set'а.
А биты с 12-го уже образуют tag, который и будет проверятся на попадание / промах с восемью тэгами из кэша (для адреса 0x12345678 тэгом будет 0x12345).

Смысл этого. Если делать полностью ассоциативный кэш, снизится быстродействие кэша (надо много всего сравнить, больше комбинаторики, ниже частота). Если одно-ассоциативный, будет много кэш-промахов, снизится итоговая производительность. Ассоциативность 4-8 для низкоуровневых кэш — вполне оптимальные значения.

Практический смысл для программистов тот же — понимать как работает железо, при решении проблем быстродействия.
При программировании встроенных систем (если мы занимаемся назначением адресов), не стоит любить круглые адреса: 0x1000, 0x2000, 0x3000. Можно нарваться на то, что они все будут принадлежать к одному Set'у и будет использована только 1/64 кэш-памяти (ну или сколько там Set'ов), что не есть эффективно.
Но!!! Тут надо быть очень осторожными, чтобы не заточить программу под конкретный тип микропроцессора.
Ну и преждевременная оптимизация — зло. Решать надо проблемы в том месте, где они есть.

А еще есть "регистровый файл" и тоже немаленький, 2 килобайта для AVX-512....

Sign up to leave a comment.