Почему время выполнения кода ниже уменьшается при увеличении kNumCacheLines
?
На каждой итерации код изменяет одну из kNumCacheLines
строк кэша, записывает строку в DIMM с clwb
инструкция, и блокирует, пока хранилище не попадет в контроллер памяти с sfence
. В этом примере требуются серверные процессоры Intel Skylake или более новые клиентские процессоры Xeon или IceLake.
#include <stdlib.h>
#include <stdint.h>
#define clwb(addr) \
asm volatile(".byte 0x66; xsaveopt %0" : "+m"(*(volatile char *)(addr)));
static constexpr size_t kNumCacheLines = 1;
int main() {
uint8_t *buf = new uint8_t[kNumCacheLines * 64];
size_t data = 0;
for (size_t i = 0; i < 10000000; i++) {
size_t buf_offset = (i % kNumCacheLines) * 64;
buf[buf_offset] = data++;
clwb(&buf[buf_offset]);
asm volatile("sfence" ::: "memory");
}
delete [] buf;
}
(примечание редактора: _mm_sfence()
и _mm_clwb(void*)
позволяют избежать использования встроенного asm, но этот встроенный asm выглядит корректно, включая"memory"
clobber).
Вот некоторые показатели производительности на моем аппарате Skylake Xeon, о которых сообщается при запуске time ./bench
с различными значениями kNumCacheLines
:
kNumCacheLines Time (seconds)
1 2.00
2 2.14
3 1.74
4 1.82
5 1.00
6 1.17
7 1.04
8 1.06
Интуитивно яможно ожидать, что kNumCacheLines = 1
даст лучшую производительность из-за попаданий в очередь ожидания записи контроллера памяти. Но это один из самых медленных.
В качестве объяснения неинтуитивного замедления, возможно, что, пока контроллер памяти завершает запись в строку кэша, он блокирует другие записи в той же строке кэша. Я подозреваю, что увеличение kNumCacheLines
увеличивает производительность из-за более высокого параллелизма, доступного контроллеру памяти. Время работы увеличивается с 1,82 до 1,00 секунды, когда kNumCacheLines
изменяется с четырех до пяти. Похоже, это коррелирует с тем фактом, что очередь ожидающих записи контроллера памяти имеет место для 256 байтов из потока [https://arxiv.org/pdf/1908.03583.pdf, Section 5.3].
Обратите внимание, что, поскольку buf
меньше 4 КБвсе доступы используют один и тот же модуль DIMM. (Предполагается, что он выровнен и не пересекает границы страницы)