Правильное использование инструкции ARM PLD (ARM11)
ARM ARM на самом деле не дает правильного способа использования этой инструкции, но я обнаружил, что он используется в другом месте, чтобы знать, что он принимает адрес как подсказку о том, где читать следующее значение.
Мой вопрос, учитывая 256-байтовый цикл копирования ldm/stm
инструкции, скажем, r4-r11 x 8, было бы лучше предварительно выбрать каждую строку кэша перед копированием, между каждой парой команд, или не делать это вообще, как memcpy
речь идет не о чтении и записи в одной и той же области памяти. Я уверен, что мой размер строки кэша составляет 64 байта, но это может быть 32 байта - в ожидании подтверждения об этом перед написанием окончательного кода здесь.
3 ответа
Из Руководства программиста серии Cortex-A, глава 17.4 (NB: некоторые детали могут отличаться для ARM11):
Наилучшая производительность для memcpy() достигается при использовании LDM всей строки кэша, а затем записи этих значений в STM всей строки кэша. Выравнивание магазинов важнее, чем выравнивание грузов. Инструкция PLD должна использоваться там, где это возможно. В блоке загрузки / хранения есть четыре слота PLD. Инструкция PLD имеет приоритет над автоматическим предварительным извлечением и не требует затрат с точки зрения производительности целочисленного конвейера. Точная синхронизация инструкций PLD для наилучшего memcpy() может незначительно отличаться в разных системах, но PLD по адресу на три строки кэша перед текущей копируемой строкой является полезной отправной точкой.
Пример достаточно общего цикла копирования, который использует размер кэширования LDM
/ STM
блоки и / или PLD
где доступно можно найти в ядре Linux, arch/arm/lib/copy_page.S
, Это реализует то, что Игорь упоминает выше относительно использования предварительных загрузок, и иллюстрирует блокировку.
Обратите внимание, что на ARMv7 (где размер строки кэша обычно составляет 64 байта) невозможно LDM
полная кешлайн как одна операция (с тех пор вы можете использовать только 14 рег SP
/ PC
не может быть тронут за это). Таким образом, вам, возможно, придется использовать две / четыре пары LDM
/ STM
,
Чтобы действительно получить "самый быстрый" из возможных ARM-асм-кодов, вам нужно протестировать различные подходы в вашей системе. Что касается цикла ldm/stm, этот мне кажется наиболее подходящим:
// Use non-conflicting register r12 to avoid waiting for r6 in pld
pld [r6, #0]
add r12, r6, #32
1:
ldm r6!, {r0, r1, r2, r3, r4, r5, r8, r9}
pld [r12, #32]
stm r10!, {r0, r1, r2, r3, r4, r5, r8, r9}
subs r11, r11, #16
ldm r6!, {r0, r1, r2, r3, r4, r5, r8, r9}
pld [r12, #64]
stm r10!, {r0, r1, r2, r3, r4, r5, r8, r9}
add r12, r6, #32
bne 1b
В вышеприведенном блоке предполагается, что вы уже настроили r6, r10, r11, и этот цикл ведет обратный отсчет на словах r11, а не байтах. Я проверил это на Cortex-A9 (iPad2), и, похоже, на этом процессоре он показывает неплохие результаты. Но будьте осторожны, потому что на Cortex-A8 (iPhone4) петля NEON кажется быстрее, чем ldm/stm, по крайней мере, для больших копий.