В руководстве Agner Fog Оптимизация программного обеспечения на С++ в разделе 9.10 "Конфессии Cahce в больших структурах данных" он описывает проблему, переносящую матрицу, когда ширина матрицы равна так называемому критическому шагу. В его тесте стоимость для матрицы в L1 на 40% больше, когда ширина равна критическому шагу. Если матрица еще больше и подходит только в L2, стоимость составляет 600%! Это хорошо подведено в таблице 9.1 в его тексте. Это очень важно, Почему перенос матрицы 512x512 намного медленнее, чем перенос матрицы из 513x513?
Позже он пишет:
Причина, по которой этот эффект намного сильнее для до уровня кэша уровня 2, чем для утверждений о кэшировании уровня 1, заключается в том, что кеш уровня 2 не может предварять более одной строки за раз.
Итак, мои вопросы связаны с предварительной выборкой данных.
Из его комментария я делаю вывод, что L1 может предварительно отбирать несколько строк кэша за раз. Сколько может быть prefetch?
Из того, что я понимаю, попытка написать код для предварительной выборки данных (например, с помощью _mm_prefetch) редко бывает полезной. Единственным примером, который я прочитал, является Prefetching Examples?, и это только улучшение O (10%) (на некоторых машинах). Агнер позже объясняет это:
Причина в том, что современные процессоры автоматически извлекают данные из-за исполнение вне порядка и расширенные механизмы прогнозирования. Современные микропроцессоры возможность автоматической предварительной выборки данных для обычных шаблонов доступа, содержащих несколько потоков с разными шагами. Поэтому вам не нужно предварительно выбирать данные, если доступ к данным может располагаться в регулярных шаблонах с фиксированными шагами.
Итак, как же ЦПУ решает, какие данные нужно предварительно запрограммировать, и есть ли способы помочь ЦП сделать лучший выбор для предварительной выборки (например, "регулярные шаблоны с фиксированными шагами" )?
Изменить: Основываясь на комментарии Leeor, позвольте мне добавить к моим вопросам и сделать его более интересным. Почему критический шаг имеет гораздо большее влияние на L2 по сравнению с L1?
Изменить: Я попытался воспроизвести таблицу Agner Fog с помощью кода Почему перенос матрицы 512x512 намного медленнее, чем перенос матрицы из 513x513? Я запускал это с 64-разрядным режимом MSVC2013 на Xeon E5 1620 (Ivy Bridge), который имеет L1 32KB 8-way, L2 256 KB 8-way и L3 10MB 20-way. Максимальный размер матрицы для L1 составляет около 90x90, 256x256 для L3 и 1619 для L3.
Matrix Size Average Time
64x64 0.004251 0.004472 0.004412 (three times)
65x65 0.004422 0.004442 0.004632 (three times)
128x128 0.0409
129x129 0.0169
256x256 0.219 //max L2 matrix size
257x257 0.0692
512x512 2.701
513x513 0.649
1024x1024 12.8
1025x1025 10.1
Я не вижу потери производительности в L1, однако у L2 явно есть проблема с критическим шагом и, возможно, L3. Я еще не уверен, почему L1 не показывает проблемы. Возможно, есть и другой источник фона (накладных расходов), который доминирует в L1 раз.