2014 dxdy logo

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

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




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


12/07/15
3355
г. Чехов
Я запускаю компиляцию в режиме отладки, а как иначе увидеть код ассемблера?

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 02:16 
Заслуженный участник


02/08/11
7014
Mihaylo в сообщении #1437862 писал(а):
как иначе увидеть код ассемблера?
Использовать флаг -S.

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 07:40 
Заслуженный участник


20/08/14
11867
Россия, Москва
Плохой пример, оба варианта внутреннего цикла
Используется синтаксис 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 


12/07/15
3355
г. Чехов
Dmitriy40 в сообщении #1437872 писал(а):
Плохой пример, оба варианта внутреннего цикла.

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

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

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

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение02.02.2020, 20:45 
Заслуженный участник


27/04/09
28128
Не уверен, что то сказал я. :D Я в реализациях нейросетей разбираюсь ещё меньше, чем в их использовании вообще. Я там что-то общее выше наверно писал, но оно было выведено чисто из того, кто что успел написать до того, ну и каких-то эвристик из головы.

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 18:18 
Экс-модератор
Аватара пользователя


23/12/05
12065
Mihaylo в сообщении #1437862 писал(а):
а как иначе увидеть код ассемблера?

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

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 18:58 
Заслуженный участник


20/08/14
11867
Россия, Москва
Отличная вещь, часто ей пользуюсь для примеров, но вот качество компиляции ... варианты MSVC генерят ужасный код, в разы больше нормального. А clang (выше ошибся, не gcc) часто компилит сильно сложнее код, зато более быстрый, например этот цикл выше векторизирует в xmm регистрах. Для себя выбрал лишь один приемлемый вариант, gcc (только не понял как его заставить компилить x86 вместо x64).

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 19:39 
Экс-модератор
Аватара пользователя


23/12/05
12065
Dmitriy40 в сообщении #1438116 писал(а):
(только не понял как его заставить компилить x86 вместо x64)
Код:
-O3 -m32

 Профиль  
                  
 
 Re: Арифметика указателей vs индексация
Сообщение03.02.2020, 22:22 


12/07/15
3355
г. Чехов
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 


16/04/19
161
С опцией 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

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group