Разница между предварительной выборкой для чтения или записи

В документах gcc говорится о различии между предварительной выборкой для чтения и предварительной выборки для записи. Какая техническая разница?

    На уровне процессора предварительная выборка программного обеспечения (в отличие от тех, которые запускаются самим аппаратом) – это удобный способ намекнуть на CPU, что линия должна быть доступна, и вы хотите заранее запрограммировать ее для сохранения задержки.

    Если доступ будет простым чтением, вам нужна регулярная предварительная выборка, которая будет вести себя аналогично нормальной нагрузке из памяти (кроме того, что она не блокирует CPU в случае ее промаха, а не сбои в случае плохого адреса и всевозможные других преимуществ, в зависимости от микро архитектуры).

    Однако, если вы собираетесь писать в эту строку, и она также существует в другом ядре, простой операции чтения будет недостаточно. Это связано с протоколами обработки кэша на основе MESI. Ядро должно владеть линией до ее модификации, чтобы сохранить согласованность (если одна и та же строка будет изменена в нескольких ядрах, вы не сможете обеспечить правильный порядок этих изменений и даже потеряете некоторые из них, что не допускается для обычных типов памяти WB). Вместо этого операция записи начнется с приобретения права собственности на линию и последующего отслеживания ее из любого другого ядра / сокета, в котором может храниться копия. Только тогда может произойти запись. Операция чтения (запрос или предварительная выборка) оставила бы линию в других ядрах в общем состоянии, что хорошо, если строка читается несколько раз по многим ядрам, но не помогает вам, если ваше kernel ​​позже записывает на нее.

    Чтобы обеспечить полезную предварительную выборку для строк, которые позже будут записаны, большинство компаний ЦП поддерживают специальные префиксы для записи. В x86, как Intel, так и AMD поддерживают инструкцию prefetchW, которая должна иметь эффект записи (т. Е. – получение единственного права собственности на строку и аннулирование любой другой копии, если она). Обратите внимание, что не все процессоры поддерживают это (даже в том же семействе, а не во всех поколениях), и не все версии компилятора позволяют это.

    Вот пример (с gcc 4.8.2) – обратите внимание, что вам нужно включить его явно здесь –

    #include  int main() { long long int a[100]; __builtin_prefetch (&a[0], 0, 0); __builtin_prefetch (&a[16], 0, 1); __builtin_prefetch (&a[32], 0, 2); __builtin_prefetch (&a[48], 0, 3); __builtin_prefetch (&a[64], 1, 0); return 0; } 

    скомпилирован с gcc -O3 -mprfchw prefetchw.c -c

     0000000000000000 
    : 0: 48 81 ec b0 02 00 00 sub $0x2b0,%rsp 7: 48 8d 44 24 88 lea -0x78(%rsp),%rax c: 0f 18 00 prefetchnta (%rax) f: 0f 18 98 80 00 00 00 prefetcht2 0x80(%rax) 16: 0f 18 90 00 01 00 00 prefetcht1 0x100(%rax) 1d: 0f 18 88 80 01 00 00 prefetcht0 0x180(%rax) 24: 0f 0d 88 00 02 00 00 prefetchw 0x200(%rax) 2b: 31 c0 xor %eax,%eax 2d: 48 81 c4 b0 02 00 00 add $0x2b0,%rsp 34: c3 retq

    Если вы играете со вторым аргументом, вы заметите, что уровни подсказок игнорируются для prefetchW, поскольку он не поддерживает подсказки на уровне времени. Кстати, если вы удалите флаг -mprfchw, gcc преобразует его в обычную предварительную выборку чтения (я не пробовал разные настройки -march / mattr, возможно, некоторые из них также include его).

    Разница связана с тем, ожидаете ли вы, что память будет только скоро прочитана или также будет записана. В более позднем случае процессор может быть оптимизирован по-разному. Помните, что prefetch – это только подсказка, поэтому GCC может ее игнорировать.

    Чтобы процитировать страницу проекта предварительной выборки GCC :

    В некоторых инструкциях предварительной выборки данных проводится различие между памятью, которая, как ожидается, будет считана, и память, которая, как ожидается, будет записана. Когда данные должны быть записаны, команда предварительной выборки может переместить блок в кеш, чтобы ожидаемый магазин был в кеше. Предварительная выборка для записи обычно приводит данные в кеш в исключительном или измененном состоянии.