movntss
только для AMD (SSE4A) и поддерживается начиная с K10. Это медленнее, чем movntps
, однако, в семье Бульдозеров и Райзене. (Один на пропускную способность 4c против одного на 1c для Ryzen's movntps xmm
.)
movnti
(из целочисленного регистра) имеет ту же пропускную способность, что и movntps xmm
на AMD Piledriver (2c), Steamroller (1c) и Ryzen (1c).
movnti
является частью SSE2, поэтому он доступен (и эффективен) на процессорах Intel.
Ваши числа являются целыми числами (и вы все равно нуждаетесь в них в целочисленных регистрах, чтобы использовать младшие биты в качестве индекса массива), поэтому если вы собираетесь использовать хранилища NT для этого, вы ' d использовать movnti
не movntss
.
на ЦПУ с 6-полосным кэшем ассоциативных данных с 24-килобайтным набором
Все процессоры с SSE2 имеют гораздо большие кэши L2, которые вам необходимо учитывать. Удар L2 намного быстрее, чем RAM.
Это очень уникальный размер. У вас есть Intel Silvermont или в порядке Atom ( Bonnell или Saltwell ) с 24KB L1D и не менее 512 КиБ. Кэш-память второго уровня (на ядро или совместно используется парой corse).
Но в любом случае, совсем не AMD, поэтому movss
никогда не было вариантом. Маломощные Bobcat / Jaguar от AMD имеют нормальные 32-килобайтные L1d-кеши, а их основные ядра имеют 64-килобайтный ( K8 / K10 ), 16-килобайтный (семейство Bulldozer) или 32-килобайтный (Ryzen) L1d-кэши. и все они имеют гораздо большие кэши L2.
Что еще более важно, кэши с обратной записью L1d + L2 будут эффективно комбинировать записи для ваших выходных блоков. Я не думаю, что вы хотите магазины NT вообще.
Вам нужен ваш массив int *x[]
, чтобы оставаться горячим в L1d, потому что вы читаете, изменяете и пишете его внутри цикла. Но я думаю, что это обычно происходит с обычными алгоритмами кэширования LRU.
Магазины NT ужасны из-за слишком большого количества выходных потоков. Они наиболее эффективны, когда вы можете сохранить полную строку кэша до очистки буфера заполнения строки, что происходит, если подсистеме памяти она нужна для других строк, входящих / выходящих из L1d.
На основной платформе Intel каждое ядро имеет 10 LFB, начиная с Nehalem. Где находится объединяющий запись буфер? x86 . (При гиперпоточности они распределяются между ядрами, но IDK, если это статическое разбиение, например, буфер хранилища, или конкурентное совместное использование, например, сам L1d.)
В основных ядрах (IDK для Atom / Silvermont) хранилища NT имеют большую задержку перед передачей строки кэша на внешние уровни подсистемы памяти ( Enhanced REP MOVSB для memcpy ), но избегание RFO может возможно, будет преимуществом. Вы должны были бы измерить.
Моя самая большая проблема в том, что это было бы ужасно, если бы равнялся любому шаблону в ваших данных, который приводит к множеству не совсем последовательных сохранений в одном сегменте. Шаблон, который L1d могло бы быть поглощено, может быть ужасно с хранилищами NT, которые очищаются до того, как следующее хранилище может присоединиться к нему в буфере объединения записи.
так что этот код может привести к большой потере кэша
Возможно, вам лучше сделать два прохода; при первом проходе используется достаточно мало сегментов, чтобы выходные лотки оставались горячими в кеше большую часть времени (по крайней мере, если вы наклоните их, чтобы они не достигли одного и того же набора в вашем кэше).
Затем сортируйте каждое ведро отдельно; в идеале он поместится в кэш L1d.