Генерация 64-байтового чтения PCIe TLP из процессора x86
При записи данных на устройство PCIe можно использовать сопоставление записи, чтобы указать процессору, что он должен генерировать 64-байтовые TLP по отношению к устройству.
Можно ли сделать что-то подобное для чтения? Каким-то образом подсказывает процессору прочитать всю строку кэша или больший буфер вместо чтения по одному слову за раз?
2 ответа
У Intel есть документ по копированию из видеопамяти в основную память; это должно быть похоже, но намного проще (потому что данные помещаются в 2 или 4 векторных регистра).
Это говорит о том, что NT загружает целую строку кеша данных из памяти WC в LFB:
Обычные инструкции загрузки извлекают данные из памяти USWC в единицах того же размера, что и запросы инструкций. Напротив, инструкция потоковой загрузки, такая как MOVNTDQA, обычно вытягивает полную строку кэша данных в специальный "буфер заполнения" в ЦП. Последующие потоковые загрузки будут читать из этого буфера заполнения, что приведет к гораздо меньшей задержке.
Используйте AVX2 _mm256_stream_load_si256()
или SSE4.1/AVX1 128-битная версия.
Заполняющие буферы являются ограниченным ресурсом, поэтому вы определенно хотите, чтобы компилятор генерировал asm, который выполняет две выровненные загрузки 64-байтовой строки кэша, а затем сохраняет их в обычной памяти.
Если вы выполняете более одного 64-байтового блока за раз, обратитесь к техническому документу Intel за рекомендацией об использовании небольшого отказов буфера, который остается горячим в L1d, чтобы избежать смешивания хранилищ с DRAM с нагрузками NT. (Выселение L1d в DRAM, как и хранилища NT, также требует буферов заполнения строки, LFB).
Обратите внимание, что _mm256_stream_load_si256()
не используется вообще для типов памяти, отличных от WC. Подсказка NT игнорируется на текущем оборудовании, но в любом случае она требует дополнительной ALU-операции по сравнению с обычной загрузкой. Есть prefetchnta
, но это совершенно другой зверь.
Корпорация Intel опубликовала официальный документ о том, как осуществлять передачу данных по PCIe 64B: как реализовать пакетную передачу PCIe * 64B на архитектуре Intel®.
Принципы:
- Карта региона как WC.
Используйте следующий код для записи 64B
_mm256_store_si256(pcie_memory_address, ymm0); _mm256_store_si256(pcie_memory_address+32, ymm1); _mm_mfence();
куда _mm256_store_si256
является неотъемлемой частью (v)movdqa
и mfence
используется для заказа магазинов с новыми и очистки буфера WC.
Что касается моего ограниченного понимания части WC подсистемы кеша, то здесь есть ряд предположений:
CPU записывает буфер WC как пакетную транзакцию, только если буфер WC заполнен:
Единственными элементами распространения WC к системной шине, которые гарантированы, являются те, которые обеспечиваются атомарностью транзакции. Например, с процессором семейства P6 полностью полный буфер WC всегда будет распространяться как одна 32-битная пакетная транзакция с использованием любого чанкового порядка. При освобождении буфера WC, когда данные будут удалены как частичные, все данные, содержащиеся в одном и том же фрагменте (выровненные по 0 mod 8), будут распространяться одновременно.
Поэтому нужно обязательно использовать пустой буфер WC, иначе будет сделана 32-битная транзакция, и, что еще хуже, верхний блок может быть записан перед нижним.
На форуме Intel проводятся практические эксперименты с использованием FPGA, где буфер WC иногда преждевременно сбрасывается.Тип кэша WC гарантирует, что ядро записывает пакетную транзакцию, но uncore также должен быть в состоянии обработать эту транзакцию в целом.
В частности, после вычитающего декодирования комплекс Root должен уметь обрабатывать его как транзакцию 64B.
Из того же сообщения на форуме выше, кажется, что uncore способен объединять последовательные записи WC в один TLP, но играет с порядком записи (например, меняя местами два_mm256_store_si256
или оставление отверстия для размеров меньше 64B) может выпасть из возможностей корневого комплекса.