Cycles/cost для L1 Cache hit vs. Регистрация на x86?
Я помню, полагая, что кэш L1-кеша - это 1 цикл (то есть идентичный времени доступа к регистру) в моем классе архитектуры, но действительно ли это на современных процессорах x86?
Сколько циклов занимает луч L1? Как это сравнить с доступом к регистру?
Ответы
Ответ 1
Вот отличная статья на эту тему:
http://arstechnica.com/gadgets/reviews/2002/07/caching.ars/1
Чтобы ответить на ваш вопрос - да, кэш-кеш имеет примерно такую же стоимость, как и доступ к регистру. И, конечно, пропустить кеш довольно дорого;)
PS:
Специфика будет отличаться, но эта ссылка содержит несколько хороших цифр:
Приблизительная стоимость доступа к различным кешам и основной памяти?
Core i7 Xeon 5500 Series Data Source Latency (approximate)
L1 CACHE hit, ~4 cycles
L2 CACHE hit, ~10 cycles
L3 CACHE hit, line unshared ~40 cycles
L3 CACHE hit, shared line in another core ~65 cycles
L3 CACHE hit, modified in another core ~75 cycles remote
L3 CACHE ~100-300 cycles
Local DRAM ~30 ns (~120 cycles)
Remote DRAM ~100 ns
PPS:
Эти цифры представляют собой гораздо более старые, более медленные процессоры, но в основном отношения:
http://arstechnica.com/gadgets/reviews/2002/07/caching.ars/2
Level Access Time Typical Size Technology Managed By
----- ----------- ------------ --------- -----------
Registers 1-3 ns ?1 KB Custom CMOS Compiler
Level 1 Cache (on-chip) 2-8 ns 8 KB-128 KB SRAM Hardware
Level 2 Cache (off-chip) 5-12 ns 0.5 MB - 8 MB SRAM Hardware
Main Memory 10-60 ns 64 MB - 1 GB DRAM Operating System
Hard Disk 3M - 10M ns 20 - 100 GB Magnetic Operating System/User
Ответ 2
Нет.
Задержка кеша в одном цикле раньше использовалась в простых конвейерах упорядочения при более низких тактовых частотах (поэтому каждый цикл составлял больше наносекунд), особенно с более простыми кэшами (меньшими, не ассоциативными, и с меньшим TLB для кешей, которые не были чисто виртуально адресовано.) Например, классический 5-этапный конвейер RISC, такой как MIPS I, предполагает 1 цикл для доступа к памяти при попадании в кэш, с вычислением адреса в EX и доступом к памяти в MEM, до этапа WB.
Современные высокопроизводительные процессоры делят конвейер на несколько этапов, что позволяет сократить каждый цикл. Это позволяет простым инструкциям, таким как add
/or
/and
работать очень быстро, с задержкой в 1 цикл, но с высокой тактовой частотой.
Для получения дополнительной информации о подсчете циклов и выполнении вне порядка см. Pdf файл Agner Fog microarch и другие ссылки в вики-теге x86.
Время ожидания загрузки Intel Haswell L1 составляет 4 такта для отслеживания указателя, что типично для современных процессоров x86. т.е. как быстро mov eax, [eax]
может выполняться в цикле с указателем, который указывает на себя. (Или для связанного списка, который попадает в кеш, легко микробенч с замкнутым циклом). См. Также Есть ли штраф, если база + смещение находятся на странице, отличной от базы? Этот особый случай задержки с 4 циклами применяется только в том случае, если указатель поступает непосредственно от другой нагрузки, в противном случае он равен 5 циклам.
Задержка использования нагрузки на 1 цикл выше для векторов SSE/AVX в процессорах Intel.
Задержка перезагрузки хранилища составляет 5 циклов и не связана с попаданием или пропуском кэша (это переадресация магазина, чтение из буфера хранилища для данных хранилища, которые еще не зафиксированы в кэше L1d).
Как прокомментировал Гарольд, доступ к регистру равен 0 циклам. Так, например:
-
inc eax
имеет задержку в 1 цикл (только операция ALU) -
add dword [mem], 1
имеет 6 циклов задержки, пока не будет готова загрузка из dword [mem]
. (АЛУ + пересылка магазина). Например, хранение счетчика цикла в памяти ограничивает цикл одной итерацией на 6 циклов. -
mov rax, [rsi]
имеет 4 цикла задержки от готовности rsi
до готовности rax
к удару L1 (задержка использования нагрузки L1.)
http://www.7-cpu.com/cpu/Haswell.html содержит таблицу задержек на кэш (которую я скопирую здесь) и некоторые другие экспериментальные числа, включая задержку попадания L2-TLB (при промахе L1DTLB).
Intel i7-4770 (Haswell), 3,4 ГГц (Turbo Boost off), 22 нм. Оперативная память: 32 ГБ (PC3-12800 cl11 cr2).
- Кэш данных L1 = 32 КБ, 64 B/line, 8-WAY.
- Кэш инструкций L1 = 32 КБ, 64 B/line, 8-WAY.
- Кэш-память второго уровня = 256 КБ, 64 B/line, 8-WAY
-
Кэш-память L3 = 8 МБ, 64 B/строка
-
L1 Data Cache Latency = 4 цикла для простого доступа через указатель (mov rax, [rax]
)
- L1 Data Cache Latency = 5 циклов для доступа с вычислением сложного адреса (
mov rax, [rsi + rax*8]
). - Задержка кэша L2 = 12 циклов
- Задержка кэша L3 = 36 циклов
- Задержка ОЗУ = 36 циклов + 57 нс
Страница бенчмарка верхнего уровня - http://www.7-cpu.com/utils.html, но на самом деле не объясняет, что означают различные размеры тестов, но код доступен. Результаты теста включают Skylake, который почти такой же, как у Haswell в этом тесте.
Ответ @paulsm4 содержит таблицу для нескольких сокетов Nehalem Xeon, включая некоторые номера удаленной (другой сокет) памяти /L3.
Ответ 3
Если я правильно помню это примерно за 1-2 такта, но это оценка и новые кеши могут быть быстрее. Это из книги "Компьютерная архитектура" у меня есть, и это информация для AMD, поэтому Intel может немного отличаться, но я бы связал ее между 5 и 15 тактами, что мне кажется хорошей оценкой.
EDIT: Whoops L2 - 10 циклов с доступом TAG, L1 занимает от 1 до 2 циклов, моя ошибка:\
Ответ 4
Фактически, стоимость попадания кеша L1 почти такая же, как и стоимость доступа к регистру. Для меня это было удивительно, но это правда, по крайней мере для моего процессора (Athlon 64). Некоторое время назад я написал простое тестовое приложение для проверки эффективности доступа к общим данным в многопроцессорной системе. Тело приложения является простой переменной памяти, увеличивающейся в течение предопределенного периода времени. Чтобы сделать comapison, я сначала проверил не разделяемую переменную. И во время этого действия я захватил результат, но затем во время демонтажа приложения я обнаружил, что компилятор был обманут мои ожидания и применил нежелательную оптимизацию к моему коду. Он просто поместил переменную в регистр CPU и увеличил ее итеративно в регистре без доступа к памяти. Но реальный сюрприз был достигнут после того, как я заставил компилятор использовать переменную in-memory вместо переменной register. В обновленном приложении я достиг почти тех же результатов бенчмаркинга. Снижение производительности было действительно незначительным (~ 1-2%) и похоже на некоторый побочный эффект.
В результате:
1) Я думаю, что вы можете рассматривать кеш L1 как неуправляемый пул регистров процессора.
2) Нет никакого смысла применять грубую оптимизацию, заставляя хранилище компилятора часто получать данные в регистрах процессоров. Если они действительно доступны, они будут жить в кеше L1, и из-за этого будут иметь такую же стоимость доступа, как и регистр процессора.