2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 01:21 
Я запускаю компиляцию в режиме отладки, а как иначе увидеть код ассемблера?

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 02:16 
Mihaylo в сообщении #1437862 писал(а):
как иначе увидеть код ассемблера?
Использовать флаг -S.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 07:40 
Плохой пример, оба варианта внутреннего цикла
Используется синтаксис C++
for (int i = 0; i<N; i++) {
    *pnt1++ = !*pnt2++;//Вариант с указателями
    array1[i] = !array2[i];//Вариант с индексами
}
генерят ровно один и тот же код
Используется синтаксис ASM
        xor     eax, eax
.L2:
        movzx   edx, BYTE PTR array2[rax]
        add     rax, 1
        xor     edx, 1
        mov     BYTE PTR array1[rax-1], dl
        cmp     rax, N
        jne     .L2
Иногда заменяя movzx на mov dl, и оперируя байтами, но чаще именно как показано.
Правда я использовал статические массивы, чтобы не использовать malloc.
Внешний цикл кстати оптимизатором вообще выкидывается.
А gcc может даже и векторизовать цикл и использовать xmm регистры.

Т.е. разницы использовать указатели или индексы нет никакой. И именно поэтому пример плох.

-- 02.02.2020, 07:45 --

Надо было идти по массивам в разную сторону, тогда компилятор фиг бы обошёлся одним индексом. Или второй массив адресовать с переменным шагом.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 10:36 
Dmitriy40 в сообщении #1437872 писал(а):
Плохой пример, оба варианта внутреннего цикла.

Извините, не пояснил, что я исследовал немного иные (но важные для меня) нюансы компиляции.

Dmitriy40 в сообщении #1437872 писал(а):
Надо было идти по массивам в разную сторону, тогда компилятор фиг бы обошёлся одним индексом. Или второй массив адресовать с переменным шагом.

Да, еще arseniiv правильно сказал, что особенностью кода нейронных сетей является доступ к массиву с непроизвольным индексом (инкрементируемым индексом). Вы же говорили про доступ с произвольным индексом. Ок, чуть попозже сгенерирую простые обращения к массиву с произвольным индексом.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 20:45 
Не уверен, что то сказал я. :D Я в реализациях нейросетей разбираюсь ещё меньше, чем в их использовании вообще. Я там что-то общее выше наверно писал, но оно было выведено чисто из того, кто что успел написать до того, ну и каких-то эвристик из головы.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 18:18 
Аватара пользователя
Mihaylo в сообщении #1437862 писал(а):
а как иначе увидеть код ассемблера?

Если интересует простенькая функция, то удобно пользоваться https://godbolt.org/ - выбираете нужный компилятор, ключи компиляции и смотрите.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 18:58 
Отличная вещь, часто ей пользуюсь для примеров, но вот качество компиляции ... варианты MSVC генерят ужасный код, в разы больше нормального. А clang (выше ошибся, не gcc) часто компилит сильно сложнее код, зато более быстрый, например этот цикл выше векторизирует в xmm регистрах. Для себя выбрал лишь один приемлемый вариант, gcc (только не понял как его заставить компилить x86 вместо x64).

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 19:39 
Аватара пользователя
Dmitriy40 в сообщении #1438116 писал(а):
(только не понял как его заставить компилить x86 вместо x64)
Код:
-O3 -m32

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 22:22 
photon в сообщении #1438109 писал(а):
удобно пользоваться https://godbolt.org/ - выбираете нужный компилятор, ключи компиляции и смотрите.

Спасибо! Выбрал GCC 8.1, который вроде соответствует моему текущему MingW64.

Сравнил циклы с использованием for, while и if goto. Скомпилированные коды совершенно одинаковые, во всех сравниваемых случаях. Но только на уровне оптимизации O3.

Так что были правы люди:

tolstopuz в сообщении #1437860 писал(а):
Судя по всему, вы забыли включить оптимизацию.


-- 04.02.2020, 00:49 --

Что касается выноса if {} за пределы цикла, то с этим компилятор не справился похоже эффективно. Трудно сравнивать коды. Просто отследил по последним двум условным прыжкам jne LABEL.

 
 
 
 Re: Арифметика указателей vs индексация
Сообщение10.02.2020, 13:31 
С опцией gcc 9.2 -O3 -funroll-loops оператор __restrict немного меняет код.
gcc 8.1 выдаёт код чуть короче(с метками), тоже __restrict меняет код. Скорость - не знаю.
Используется синтаксис C++
void func(bool *pnt1, const bool *pnt2, const int N)
{
    for (int i = 0; i < N; i++)
    {
        *pnt1 = !*pnt2;
        pnt1++;
        pnt2++;
    }
}

код: [ скачать ] [ спрятать ]
Используется синтаксис ASM
func(bool*, bool const*, int):
        test    edx, edx
        jle     .L1
        xor     r9d, r9d
        lea     ecx, [rdx-1]
        and     edx, 7
        je      .L3
        cmp     rdx, 1
        je      .L26
        cmp     rdx, 2
        je      .L27
        cmp     rdx, 3
        je      .L28
        cmp     rdx, 4
        je      .L29
        cmp     rdx, 5
        je      .L30
        cmp     rdx, 6
        jne     .L41
.L31:
        movzx   edx, BYTE PTR [rsi+r9]
        xor     edx, 1
        mov     BYTE PTR [rdi+r9], dl
        add     r9, 1
.L30:
        movzx   r8d, BYTE PTR [rsi+r9]
        xor     r8d, 1
        mov     BYTE PTR [rdi+r9], r8b
        add     r9, 1
.L29:
        movzx   r10d, BYTE PTR [rsi+r9]
        xor     r10d, 1
        mov     BYTE PTR [rdi+r9], r10b
        add     r9, 1
.L28:
        movzx   r11d, BYTE PTR [rsi+r9]
        xor     r11d, 1
        mov     BYTE PTR [rdi+r9], r11b
        add     r9, 1
.L27:
        movzx   eax, BYTE PTR [rsi+r9]
        xor     eax, 1
        mov     BYTE PTR [rdi+r9], al
        add     r9, 1
.L26:
        movzx   edx, BYTE PTR [rsi+r9]
        mov     r8, r9
        xor     edx, 1
        mov     BYTE PTR [rdi+r9], dl
        add     r9, 1
        cmp     rcx, r8
        je      .L42
.L3:
        movzx   r10d, BYTE PTR [rsi+r9]
        xor     r10d, 1
        mov     BYTE PTR [rdi+r9], r10b
        movzx   r11d, BYTE PTR [rsi+1+r9]
        xor     r11d, 1
        mov     BYTE PTR [rdi+1+r9], r11b
        movzx   eax, BYTE PTR [rsi+2+r9]
        xor     eax, 1
        mov     BYTE PTR [rdi+2+r9], al
        movzx   edx, BYTE PTR [rsi+3+r9]
        lea     rax, [r9+7]
        xor     edx, 1
        mov     BYTE PTR [rdi+3+r9], dl
        movzx   r8d, BYTE PTR [rsi+4+r9]
        xor     r8d, 1
        mov     BYTE PTR [rdi+4+r9], r8b
        movzx   r10d, BYTE PTR [rsi+5+r9]
        xor     r10d, 1
        mov     BYTE PTR [rdi+5+r9], r10b
        movzx   r11d, BYTE PTR [rsi+6+r9]
        xor     r11d, 1
        mov     BYTE PTR [rdi+6+r9], r11b
        movzx   edx, BYTE PTR [rsi+7+r9]
        xor     edx, 1
        mov     BYTE PTR [rdi+7+r9], dl
        add     r9, 8
        cmp     rcx, rax
        jne     .L3
.L1:
        ret
.L41:
        movzx   eax, BYTE PTR [rsi]
        mov     r9d, 1
        xor     eax, 1
        mov     BYTE PTR [rdi], al
        jmp     .L31
.L42:
        ret


Используется синтаксис C++
void func(bool *__restrict pnt1, const bool *__restrict pnt2, const int N)
{
    for (int i = 0; i < N; i++)
    {
        *pnt1 = !*pnt2;
        pnt1++;
        pnt2++;
    }
}

код: [ скачать ] [ спрятать ]
Используется синтаксис ASM
func(bool*, bool const*, int):
        test    edx, edx
        jle     .L1
        xor     r9d, r9d
        lea     ecx, [rdx-1]
        and     edx, 7
        je      .L3
        cmp     rdx, 1
        je      .L26
        cmp     rdx, 2
        je      .L27
        cmp     rdx, 3
        je      .L28
        cmp     rdx, 4
        je      .L29
        cmp     rdx, 5
        je      .L30
        cmp     rdx, 6
        jne     .L41
.L31:
        movzx   edx, BYTE PTR [rsi+r9]
        xor     edx, 1
        mov     BYTE PTR [rdi+r9], dl
        add     r9, 1
.L30:
        movzx   r8d, BYTE PTR [rsi+r9]
        xor     r8d, 1
        mov     BYTE PTR [rdi+r9], r8b
        add     r9, 1
.L29:
        movzx   r10d, BYTE PTR [rsi+r9]
        xor     r10d, 1
        mov     BYTE PTR [rdi+r9], r10b
        add     r9, 1
.L28:
        movzx   r11d, BYTE PTR [rsi+r9]
        xor     r11d, 1
        mov     BYTE PTR [rdi+r9], r11b
        add     r9, 1
.L27:
        movzx   eax, BYTE PTR [rsi+r9]
        xor     eax, 1
        mov     BYTE PTR [rdi+r9], al
        add     r9, 1
.L26:
        movzx   edx, BYTE PTR [rsi+r9]
        mov     r8, r9
        xor     edx, 1
        mov     BYTE PTR [rdi+r9], dl
        add     r9, 1
        cmp     rcx, r8
        je      .L42
.L3:
        movzx   r10d, BYTE PTR [rsi+r9]
        movzx   r11d, BYTE PTR [rsi+1+r9]
        movzx   edx, BYTE PTR [rsi+3+r9]
        movzx   eax, BYTE PTR [rsi+2+r9]
        xor     r10d, 1
        xor     r11d, 1
        movzx   r8d, BYTE PTR [rsi+4+r9]
        xor     edx, 1
        mov     BYTE PTR [rdi+r9], r10b
        movzx   r10d, BYTE PTR [rsi+5+r9]
        xor     eax, 1
        mov     BYTE PTR [rdi+1+r9], r11b
        movzx   r11d, BYTE PTR [rsi+6+r9]
        xor     r8d, 1
        mov     BYTE PTR [rdi+3+r9], dl
        movzx   edx, BYTE PTR [rsi+7+r9]
        xor     r10d, 1
        mov     BYTE PTR [rdi+2+r9], al
        xor     r11d, 1
        lea     rax, [r9+7]
        xor     edx, 1
        mov     BYTE PTR [rdi+4+r9], r8b
        mov     BYTE PTR [rdi+5+r9], r10b
        mov     BYTE PTR [rdi+6+r9], r11b
        mov     BYTE PTR [rdi+7+r9], dl
        add     r9, 8
        cmp     rcx, rax
        jne     .L3
.L1:
        ret
.L41:
        movzx   eax, BYTE PTR [rsi]
        mov     r9d, 1
        xor     eax, 1
        mov     BYTE PTR [rdi], al
        jmp     .L31
.L42:
        ret

Если условия завершения цикла сложные, то можно вручную разворачивать циклы, вставив внутрь фиксированный цикл от 0 до 31, например, и добавив необходимые фиктивные элементы в массивах. Ветвления тормозят (на моём core2 duo по крайней мере).
А если так важна скорость, то можно под конкретный процессор написать.

-- 10.02.2020, 14:33 --

А может сейчас простые циклы процессор уже разворачивает, раз O3 не разворачивает по умолчанию, странно.

 
 
 [ Сообщений: 40 ]  На страницу Пред.  1, 2, 3


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group