Войти
ПрограммированиеФорумОбщее

C++, низкий уровень, оптимизация быстродействия. (2 стр)

Страницы: 1 2 3 412 Следующая »
#15
(Правка: 13:26) 13:22, 13 фев. 2019

Mikle
> Попробую. А с кэшем проблем не будет?
Да можно использовать и инкременты, для инициализации брать отрицательные значения. Код также будет (для x86):

MOV ECX, count
LEA EAX,[ECX+dstsrc1]
LEA EBX,[ECX+src2]
NEG ECX
@@:
MOVQ XMM1,[EAX+ECX]
PADDUSB XMM1,[EBX+ECX]
MOVQ [EAX+ECX],XMM1
ADD ECX,10
JNZ @B
Это без проверки count на валидность.
#16
(Правка: 13:30) 13:26, 13 фев. 2019

the trick
> Да можно использовать и инкременты, для инициализации брать отрицательные
> значения.

Можно всё когда ты пишешь асм код сам. Но наша задача, чтобы наш хитрый план понял компилятор. Если понимает, то почему бы и не отрицательные. А если ты пишешь кросс-платформенный кросс-компиляторный код, тебе надо, чтобы они все поняли тебя правильно.

#17
13:55, 13 фев. 2019

Truthfinder
> Можно всё когда ты пишешь асм код сам.
Ну да, этот код приведен если он будет в масме делать вставки.

Вообще в 2010 студии вот такой код:

void _add(char *dst, char const *src, int n){
  for(int i = -n; i; i += 16)
    *(__m128i*) (dst + n + i) = _mm_adds_epu8( *(__m128i*) (dst + n + i), *(__m128i*) (src + n + i));
}
Компилируется достаточно неплохо:
sub rdx,rcx
mov eax,10
nop dword ptr ds:[rax+rax]
@@:
movdqa xmm0,[rcx]
add rcx,10
dec rax
paddusb xmm0,[rdx+rcx-10]
movdqa [rcx-10],xmm0
jne @B
ret 

Код с декрементом:

void _add(char *dst, char const *src, int n)
{
  for(int i = n - 16; i; i -= 16)
    *(__m128i*) (dst + i) = _mm_adds_epu8( *(__m128i*) (dst + i), *(__m128i*) (src + i));
}
lea rax,[rcx+F0]
sub rdx,rcx
mov ecx,F
nop 
@@:
movdqa xmm0,[rax]
sub rax,10
dec rcx
paddusb xmm0,[rdx+rax+10]
movdqa [rax+10],xmm0
jne @B
ret 
Разницы особой нет, только направление.

#18
15:22, 13 фев. 2019

Truthfinder
Твой код:

extern "C" __declspec(dllexport) void __stdcall ADD_(int* src, int* dst, int w, int h, int ws, int wd) {
  for (int y = 0; y < h; y++, dst+=wd, src+=ws) {
    int *s = src, *d = dst;
    for (int x = 0; x < w; x++, s++, d++)
      *d = ADS_UB(*d, *s);
  }
  //return; вот это не надо писать
}
Я исправил так:
extern "C" __declspec(dllexport) void __stdcall ADD_(int* src, int* dst, int w, int h, int ws, int wd) 
{
  for (int y = 0; y < h; y++, dst += wd, src += ws) 
  {
    __m64 *s = (__m64*)src, *d = (__m64*)dst;
    for (int x = 0; x < w; x += 2, s++, d++)
      *d = _mm_adds_pu8(*d, *s);
  }
}
Так компилируется, но выдаёт варнинг "function 'ADD_' has no EMMS instruction". Это получается, что MMX таки есть в интринсиках?
Код запускается и работает, но через некоторое время крашится, видимо emms таки нужна. Как её выразить интринсиком? Что-то не нахожу её в тех списках.
#19
15:31, 13 фев. 2019

Mikle
> Я исправил так:

Ну это неправильно. У тебя mmx, потому что ты используешь _mm_adds_pu8. А раз mmx, значит требуется. Называется она _mm_empty().

(__m64*)ptr; То есть когда ты доходишь до последнего int в массиве, а регистр 64 бита, ты выйдешь операцией add за границы массива при чтении массива.

#20
15:36, 13 фев. 2019

Mikle

_mm_empty вставляешь туда, куда положена по правилам вставки emms при работе с mmx.
Сумму правильно писать как я писал выше.
Вот это

  • d = _mm_cvtsi128_si32(_mm_adds_epu8(_mm_cvtsi32_si128(*d), _mm_cvtsi32_si128(*s)));

  • переписываем как это
  • d = _mm_cvtsi64_si32(_mm_adds_pu8(_mm_cvtsi32_si64(*d), _mm_cvtsi32_si64(*s)));
  • Ещё одна твоя ошибка c (__m64*)ptr состоит в том, что ты уже сложил 2 int рядом стоящих, а потом икрементируешься на int и снова складываешь int который ты уже сложил.

    #21
    15:36, 13 фев. 2019

    Mikle
    Напомню: https://gamedev.ru/flame/forum/?id=218515 .
    Там, впрочем, код без особых объясненй.

    Советуемый }:+()___ [Smile] https://software.intel.com/sites/landingpage/IntrinsicsGuide - он скорее справочник.
    Чтобы именно краткое введение в SIMD - хз. Я обычно даю ссылку на http://softpixel.com/~cwright/programming/simd/index.php , но это тоже так себе, от безрыбья.

    > Кстати, какая минимально студия поддерживает интринсики?
    VC6 поддерживает, насколько я знаю. Может раньше.

    > Как её выразить интринсиком? Что-то не нахожу её в тех списках.
    _mm_empty().
    Тривиально гуглится же.
    Вообще, в https://www.felixcloutier.com/x86/index.html рядом с мнемониками интринсики подписаны.

    Другое дело, нафиг тебе вообще MMX, когда можно _mm_adds_epu8.

    #22
    (Правка: 15:39) 15:37, 13 фев. 2019

    А нет, пардон. Просмотрел. Там x+=2 у тебя. Данные выровнены на 8 байт?

    #23
    15:38, 13 фев. 2019

    FordPerfect
    > Другое дело, нафиг тебе вообще MMX, когда можно _mm_adds_epu8.

    Для понимания. Он же ещё только учится.

    #24
    (Правка: 15:44) 15:41, 13 фев. 2019

    FordPerfect
    > Другое дело, нафиг тебе вообще MMX, когда можно _mm_adds_epu8.
    Mikle

    Попробуй свою реализацию на MMX и мою на SSE. По идее должно быть сейчас у тебя быстрее. Если же можно через x+=4, то быстрее можно сделать уже через мою. А если можно +8, то можно через avx сделать. Для sse empty не нужен. Для AVX нужна _mm256_zeroupper().

    #25
    15:53, 13 фев. 2019

    Truthfinder
    > Данные выровнены на 8 байт
    Да, я проверил, что размеры чётные.
    FordPerfect
    > нафиг тебе вообще MMX, когда можно _mm_adds_epu8
    Я просто взял код из #4, не понимая, что это скомпилируется в MMX, сейчас попробую _mm_adds_epu8.

    #26
    15:58, 13 фев. 2019
    Truthfinder
    > Для AVX нужна _mm256_zeroupper().
    Она нужна несколько в другом смысле, чем _mm_empty().
    #27
    16:05, 13 фев. 2019

    Получилось на _mm_adds_epu8
    Truthfinder
    > Попробуй свою реализацию на MMX и мою на SSE. По идее должно быть сейчас у тебя быстрее.
    Нет, на SSE стало ещё на 5% быстрее, я ведь теперь по 4 пикселя за раз обрабатываю.

    Ещё такой вопрос: с выравниванием по ширине понятно, чтобы за край не выйти, а разве SSE не требует Align16 для данных? Сейчас я за этим не слежу, но, вроде, работает, может случайно попал?

    #28
    (Правка: 16:25) 16:13, 13 фев. 2019

    Mikle
    > Align16 для данных?
    Требует, но там есть отдельные операции которые работают с выровненной и не выровненной памятью, и это относиться только к операциям чтения записи. Скорее всего они у тебя подменились компилятором, надо диз-асм смотреть.

    Если ты хочешь этим вручную управлять то смотри на _mm_load/_mm_loadu .. соответственно.

    Mikle
    > с выравниванием по ширине понятно
    а я только конец выравниваю.

    #29
    16:15, 13 фев. 2019

    Mikle
    > разве SSE не требует Align16 для данных

    Смотри что у тебя в asm. movaps требует, movups нет. Какой у тебя проц?

    Страницы: 1 2 3 412 Следующая »
    ПрограммированиеФорумОбщее