Оптимизация, C++, Asm

kentavr

Может ли такое выражение изменить значение флага CF?
for(int i=0;i<10;i++)
{
// что-то вроде __asm rcl tralala[i],1
// ....
}

kentavr

прошу прощения за не точность имелось ввиду только голый for
for(int i=0;i<10;i++)
{
}
по мне не должен, но вот не могу быть уверен на все 100% при каких условиях что компилятор с генерирует

zzzzzzzzzzz

О да, отличный вопрос по С++

kentavr

не очень понял что вы имели виду,
а вы бы это к какой категории отнесли?

ppplva

В стандарте не сказано обратного, значит может.

mira-bella

Может ли такое выражение изменить значение флага CF?
for(int i=0;i<10;i++)
{
}
цикл не есть выражение
ответ: разумеется может (ибо как справедливо заметил : в стандарте не сказано обратного и вообще там ничего не сказано про регистры - значит любой из регистров может изменится).
А в данном случае на x86 платформе флаг CF не только может, а с очень большой вероятностью изменится на 0 по окончании цикла (вследствие операции сравнения с 10) и скорее всего CF=1 в начале тела цикла (хотя все это разумеется зависит от реализации: оптимизатор может такой простой цикл раскрутить, а этот пустой цикл вовсе удалить). Но к языку C++ это уже не имеет отношения, а только к конкретной его реализации.

kentavr

(например вследствие операции сравнения с 10)
правильно, забыл что cmp и sub, меняют значение флага CF по которому и определяет прыгать или нет.
Буду стараться избегать такого.
Заметил, что компилятор VC++2003 почему то любит именно команду sub
но вот тут есть один момент
for(int i=0;i<repCount;i++)
{
__asm rcl tralala[i],1
}
где repCount является константой и не большой величиной
в таком случае оптимизатор может в место повторного использования одного rcl вызвать их последовательно, что значительно повысит скорость
__asm rcl tralala[0],1
__asm rcl tralala[1],1
__asm rcl tralala[2],1
....
в таком случае заработает по задуманному
или может я ошибаюсь?
а вообще стоит такие трюки делать?

mira-bella

отредактировал предыдущий пост еще не прочитав ваш ответ
но вот тут есть один момент
for(int i=0;i<repCount;i++)
{
__asm rcl tralala[i],1
}
где repCount является константой и не большой величиной
в таком случае оптимизатор может в место повторного использования одного rcl вызвать их последовательно, что значительно повысит скорость
__asm rcl tralala[0],1
__asm rcl tralala[1],1
__asm rcl tralala[2],1
....
да раскруткой цикла (loop unrolling) называется
в таком случае заработает по задуманному
или может я ошибаюсь?
а вообще стоит такие трюки делать?
конечно не стоит
сказать, что это не портируемо - это будет очень мягко сказано: даже от опций одного и того же компилятора будет зависеть заработает или не заработает.

ppplva

Да и от repCount тоже

kentavr

понятно, спасибо
отредактировал предыдущий пост еще не прочитав ваш ответ
а мне показалось, что я ваше сообщение не внимательно прочитал посмотрев его второй раз
Я реализую всякие криптоалгоритмы, знаете как там важна скорость, всё время с битами работаю.
На голом ассемблере ничего писать не люблю =(
Пытаюсь создать один общий шаблон класс Register там надо всякие сдвиги делать... Универсальные ясные, надёжные алгоритмы которые и асму не требует, работающие с регистром любой длины мягко говоря не очень эффективны.
Хочу умудриться сделать так чтоб для регистра любой длины генерировал максимально эффективный код.
Всякие макросы использую... всякие трюки пытаюсь делать.
Не очень получается.
Видимо для каждого отдельного случая буду писать отдельный код для макс скорости с использованием асмы без for-ов =(

kokoc88

Мне кажется, что в наши дни использование ассемблера вместо Си во многих задачах даёт выигрыш дай бог в 2-10%, при условии хорошо написанного кода. Зато код на Си будет иметь меньше ошибок и будет более понятным.

Dasar

Вместо использования asm-а лучше найди либу, которая сама умеет раскладывать ряд операций на использование SSE, 3DNow и т.д.
Также стоит поддержать hyperthreading.
и то, и другое - тебе может дать выигрыш в разы, при использование asm-а (как правильно заметил ) ты скорее всего выиграешь только ~10%

Olenenok

Нет, он проиграет 30%. Компилятор встретив __asm в функции не оптимизирует эту функцию.

kentavr

гадать не стоит я просто сделаю сравнение и о результатах вам скажу

mira-bella

Все верно: хорошо написанный ассемблерный код будет иметь производительность примерно на 10%-20% больше чем хорошо написанный C код, откомпилированный хорошим компилятором (именно C, а не C++ -- хороших компиляторов C++ пока не существует но C код - это портируемость. Лично я предпочитаю писать и тот и другой код (и ассемблерный еще в двух вариантах: в стиле GCC и в стиле MSVC).
Разумеется не забывай, что компилятор может изменить любые регистры между ассемблерными блоками, так что очень часто придется помещать большую часть кода в один __asm блок. Короче MSDN все расскажет.

kokoc88

На очень маленьких задачах с этим ещё можно согласиться. (Хотя я всё ещё встречаю программистов, которые не умеют быстро копировать блоки памяти на ассемблере.) Большая задача с ассемблерными вставками скорее всего выродится в в нечитабельную программу, которую очень трудно поддерживать, модифицировать и исправлять.

Olenenok

Его писать две недели, а потом ещё три недели оптимизировать со справочником в зубах, переставляя команды так и эдак.

mira-bella

Большая задача с ассемблерными вставками скорее всего выродится в в нечитабельную программу, которую очень трудно поддерживать, модифицировать и исправлять.
только если писать через ж...
простите мой французский

bastii

Есть же тулы специальные. Разве под современный проц реально в уме представлять как поток команд в проце выполняется?

mira-bella

Его писать две недели, а потом ещё три недели оптимизировать со справочником в зубах, переставляя команды так и эдак.
нафиг это надо команды переставлять так и эдак? Все равно для всех нынешних и будущих процов не оптимайзнешь идеальным образом, и ИМХО практики минимизации количества доступов к памяти, инструкций и используемых регистров (в таком порядке приоритета) вполне достаточно (ну еще плюс избегание использования сложных команд как интел завещал чтобы достаточно большой ассемблерный блок работал близко к идеалу, но могу и ошибаться.

natucia94

во многих задачах даёт выигрыш дай бог в 2-10%,
у меня не тот случай
в C++ насколько я знаю существуют всего на всего 2 оператора для сдвига регистров >>,<<. Этого мне мало, чтоб этими 2 операторами мне добиться желаемого я должен всякие битовые маски использовать... что требует множество дополнительных тактов, мне нужен rcl,rcr,shl,shr,jc,jnc чтоб я мог построить нечто намного быстрое, ключ к хорошему резултату будет не то что я просто возьму и перепишу из C в Асму и мучаясь добъюсь результата 5-10% делая то что оптимизатор делает, а именно используя rcl,rcr... чего в C насколько я знаю нет, что и вообще изменит алгоритм.

natucia94

Нет, он проиграет 30%. Компилятор встретив __asm в функции не оптимизирует эту функцию.
даже если она объявлена как inline?
поясните пожалуйста, очень интересно узнать почему.

stm7583298

Кстати, ко-нибудь проверял, к какому виду C-компилеры приводят вот такую операцию? И существует ли компилятор, который свернет это по-человечески?

a=b<<(32-s)|b>>s;

natucia94

никогда в жизни подобные закрученные штучки не писал, чтобы не сомневаться в чём либо

Dasar

> нужен rcl,rcr,shl,shr,jc,jnc чтоб я мог построить нечто намного быстрое
И в чем проблема найти библиотечку, которая делает это за тебя, используя для этого - все возможности процессора?

stm7583298

Я не сомневаюсь в правильности работы этого кода, мне интересно, сворачивает ли это компилятор в нормальный человеческий rol или ror

natucia94

хмм меня тоже заинтересовало, сейчас проверим

natucia94


int a = 0x1;
int b = 0x2;
int s = 0x4;
void main
{
a=b<<(32-s)|b>>s;
}

результат в режиме release

00401000 mov edx,dword ptr [s (407038h)]
00401006 mov eax,dword ptr [b (407034h)]
0040100B push esi
0040100C mov ecx,20h
00401011 mov esi,eax
00401013 sub ecx,edx
00401015 shl esi,cl
00401017 mov ecx,edx
00401019 sar eax,cl
0040101B or esi,eax
0040101D mov dword ptr [a (407030h)],esi
00401023 xor eax,eax
00401025 pop esi
00401026 ret

stm7583298

Что-то в этом духе я и предполагал. А чем компилял?

natucia94

Ms. Visual C++ 7 2003 .NET

Olenenok

Инлайн тоже не оптимизирует, сам с этим разок столкнулся. Нужно было сначала умножить и могло получится число большее 0xffffffff, а потом взять остаток от деления. Чтобы не гемороится решил написать на асме и от этого скорость кода упала в 8 раз по сравнению с хитрожопным выриантом вычисления остатка. Код кроме вычисления остатка оставался тем же самым.

stm7583298

Попробовал сделать на gcc:

int a=123;
int s=7;
int b;
int main
{
b=a<<s|a>>(32-s);
}

Собирал с -O3. Пробовал без оптимизации - примерно так же получается.

push ebp
mov ebp , esp
push ebx
push eax
mov ebx , 0x80493E0
mov eax , 0x080493DC
mov cl , bl
mov edx , eax
shl edx , cl
mov ecx , 0x20
sub ecx , ebx
sar eax , cl
or edx , eax
and esp , 0xF0
mov 0x80494DC , edx
mov ebx , [ebp-0x04]
leave
ret

korsar0156

встретив asm в функции все известные мне компиляторы C++ забивают на inline.

mira-bella

во многих задачах даёт выигрыш дай бог в 2-10%,
у меня не тот случай
в C++ насколько я знаю существуют всего на всего 2 оператора для сдвига регистров >>,<<. Этого мне мало, чтоб этими 2 операторами мне добиться желаемого я должен всякие битовые маски использовать... что требует множество дополнительных тактов, мне нужен rcl,rcr,shl,shr,jc,jnc чтоб я мог построить нечто намного быстрое, ключ к хорошему резултату будет не то что я просто возьму и перепишу из C в Асму и мучаясь добъюсь результата 5-10% делая то что оптимизатор делает, а именно используя rcl,rcr... чего в C насколько я знаю нет, что и вообще изменит алгоритм.
с чего вы взяли, что у вас не тот случай? Как измерите время выполнения так и сможете сказать какой у вас случай.
Не уж то в вашем криптографическом алгоритме нет ничего кроме ролов?
Даже если там несколько раз встречаются ролы, и проверки сдвинутого за границу числа бита, все равно несмотря на кучу лишних инструкций хороший C алгоритм (откомпиленый хорошим C компилятором - не C++) обычно работает примерно на 5-20% хуже хорошего ассемблерного кода (а для задач "удобных" для реализации на C к которым ваша не относится может даже на какой-то процентик лучше, если не заморачиваться очень тщательно над оптимизацией ассемблерного кода).
Это проверенный факт, а не пустые предположения. Я лично впрочем ради этих 5-20% все равно стараюсь, но C версия почти обязательна все равно (потому, что это портируемый код не ограниченный виндой и x86 архитектурой).
Известные мне хорошие компиляторы на которые я ссылаюсь - это GCC-2.95.3, GCC-4.0, Intel C Compiler (который легко встраивается в VS, являясь лучшей альтернативой MSVC).
Правда восьмой интеловский компилятор с ассемблерными вставками глючит (компилит глючный код но без ассемблера его оптимизатор на высоте (а с ассемблером оптимизатор не важен, поэтому достаточно и MSVC).

mira-bella

gcc --version
?
что-то меня этот leave настораживает (хоть это и оффтоп)
а то, что до рола не оптимайзят ничего удивительного - тупые все компиляторы.

Olenenok

Послушай, тебе ведь и примеры приводили, что нынешние микрософтовские компиляторы оптимизируют лучше чем gcc. У меня был крайний случай - математика, чистая скорость. Картина вышла такая:
1) MSVC - оптимизация по скорости, GCC -O3. VC выигрывает > 15%
2) MSVC тот же, GCC -O3 -unroll-loops. VC выигрывает ~3%
3) MSVC отрубаем отладочную информацию, GCC тот же. VC выигрывает ~4%
4) MSVC тот же, GCC -O3 -unroll-loops -march=athlon-xp. GCC выигрывает ~1%
Но! Это под консолью, в gnome GCC выигрывает ~0.5%, в kde паритет, при том что в виндах висят антивиры, файрволы и т.п. + нет оптимизации под AXP.

mira-bella

Послушай, тебе ведь и примеры приводили, что нынешние микрософтовские компиляторы оптимизируют лучше чем gcc. У меня был крайний случай - математика, чистая скорость. Картина вышла такая:
1) MSVC - оптимизация по скорости, GCC -O3. VC выигрывает > 15%
2) MSVC тот же, GCC -O3 -unroll-loops. VC выигрывает ~3%
3) MSVC отрубаем отладочную информацию, GCC тот же. VC выигрывает ~4%
4) MSVC тот же, GCC -O3 -unroll-loops -march=athlon-xp. GCC выигрывает ~1%
Но! Это под консолью, в gnome GCC выигрывает ~0.5%, в kde паритет, при том что в виндах висят антивиры, файрволы и т.п. + нет оптимизации под AXP.
Во-первых до этого мне никто никаких примеров не приводил, а только делали пустые заявления в духе "GCC оптимизирует хуже чем MSVC" не удосуживаясь даже версию того и другого привести (на пример с "switch" я отвечал детально). Я при этом спрашивал версии, все молчали.
Во-вторых: Как это вообще возможно сравнивать производительности программ, работающих в разных ОС под неизвестным окружением и приводить потом это в качестве аргумента о качественности оптимизации? Вам не пришло в голову откомпилить консольную прогу при помощи GCC под винду и сравнивать с компиляцией той же проги при помощи MSVC отрубив предварительно всё лишнее и выставив этим прогам максимальный приоритет? Мне вот пришло.
В третьих: Когда вы приводите такую статистику, необходимо писать ВЕРСИИ всех компиляторов. Например разные версии GCC очень отличаются по качеству оптимизации. Неужели не ясно что надо версии писать? (опции вы написали, что не может не радовать, первый из тех кто делал подобные заявления)
Я просто констатирую, что MSVC6 сосет по оптимизации у GCC-2.95.3 или GCC-4.0 или GCC-3.4.
Я это проверял на двух разных задачах (консольными приложениями в текстовом, а не оконном режиме которые очень требовательны к ресурсам проца (тоже чистые вычисления: в одном из сравнений арифметика длинных чисел, в другом - блочное шифрование в одинаковом окружении под виндой с Realtime приоритетом под админом и с отрубленой сеткой.
Про MSVC7/8 я ничего не говорил вообще, насчет них еще проверю.

mira-bella

PS: в GCC еще полезно иногда добавлять опцию -fomit-frame-pointer (это иногда может дать, существенное преимущество, а может и наоборот).

stm7583298

gcc --version
gcc 3.2.2

sergey_m

Послушай, тебе ведь и примеры приводили, что нынешние микрософтовские компиляторы оптимизируют лучше чем gcc. У меня был крайний случай - математика, чистая скорость.
А твоя программа не использовала математическую библиотеку?

Olenenok

Этож учебная. Использовала только math.h, ничем другим пользоваться нельзя.

sergey_m

> Этож учебная. Использовала только math.h, ничем другим пользоваться нельзя.
Нужно подробно объяснять, что ты протестировал не компиляторы?

Dasar

> Я просто констатирую, что MSVC6 сосет по оптимизации у GCC-2.95.3 или GCC-4.0 или GCC-3.4.
странно, если бы было обратное
ms vc6 - уже лет 10 как на днях будет.

evgen5555

ms vc6 - уже лет 10 как на днях будет.
Зато он стабильнее, чем MSVC7

Dasar

> Зато он стабильнее, чем MSVC7
не замечал
скорее - наоборот, у MSVC 6 - компилятор постоянно дохнет на сложном C++.
но я с появлением 7-ой версии отошел от активного использования плюсов

Olenenok

Объясняй, я весь внимание

sergey_m

Приложения собранные MS VC и gcc с GNU окружением используют различные математические библиотеки. Объявления из math.h - это не часть языка, а хидеры этой самой библиотеки.

bleyman

А что, для компиляции выражения j = i + 1 или for(int i = 0; i < n; i++) result += a[i] * b[i] используются математические библиотеки?

bleyman

Или в math.h есть существенно более интересные вещи, чем "#define Max(a, b) a)>(b?(a):(b" ?

artimon

Эээ, тригонометрия всяческая?

bleyman

Разве что.

mira-bella

Или в math.h есть существенно более интересные вещи, чем "#define Max(a, b) a)>(b?(a):(b" ?
да, там все существенно более интересно, особенно согласно стандарту C99
А такого макроса как ты написал там в принципе быть не может, поскольку он не безопасен для использования. Надеюсь не надо объяснять почему.

bleyman

Ну, если a и b без сайд эффектов, то макрос вполне безопасный.

mira-bella

Ну, если a и b без сайд эффектов, то макрос вполне безопасный.
разумеется, но любая функция стандартной библиотеки конечно же не может делать предположений относительно того есть ли у параметров side effects, за исключением assert (что в стандарте особо оговорено).
Т.е. любая функция кроме assert должна себя вести как функция (т.е. возможность side effects должна быть учтена хотя некоторые из них допустимо реализовать как макрос.

sergey_m

> А что, для компиляции выражения j = i + 1 или for(int i = 0; i < n; i++) result += a[i] * b[i] используются математические библиотеки?
Читай тред внимательнее.

sergey_m

> Или в math.h есть существенно более интересные вещи, чем "#define Max(a, b) a)>(b?(a):(b" ?
Читай math.h

Olenenok

Я из math.h использовал толькл sqrt и общее время исполнения этого sqrt заняло не более 0.01сек. из 32

rosali

использовал только sqrt
Тем более что sqrt компилируется в одну ассемблерную инструкцию, а если компилятор этого не может, то нечего пинять на math.h Кстати я склонен считать math.h и прочие библиотеки частью компилятора, особенно если речь идето сравнении производительности компиляторов.

rosali

тригонометрия всяческая?
Большинство тригономестрических функций тоже компилируются в одну ассемблерную инструкцию.

sergey_m

Тем более что sqrt компилируется в одну ассемблерную инструкцию, а если компилятор этого не может, то нечего пинять на math.h Кстати я склонен считать math.h и прочие библиотеки частью компилятора, особенно если речь идето сравнении производительности компиляторов.
Вот человек тебе скажет, что использовал gcc. О какой математической библиотеке ты подумаешь?
Оставить комментарий
Имя или ник:
Комментарий: