Информация об изменениях

Сообщение Re[24]: C# - from indians by indians от 05.06.2015 12:40

Изменено 05.06.2015 12:45 Evgeny.Panasyuk

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

S>Не, можно заиспользовать RyuJIT+SIMD


От SIMD тут будет не так много эффекта, так как значительную часть времени здесь занимает перекачка данных из памяти. Точнее он будет, но не кратен увеличению max flop/s.
GCC кстати делает векторизацию C++ кода выше автоматом (опции компиляции):
.L94:
    vmovupd    (%rcx), %xmm3
    addq    $1, %r10
    addq    $64, %rcx
    addq    $64, %rdi
    vinsertf128    $0x1, -48(%rcx), %ymm3, %ymm1
    vmovupd    -32(%rcx), %xmm3
    vinsertf128    $0x1, -16(%rcx), %ymm3, %ymm3
    vmovupd    -64(%rdi), %xmm4
    vinsertf128    $1, %xmm3, %ymm1, %ymm0
    vperm2f128    $49, %ymm3, %ymm1, %ymm3
    vunpcklpd    %ymm3, %ymm0, %ymm2
    vunpckhpd    %ymm3, %ymm0, %ymm3
    vinsertf128    $0x1, -48(%rdi), %ymm4, %ymm0
    vmovupd    -32(%rdi), %xmm4
    vinsertf128    $0x1, -16(%rdi), %ymm4, %ymm4
    vinsertf128    $1, %xmm4, %ymm0, %ymm5
    vperm2f128    $49, %ymm4, %ymm0, %ymm4
    vunpcklpd    %ymm4, %ymm5, %ymm1
    vunpckhpd    %ymm4, %ymm5, %ymm4
    vmulpd    %ymm1, %ymm2, %ymm0
    vmulpd    %ymm4, %ymm3, %ymm5
    vmulpd    %ymm4, %ymm2, %ymm2
    vmulpd    %ymm1, %ymm3, %ymm1
    vsubpd    %ymm5, %ymm0, %ymm0
    vaddpd    %ymm1, %ymm2, %ymm1
    vinsertf128    $1, %xmm0, %ymm0, %ymm2
    vperm2f128    $49, %ymm0, %ymm0, %ymm0
    vinsertf128    $1, %xmm1, %ymm1, %ymm3
    vperm2f128    $49, %ymm1, %ymm1, %ymm1
    vshufpd    $12, %ymm3, %ymm2, %ymm2
    vshufpd    $12, %ymm1, %ymm0, %ymm0
    vmovups    %xmm2, -64(%rcx)
    vextractf128    $0x1, %ymm2, -48(%rcx)
    vmovups    %xmm0, -32(%rcx)
    vextractf128    $0x1, %ymm0, -16(%rcx)
    cmpq    %rsi, %r10
    jb    .L94


S>или распараллелить *(конкретно тут не поможет, время слишком мелкое)


Распараллеливание существенно помогает даже на Coliru.
Причём распараллеливается двумя строчками — добавлением #include <parallel/algorithm> и заменой std::transform на __gnu_parallel::transform (у него такая же сигнатура)

S>но это читерство и несерьёзно.


Пример же совершенно не про SIMD и Parallel. Как я уже говорил выше — отсутствие структур и лишние индерекци бьют далеко не только по интенсивным вычислениям, а практически по всему коду.

S>UPD2. Тот же код с классами вместо структур:

S>
S>.NET Elapsed: 4723,0000 ms
S>


Я об этом и говорил выше — разница может быть на порядки.

S>Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"


А тут не в GC, а в постоянных cache miss'ах. Если на C++ сделать такой же memory layout — то точно также получим тормоза (подобный пример
Автор: Evgeny.Panasyuk
Дата: 18.10.14
).
Re[24]: C# - from indians by indians
Здравствуйте, Sinix, Вы писали:

S>Не, можно заиспользовать RyuJIT+SIMD


От SIMD тут будет не так много эффекта, так как значительную часть времени здесь занимает перекачка данных из памяти. Точнее он будет, но не кратен увеличению max flop/s.
GCC кстати делает векторизацию C++ кода выше автоматом (опции компиляции):
  ASM
.L94:
    vmovupd    (%rcx), %xmm3
    addq    $1, %r10
    addq    $64, %rcx
    addq    $64, %rdi
    vinsertf128    $0x1, -48(%rcx), %ymm3, %ymm1
    vmovupd    -32(%rcx), %xmm3
    vinsertf128    $0x1, -16(%rcx), %ymm3, %ymm3
    vmovupd    -64(%rdi), %xmm4
    vinsertf128    $1, %xmm3, %ymm1, %ymm0
    vperm2f128    $49, %ymm3, %ymm1, %ymm3
    vunpcklpd    %ymm3, %ymm0, %ymm2
    vunpckhpd    %ymm3, %ymm0, %ymm3
    vinsertf128    $0x1, -48(%rdi), %ymm4, %ymm0
    vmovupd    -32(%rdi), %xmm4
    vinsertf128    $0x1, -16(%rdi), %ymm4, %ymm4
    vinsertf128    $1, %xmm4, %ymm0, %ymm5
    vperm2f128    $49, %ymm4, %ymm0, %ymm4
    vunpcklpd    %ymm4, %ymm5, %ymm1
    vunpckhpd    %ymm4, %ymm5, %ymm4
    vmulpd    %ymm1, %ymm2, %ymm0
    vmulpd    %ymm4, %ymm3, %ymm5
    vmulpd    %ymm4, %ymm2, %ymm2
    vmulpd    %ymm1, %ymm3, %ymm1
    vsubpd    %ymm5, %ymm0, %ymm0
    vaddpd    %ymm1, %ymm2, %ymm1
    vinsertf128    $1, %xmm0, %ymm0, %ymm2
    vperm2f128    $49, %ymm0, %ymm0, %ymm0
    vinsertf128    $1, %xmm1, %ymm1, %ymm3
    vperm2f128    $49, %ymm1, %ymm1, %ymm1
    vshufpd    $12, %ymm3, %ymm2, %ymm2
    vshufpd    $12, %ymm1, %ymm0, %ymm0
    vmovups    %xmm2, -64(%rcx)
    vextractf128    $0x1, %ymm2, -48(%rcx)
    vmovups    %xmm0, -32(%rcx)
    vextractf128    $0x1, %ymm0, -16(%rcx)
    cmpq    %rsi, %r10
    jb    .L94


S>или распараллелить *(конкретно тут не поможет, время слишком мелкое)


Распараллеливание существенно помогает даже на Coliru.
Причём распараллеливается двумя строчками — добавлением #include <parallel/algorithm> и заменой std::transform на __gnu_parallel::transform (у него такая же сигнатура)

S>но это читерство и несерьёзно.


Пример же совершенно не про SIMD и Parallel. Как я уже говорил выше — отсутствие структур и лишние индерекци бьют далеко не только по интенсивным вычислениям, а практически по всему коду.

S>UPD2. Тот же код с классами вместо структур:

S>
S>.NET Elapsed: 4723,0000 ms
S>


Я об этом и говорил выше — разница может быть на порядки.

S>Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"


А дело тут не в GC, а в постоянных cache miss'ах. Если на C++ сделать такой же memory layout — то точно также получим тормоза (подобный пример
Автор: Evgeny.Panasyuk
Дата: 18.10.14
).