memcpy используя sse, sse2, avx
От: Molchalnik  
Дата: 08.03.16 10:03
Оценка:
есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.

спасибо.

желательно на визуал студии, но джисиси тоже ничего.


З.ы. результат крайне желателен сегодня — за большее время я и сам разберусь, но будет уже поздняк метаться
Re: memcpy используя sse, sse2, avx
От: smeeld  
Дата: 08.03.16 10:21
Оценка: +1
Здравствуйте, Molchalnik, Вы писали:

M>есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.


Не знаю как там в ваших виндовсах, но в юниксах memcpy уже расписан на asm с использованием SSE. Его не надо переписывать по своему. В gcc есть builtins, врайпящие асмовые SSE инструкции.
Re[2]: memcpy используя sse, sse2, avx
От: Molchalnik  
Дата: 08.03.16 11:04
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Не знаю как там в ваших виндовсах, но в юниксах memcpy уже расписан на asm с использованием SSE. Его не надо переписывать по своему. В gcc есть builtins, врайпящие асмовые SSE инструкции.


как минимум, чтобы переписать memcpy на SSE, нужно потратиться на выравнивающую обвязку, что вызовет несколько джампов/goto, а каждый джамп — перезагрузка конвейера (если в предсказание конвейера не попасть)

у меня же тут клинически идеальный случай — всё уже выравнено как надо.
Re: memcpy используя sse, sse2, avx
От: watchmaker  
Дата: 08.03.16 11:36
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.

Общая идея очень простая:
#include "emmintrin.h"

void cpy(const char* src, char* dst, size_t sz) {
  using M = __m128i; // __m256 для avx
  const M* s = (const M*)src;
  M* d = (M*)dst;
  for (; sz > 0; sz -= sizeof(M) * 4) {
    *d++ = *s++; 
    *d++ = *s++;
    *d++ = *s++;
    *d++ = *s++;
  };
}


Впрочем я бы просто удостоверился, что в компиляторе используется достаточно свежая версия memcpy, которая знает про векторные инструкции, и использовал её. Потому как всё равно понадобится какая-то обвязка для такого кода. Например, нужно будет добавить код, который будет решить что делать, если avx процессором не поддерживается. И протестировать насколько вышеприведённый цикл лучше развернуть (может быть 8 итераций), и вообще может быть лучше с конца к началу копировать. И для очень длинных массивов написать ещё одну версию с non-temporal storage, чтобы кеш заполнять данными, которые всё равно туда не влезут (тут не ясно, бывает ли такой у тебя случай).
Конечно, memcpy обладает избыточностью и обрабатывает всякие невозможные тут ситуации, но даже с учётом этих затрат эта функция может быть очень хорошим выбором (до тех пор, пока профайлер не покажет, что кроме memcpy оптимизировать уже нечего)
Отредактировано 08.03.2016 11:57 watchmaker . Предыдущая версия . Еще …
Отредактировано 08.03.2016 11:48 watchmaker . Предыдущая версия .
Re[3]: memcpy используя sse, sse2, avx
От: ononim  
Дата: 08.03.16 15:05
Оценка: 3 (1)
S>>Не знаю как там в ваших виндовсах, но в юниксах memcpy уже расписан на asm с использованием SSE. Его не надо переписывать по своему. В gcc есть builtins, врайпящие асмовые SSE инструкции.
M>как минимум, чтобы переписать memcpy на SSE, нужно потратиться на выравнивающую обвязку, что вызовет несколько джампов/goto, а каждый джамп — перезагрузка конвейера (если в предсказание конвейера не попасть)
M>у меня же тут клинически идеальный случай — всё уже выравнено как надо.
__builtin_assume_aligned
Как много веселых ребят, и все делают велосипед...
Re: memcpy используя sse, sse2, avx
От: _NN_ www.nemerleweb.com
Дата: 09.03.16 05:24
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.


M>спасибо.


M>желательно на визуал студии, но джисиси тоже ничего.



M>З.ы. результат крайне желателен сегодня — за большее время я и сам разберусь, но будет уже поздняк метаться


О какой версии студии идёт речь ?
2013,2015 поддерживают AVX2 см: https://msdn.microsoft.com/en-us/library/7t5yh4fd%28v=vs.140%29.aspx
Нужно собрать программку в релизе с максимальными оптимизациями и просто посмотреть что генерируется.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: memcpy используя sse, sse2, avx
От: BulatZiganshin  
Дата: 10.03.16 17:38
Оценка: 4 (1)
Здравствуйте, Molchalnik, Вы писали:

M>есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.


в ассемблере — rep movsb. в C++ — memcpy полюс свежий компилятор
Люди, я люблю вас! Будьте бдительны!!!
Re[2]: memcpy используя sse, sse2, avx
От: smeeld  
Дата: 10.03.16 18:20
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>в ассемблере — rep movsb.


Это не SIMD. Кстати, movsb-это копирование побайтно, в наборе имеются инструкции копирования пословно, movsw, movsd, поэтому правильней сказать rep movsX.
Re[3]: memcpy используя sse, sse2, avx
От: BulatZiganshin  
Дата: 10.03.16 18:43
Оценка:
Здравствуйте, smeeld, Вы писали:

BZ>>в ассемблере — rep movsb.


S>Это не SIMD. Кстати, movsb-это копирование побайтно, в наборе имеются инструкции копирования пословно, movsw, movsd, поэтому правильней сказать rep movsX.


нет, используй именно rep movsb
Люди, я люблю вас! Будьте бдительны!!!
Re[4]: memcpy используя sse, sse2, avx
От: smeeld  
Дата: 10.03.16 18:52
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>нет, используй именно rep movsb


Буду использовать пакетный мовинг через AVX или XMM регистры. Так получается быстрее всего, измерял. rep movsX вообще уже из разяда устаревающего хлама.
Re[5]: memcpy используя sse, sse2, avx
От: BulatZiganshin  
Дата: 10.03.16 19:06
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Буду использовать пакетный мовинг через AVX или XMM регистры. Так получается быстрее всего, измерял. rep movsX вообще уже из разяда устаревающего хлама.


ясно. советую тебе читать intel/fog optimization manuals, чтобы в следующий раз не попасть впросак
Люди, я люблю вас! Будьте бдительны!!!
Отредактировано 10.03.2016 19:18 BulatZiganshin . Предыдущая версия .
Re[6]: memcpy используя sse, sse2, avx
От: smeeld  
Дата: 10.03.16 19:34
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, smeeld, Вы писали:


S>>Буду использовать пакетный мовинг через AVX или XMM регистры. Так получается быстрее всего, измерял. rep movsX вообще уже из разяда устаревающего хлама.


BZ> да и зачем вообще мерять, если у фога всё расписано??


Fog не авторитет, как и любой праздный писака-теоретик. Как они далеки от реальности можно понять заглянув в реализацию memcpy в glibc, например.
Отредактировано 10.03.2016 19:38 smeeld . Предыдущая версия .
Re[7]: memcpy используя sse, sse2, avx
От: BulatZiganshin  
Дата: 10.03.16 21:46
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Fog не авторитет, как и любой праздный писака-теоретик. Как они далеки от реальности можно понять заглянув в реализацию memcpy в glibc, например.


хоть этот код и не верх совершенства, но rep movsb он использует. мог бы сразу посмотреть чтобы зря не спорить
Люди, я люблю вас! Будьте бдительны!!!
Отредактировано 10.03.2016 22:45 BulatZiganshin . Предыдущая версия . Еще …
Отредактировано 10.03.2016 21:57 BulatZiganshin . Предыдущая версия .
Re[2]: memcpy используя sse, sse2, avx
От: Molchalnik  
Дата: 14.03.16 18:57
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, Molchalnik, Вы писали:


M>>есть блок памяти, выровненный по 32 байта. длина выровнена по 1024 байта. Подскажите, пожалуйста, как не залезая в ассемблер , интринсиками или ещё чем эффективно скопировать этот блок в другой, такого же размера.


BZ>в ассемблере — rep movsb. в C++ — memcpy полюс свежий компилятор


почему тогда не movdqa?
Re[3]: memcpy используя sse, sse2, avx
От: bnk СССР http://unmanagedvisio.com/
Дата: 14.03.16 19:52
Оценка: 4 (1) +1
Здравствуйте, Molchalnik, Вы писали:

BZ>>в ассемблере — rep movsb. в C++ — memcpy полюс свежий компилятор


M>почему тогда не movdqa?


Потому что (современные) процы обрабатывюет rep movsb специальным образом (a rep movqa нет), т.е. "тупое побайтовое копирование" будет быстрее чем SIMD или AVX

Beginning with processors based on Intel microarchitecture code named Ivy Bridge,
REP string operation using MOVSB and STOSB can provide both flexible and highperformance
REP string operations for software in common situations like memory
copy and set operations

Re[3]: memcpy используя sse, sse2, avx
От: watchmaker  
Дата: 14.03.16 19:55
Оценка: 4 (1)
Здравствуйте, Molchalnik, Вы писали:


BZ>>в ассемблере — rep movsb. в C++ — memcpy полюс свежий компилятор


M>почему тогда не movdqa?


movdqa будет быстрее для коротких участков (меньше 128 байт) и на на старых процессорах.

Про rep movs Агнер Фог пишет так:

The REP MOVS instruction (1) is a simple solution which is useful when optimizing for code
size rather than for speed. This instruction is implemented as microcode in the CPU. The
microcode implementation may actually use one of the other methods internally. In some
cases it is well optimized, in other cases not. Usually, the REP MOVS instruction has a large
overhead for choosing and setting up the right method. Therefore, it is not optimal for small
blocks of data.


Many modern processors have optimized the REP MOVS instruction (method 1) to use the
largest available register size and the fastest method, at least in simple cases. But there are
still cases where the REP MOVS method is slow, for example for certain misalignment cases
and false memory dependence. However, the REP MOVS instruction has the advantage that
it will probably use the largest available register size on processors in a more distant future
with registers bigger than 256 bits. As instructions with the expected future register sizes
cannot yet be coded and tested, the REP MOVS instruction is the only way we can write code
today that will take advantage of future extensions to the register size. Therefore, it may be
useful to use the REP MOVS instruction for favorable cases of large aligned memory blocks.



On many processors, REP MOVS and REP STOS can perform fast by moving 16 bytes or an
entire cache line at a time. This happens only when certain conditions are met. Depending
on the processor, the conditions for fast string instructions are, typically, that the count must
be high, both source and destination must be aligned, the direction must be forward, the
distance between source and destination must be at least the cache line size, and the
memory type for both source and destination must be either write-back or write-combining
(you can normally assume the latter condition is met).
Under these conditions, the speed is as high as you can obtain with vector register moves
or even faster on some processors.


В подтверждение можно заглянуть в официальный Intel 64 and IA-32 Architectures Optimization Reference Manual. Фича называется Enhanced REP MOVSB and STOSB operation (ERMSB). И если она поддерживается, то копирование длинных выровненных блоков будет быстрее чем реализация через SSE, AVX или что-то другое.
Re[4]: memcpy используя sse, sse2, avx
От: ononim  
Дата: 14.03.16 20:00
Оценка:
bnk>Потому что (современные) процы обрабатывюет rep movsb специальным образом (a rep movqa нет), т.е. "тупое побайтовое копирование" будет быстрее чем SIMD или AVX
У меня есть рацпредложение для Интел: оптимизировать и все остальные инструкции специальным образом, чтоб работали быстрее чем раньше. Глядишь и не придеться техпроцессы новые вводить..
Как много веселых ребят, и все делают велосипед...
Re[4]: memcpy используя sse, sse2, avx
От: smeeld  
Дата: 14.03.16 20:45
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>В подтверждение можно заглянуть в официальный Intel 64 and IA-32 Architectures Optimization Reference Manual. Фича называется Enhanced REP MOVSB and STOSB operation (ERMSB). И если она поддерживается, то копирование длинных выровненных блоков будет быстрее чем реализация через SSE, AVX или что-то другое.


Нифига оно не быстрее. Копирование через XMM и YMM регистры быстрее. Тестили, измеряли. Кто там лжёт, инженегеры интеля, или составители мануалов разбираться не интересно.
Re[5]: memcpy используя sse, sse2, avx
От: watchmaker  
Дата: 14.03.16 21:19
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Тестили, измеряли.


Ну, измерять производительность своего конкретного кода — это здравое действие, конечно. Цифры будет ценнее чем абстрактные примеры в идеальных условиях. А то может оказаться, что в программе и не memcpy тормозит :)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.