Я понял, что Little Law ограничивает скорость передачи данных при заданной задержке и заданном уровне concurrency. Если вы хотите перевести что-то быстрее, вам либо нужны большие трансферы, либо больше передач "в полете", либо более низкая латентность. В случае чтения из ОЗУ concurrency ограничено количеством буферов заполнения строк.
Буфер заполнения строки выделяется, когда загрузка пропускает кеш L1. Современные чипы Intel (Nehalem, Sandy Bridge, Ivy Bridge, Haswell) имеют 10 LFB на ядро и, таким образом, ограничены 10 выдающимися промахами кэша на ядро. Если время ожидания лазера составляет 70 нс (правдоподобно), и каждая передача составляет 128 байт (линия кэша 64B плюс его предварительно настроенное двойное соединение), это ограничивает пропускную способность на ядро до: 10 * 128B/75 ns = ~ 16 ГБ/с. Тесты, такие как однопоточные Stream, подтверждают, что это достаточно точно.
Очевидным способом уменьшить задержку будет предварительная выборка желаемых данных с помощью инструкций x64, таких как PREFETCHT0, PREFETCHT1, PREFETCHT2 или PREFETCHNTA, так что ее не нужно читать из ОЗУ. Но я не смог что-то ускорить, используя их. Кажется, проблема заключается в том, что сами команды __mm_prefetch() потребляют LFB, поэтому они тоже подвержены тем же пределам. Предварительные настройки оборудования не касаются LFB, но также не будут пересекать границы страниц.
Но я не могу найти нигде этого документально. Самое близкое, что я нашел, - это 15-летняя статья , в которой говорится, что prefetch на Pentium III использует Buffer Fill Buffers. Я беспокоюсь, что с тех пор ситуация изменилась. И так как я думаю, что LFB связаны с кешем L1, я не уверен, почему их будет использовать prefetch для L2 или L3. И тем не менее, скорости, которые я измеряю, согласуются с этим.
Итак: есть ли способ инициировать выборку из нового места в памяти, не используя один из этих 10 буферов линейной заливки, тем самым достигая более высокой пропускной способности, обойдя вокруг Little Law?