Я хочу скопировать изображение на ядро ARMv7. Наивная реализация - вызов memcpy на строку.Быстрый ARM NEON memcpy
for(i = 0; i < h; i++) {
memcpy(d, s, w);
s += sp;
d += dp;
}
Я знаю, что следующий
d, dp, s, sp, w
все 32 байт выровнены, поэтому мой следующий (по-прежнему довольно наивный) реализация была по линии
for (int i = 0; i < h; i++) {
uint8_t* dst = d;
const uint8_t* src = s;
int remaining = w;
asm volatile (
"1: \n"
"subs %[rem], %[rem], #32 \n"
"vld1.u8 {d0, d1, d2, d3}, [%[src],:256]! \n"
"vst1.u8 {d0, d1, d2, d3}, [%[dst],:256]! \n"
"bgt 1b \n"
: [dst]"+r"(dst), [src]"+r"(src), [rem]"+r"(remaining)
:
: "d0", "d1", "d2", "d3", "cc", "memory"
);
d += dp;
s += sp;
}
который был ~ На 150% быстрее, чем memcpy на большом количестве итераций (на разных изображениях, поэтому не используйте кеширование). Я чувствую, что это должно быть нигде рядом с оптимальным, потому что я еще не использовал предварительную загрузку, но, когда я это делаю, мне кажется, что я могу сделать производительность значительно хуже. У кого-нибудь есть понимание?
Попробуйте развернуть петлю как минимум на 2 раза. Нагрузки NEON не являются мгновенными из-за конвейерной обработки и скорости памяти. Если вы делаете 2 загрузки, за которыми следуют 2 магазина, вы должны увидеть преимущество. Предварительная загрузка кеша может определенно ускорить работу, но расстояние чтения вперед должно быть настроено на вашу целевую платформу. – BitBank
Я пробовал это, но разница была незначительной. Я следовал тем же соображениям, но имейте в виду, что эти нагрузки и магазины всего 2 цикла каждый ([источник] (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344k /ch16s06s07.html)). Размер строки кэша - 64 байта, я попытался выполнить предварительную выборку на 64, 128, 192 и 256 байт, что сделало это значительно медленнее (2-3 раза). –
Вы пробовали смотреть на источник memcpy? Возможно, он уже оптимизирован и использует инструкции NEON на вашей платформе. –