Я искал быстрые способы копирования различных объемов данных, когда векторные инструкции NEON доступны на устройстве ARM.
Я провел несколько тестов и обнаружил кое-что интересное. результаты. Я пытаюсь понять, на что смотрю.
У меня есть четыре версии копирования данных:
1. Базовый вариант
Копируется поэлементно:
for (int i = 0; i < size; ++i)
{
copy = orig;
}
2. NEON
Этот код загружает четыре значения во временный регистр, а затем копирует регистр для вывода.
Таким образом количество загрузок сокращается вдвое. Возможно, есть способ пропустить временный регистр и снизить нагрузку на четверть, но я не нашел способа.
int32x4_t tmp;
for (int i = 0; i < size; i += 4)
{
tmp = vld1q_s32(orig + i); // load 4 elements to tmp SIMD register
vst1q_s32(©2, tmp); // copy 4 elements from tmp SIMD register
}
3. Пошаговая memcpy,
Использует memcpy, но копирует 4 элемента за раз. Это для сравнения с версией NEON.
for (int i = 0; i < size; i+=4)
{
memcpy(orig+i, copy3+i, 4);
}
4. Обычный memcpy
Использует memcpy с полным объемом данных.
memcpy(orig, copy4, size);
Мой тест с использованием значений 2^16 дал неожиданные результаты:
1. Baseline time = 3443[µs]
2. NEON time = 1682[µs]
3. memcpy (stepped) time = 1445[µs]
4. memcpy time = 81[µs]
Ожидается ускорение времени NEON, однако более быстрое время memcpy меня удивляет. А время для 4 тем более.
Почему memcpy работает так хорошо? Под капотом используется НЕОН? Или существуют эффективные инструкции копирования памяти, о которых я не знаю?
В этом вопросе обсуждались NEON и memcpy(). Однако я не считаю, что ответы достаточно объясняют, почему реализация ARM memcpy работает так хорошо
Полный листинг кода приведен ниже:
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[]) {
int arr_size;
if (argc==1)
{
std::cout
Подробнее здесь: https://stackoverflow.com/questions/637 ... intrinsics