Очень быстро memcpy для обработки изображений?

Я делаю обработку изображений на C, которая требует копирования больших fragmentов данных вокруг памяти – источник и место назначения никогда не перекрываются.

Каков самый быстрый способ сделать это на платформе x86 с использованием GCC (где доступны SSE , SSE2, но не SSE3)?

Я ожидаю, что решение будет либо в сборе, либо с использованием свойств GCC?

Я нашел следующую ссылку, но понятия не имею, лучше ли это сделать (автор также говорит, что у нее несколько ошибок): http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm. x86 / 2006-02 / msg00123.html

EDIT: обратите внимание, что копия необходима, я не могу обойтись, чтобы скопировать данные (я мог бы объяснить, почему, но я пощажу вам объяснение :))

Предоставлено Уильямом Ченом и Google. На 30-70% быстрее, чем memcpy в Microsoft Visual Studio 2005.

void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size) { __asm { mov esi, src; //src pointer mov edi, dest; //dest pointer mov ebx, size; //ebx is our counter shr ebx, 7; //divide by 128 (8 * 128bit registers) loop_copy: prefetchnta 128[ESI]; //SSE2 prefetch prefetchnta 160[ESI]; prefetchnta 192[ESI]; prefetchnta 224[ESI]; movdqa xmm0, 0[ESI]; //move data from src to registers movdqa xmm1, 16[ESI]; movdqa xmm2, 32[ESI]; movdqa xmm3, 48[ESI]; movdqa xmm4, 64[ESI]; movdqa xmm5, 80[ESI]; movdqa xmm6, 96[ESI]; movdqa xmm7, 112[ESI]; movntdq 0[EDI], xmm0; //move data from registers to dest movntdq 16[EDI], xmm1; movntdq 32[EDI], xmm2; movntdq 48[EDI], xmm3; movntdq 64[EDI], xmm4; movntdq 80[EDI], xmm5; movntdq 96[EDI], xmm6; movntdq 112[EDI], xmm7; add esi, 128; add edi, 128; dec ebx; jnz loop_copy; //loop please loop_copy_end: } } 

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

Вы также можете проверить источник memcpy (memcpy.asm) и удалить его специальную обработку. Возможно дальнейшая оптимизация!

На любом уровне оптимизации -O1 или выше GCC будет использовать встроенные определения для таких функций, как memcpy – с параметром right -march ( -march=pentium4 для набора функций, которые вы упомянули) он должен генерировать довольно оптимальный встроенный код для конкретной архитектуры.

Я бы сравнил его и посмотрел, что получится.

SSE-код, опубликованный hapalibashi, – это путь.

Если вам нужна еще большая производительность и не уклоняйтесь от долгой и извилистой дороги написания драйвера устройства: на всех важных платформах в настоящее время есть DMA-controller, который способен выполнять копирование быстрее и параллельно с кодом CPU мог сделать.

Это связано с написанием драйвера. Никакой большой ОС, о которой я знаю, предоставляет эту функциональность пользователю из-за рисков безопасности.

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

Этот вопрос сейчас четыре года, и я немного удивлен, что никто не упоминает пропускную способность памяти. CPU-Z сообщает, что у моей машины есть ОЗУ PC3-10700. То, что ОЗУ имеет максимальную пропускную способность (скорость передачи данных, пропускная способность и т. Д.), Составляет 10700 Мбайт / с. Процессор на моей машине – i5-2430M, с максимальной частотой турбонаддува 3 ГГц.

Теоретически, с бесконечно быстрым процессором и моей оперативной памятью memcpy может идти со скоростью 5300 Мбайт / с , то есть с половиной 10700, потому что memcpy должен читать, а затем записывать в ОЗУ. (edit: Как отметил v.oddou, это упрощенное приближение).

С другой стороны, представьте себе, что у нас была бесконечно быстрая оперативная память и реалистичный процессор, чего мы могли достичь? Давайте используем в качестве примера 3-ГГц процессор. Если бы он мог делать 32-битное чтение и 32-битную запись каждого цикла, тогда он мог бы передавать 3e9 * 4 = 12000 Мбайт / сек . Это кажется легко доступным для современного процессора. Уже сейчас мы видим, что код, запущенный на CPU, на самом деле не является узким местом. Это одна из причин того, что современные машины имеют кэши данных.

Мы можем измерить то, что CPU действительно может сделать, сравнивая memcpy, когда мы знаем, что данные кэшируются. Делать это аккуратно неудобно. Я сделал простое приложение, которое записывало случайные числа в массив, memcpy’d их в другой массив, затем проверило скопированные данные. Я прошел через код в отладчике, чтобы убедиться, что умный компилятор не удалил копию. Изменение размера массива изменяет производительность кэша – небольшие массивы вписываются в кеш, а большие – меньше. Я получил следующие результаты:

  • 40 Кбайт массивов: 16000 Мбайт / с
  • 400 Кбайт массивов: 11000 Мбайт / с
  • 4000 Кбайт массивов: 3100 Мбайт / с

Очевидно, что мой процессор может читать и записывать более 32 бит за цикл, поскольку 16000 – это больше, чем 12000, которые я вычислил теоретически выше. Это означает, что процессор даже меньше узкого места, чем я уже думал. Я использовал Visual Studio 2005 и вступил в стандартную реализацию memcpy, я вижу, что он использует инструкцию movqda на моей машине. Я думаю, это может читать и писать 64 бита за цикл.

Хороший код hapalibashi опубликовал на моей машине 4200 Мбайт / с – примерно на 40% быстрее, чем реализация VS 2005. Я думаю, что это быстрее, потому что он использует инструкцию prefetch для повышения производительности кеша.

Таким образом, код, выполняющийся на процессоре, не является узким местом, и настройка этого кода будет лишь небольшими улучшениями.

Если это касается процессоров Intel, вы можете выиграть от IPP . Если вы знаете, что это будет работать с графическим процессором Nvidia, возможно, вы можете использовать CUDA – в обоих случаях лучше выглядеть шире, чем оптимизировать memcpy () – они предоставляют возможности для улучшения вашего алгоритма на более высоком уровне. Они оба, однако, зависят от конкретного оборудования.

Если вы работаете в Windows, используйте API-интерфейсы DirectX , в которых есть определенные GPU- оптимизированные подпрограммы для обработки графики (насколько быстро это возможно: ваш CPU не загружен. Сделайте что-нибудь еще, пока GPU его обманывает).

Если вы хотите быть агностиком OS, попробуйте OpenGL .

Не играйте с ассемблером, потому что слишком вероятно, что вы потерпите неудачу, чтобы превзойти 10-летних + опытных разработчиков программного обеспечения для библиотек.

  • Правильное изменение неопределенного поведения, если число больше ширины типа?
  • _addcarry_u64 и _addcarryx_u64 с MSVC и ICC
  • Не удалось загрузить файл или сборку HRESULT: 0x80131515 (При добавлении controllerа в проект MVC с ссылками на сборку на сетевом диске)
  • Visual Studio 2010: ссылочные сборки Ориентация на версию с более высокой версией
  • как загрузить все сборки из вашего каталога / bin
  • В чем разница между MOV и LEA?
  • Эффективное умножение матрицы 4x4 (C vs assembly)
  • Почему XCHG reg, reg 3 инструкции по микрооперации на современных архитектурах Intel?
  • Код C ++ для проверки гипотезы Collatz быстрее, чем assembly вручную - почему?
  • Проверьте, равен ли регистр нулю с помощью CMP reg, 0 против OR reg, reg?
  • Примеры предварительной выборки?
  • Давайте будем гением компьютера.