[Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 30.03.07 20:34
Оценка: 185 (32) -1

Exceptions vs. Return Values

Провёл на досуге исследование на тему сообщение об ошибках с помощью исключений против сообщения об ошибках с помощью возвращаемых значений с т.з. скорости выполнения кода и кодогенерации. Возможно кому-то ещё будет интересно.

Цель можно охарактеризовать примерно так: исследовать скорость работы некоторых ключевых паттернов кода, реализованных с применением исключений для сообщения об ошибках, или с помощью возвращаемых значений.

Простой случай

Что б не было скучно сразу начну с некоторых результатов.

rv (success) rv (fail) ex (success) ex (w/o try) ex (fail)
msvc71128 4 4 66928
msvc81284 417140
gcc411220 8 850476
gcc3241031267444
Сейчас поясню, что что значит.
rv (success) вызов функции, которая сообщает об ошибке с помощью возвращаемого значения (rv – return value). Функция возвращает значение, что ошибки не произошло – реально возвращается bool true. После вызова происходит проверка возвращаемого значения. Сама функция никакой работы не делает, т.е. пустая
rv (fail) аналогично предыдущему, только функция возвращает неудачу — false
ex (success) функция сообщает об ошибке с помощью исключения (ex — exception), соответственно её вызов обрамлён в try/catch. Функция исключение не кидает
ex (w/o try) аналогично предыдущему, только вызов функции не обрамлён в try/catch — что бы увидеть влияние входа/выхода в try блок
ex (fail) ex (success), только функция кидает исключение
msvc71 WinXP on Pentium4, msvc7.1
msvc8 WinXP on Pentium4, msvc8sp1
gcc41 MinGW on Pentium4, gcc4.1.1
gcc32 Linux2.4 on Pentium4, gcc3.2.3
Компилировал со всеми оптимизациями, при этом следил, чтобы исследуемые функции _не_ встраивались. Время замерял с помощью rdtsc, соответственно результаты приведены в тактах процессора. Каждый тест запускал 1000 раз, потом находил минимальный результат.
Сразу оговорюсь, что на полную объективность не претендую. Какие результаты получил в своих конкретных условиях, при определённых настройках компилятора и т.д., такие и привожу. Но тем не менее, уверен, что основные тенденции уловлены правильно. Тем более сгенерированный код во всех случаях изучался на правдоподобность.

Выводы

Выводы для такого тривиального случая с простыми функциями.

Исключения быстрее, когда реально исключения не кидаются. За счёт чего? За счёт дополнительных инструкций на проверку возвращаемого значения, и на переход (jmp).

Вход/выход в try блок [как ни странно] не влияет на производительность.

Кидание исключения очень дорого. Порядка 20мкс под Win/msvc71 и порядка 100мкс под Linux (почему так долго под Linux не знаю). А под msvc8 ухитрились сделать за 7мкс, хотя они всё равно реализованы поверх SEH.

Более интересный случай

В первом случае у исключений было небольшое приемущество, точнее немного неадекватный случай, т.к. программа не выделяла никаких ресурсов. Когда выделяются ресурсы для исключений начинается самое интересное, т.к. приходится помещать фреймы на стек, следить за созданием объектов и т.д. Теперь замерим скорость с ресурсами. Сразу поясню, что я подразумеваю под ресурсами. В условиях исключений под ресурсом подразумеваю объект класса с нетривиальным деструктором (в котором происходит освобождение ресурса) и с конструктором (который выделяет ресурс, при этом может провалиться и кинуть исключение). В условиях возвращаемых значений я рассмотрел 2 варианта. Первый – в стиле С++ — класс, в деструкторе также освобождает ресурс, а конструктор заменил на функцию bool init(), которая выделяет ресурс и сообщает о успешности. Второй вариант – в стиле С – ресурс представляет из себя некий int, и 2 функции int constructor(int*) и void destructor(int). Все функции выделения/освобождения ресурса сами по себе ничего не делают, кроме как вызываются.

Функции тестировал те же, только отличие в том, что функция в начале работы «выделяет» ресурс, потом «освобождает» ресурс и возвращается. Соответственно в присутствии исключений, т.к. у локального объекта есть деструктор, компилятору приходится создавать фреймы на стеке и т.д. Замерял только в «успешном» случае, т.к. если будет кидаться исключение, то уже понятно, что это будет настолько долго, что и сравнивать нечего.
Собственно результаты:
с с++/rvс++/ex
msvc71 242424
msvc8 242420
gcc41328884
gcc32263222
Для большей правдоподобности и интриги код в стиле С компилировал именно как С код, а не С++, соотв. пользовался не g++, а gcc.

Выводы

Выводы для случая с функциями с выделением ресурса.
Под msvc71 всё ровненько – даже не интерсно. Т.е. накладные расходы на проверки возвращаемых значений скомпенсировались накладными расходами на поддержку исключений.
gcc4.1.1 под mingw как-то совсем неадекватно себя ведёт при необходимости освобождать ресурсы... (почему так не знаю)
gcc3.2.2 под Linux – результаты примерно одинаковые. Только в С++ при использовании возвращаемых значений накладываются сразу 2 типа накладных расходов, поэтому получается значительно дольше.

Поведение в асимптотике

Теперь следующий тест. Очень много функций и очень много ресурсов. Чтобы поглядеть как ведёт себя производительность в асимптотике.
Функции такого вида:
F6()
{
повторить 6 раз // в коде это записано не в виде цикла, а развёрнуто
{
выделяем 6 ресурсов
вызываем F5();
}
}
Соответственно функция F5 аналогичная, только вызывает F4, и так далее. F0 – ничего не делает – сразу возвращается.
В С варианте это было записано примерно так:
int f6()
{
    int o1, o2;
    int res = 0;
    if (!constructor(&o1)) goto end;
    if (!constructor(&o2)) goto do1;
    if (!f5()) goto do2;
    res = 1;
    do2:    destructor(o2);
    do1:    destructor(o1);
    end:    return res;        
}

только экстраполировано на выделение 6 ресурсов и это всё повторяется 6 раз.
В варианте с++/rv:
bool f6()
{
    obj o1, o2;
    if (!o1.init()) return false;
    if (!o2.init()) return false;
    if (!f5()) return false;
    return true;
}

В варианте с++/ex:
bool f6()
{
    obj o1, o2;
    f5();
}


Результаты:
с с++/rvс++/ex
msvc71 636300462310606182104
msvc8 6361992 6258460 6181740
gcc41 9016944 9760084 9385664
gcc32 8510423 6640676 5545090

Выводы

Ну что тут можно сказать. В принципе код с исключениями немного быстрее, но совсем немного (но это уже приятно ). Единственное он медленнее на gcc41, но вообще как-то совсем неадекватно сгенерировал код...

Ещё тест


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

Размер кода


Так же есть ещё один аспект, влияющий на производительность, но который ускользает при таких замерах – размер сгенерированного кода. Чем больше кода – тем больше промахов кэша и переходов через границы страницы памяти – это может достаточно сильно влиять на производительность. Соответственно я замерил размер кода для одной функции типа f6(), которые я приводил выше. Результаты:
с с++/rvс++/ex
instr 386 442 232
size 1320 2359 1329
Замерял на msvc71. instr – кол-во ассемблерных команд. Size – размер функции в байтах.

У исключений значительно меньше инструкций, тем не менее размер кода равен размеру кода на С с возвращаемыми значениями. Как ни странно... Связано с тем, что команды там больше по размеру. Код на С++ с возвращаемыми значениями тут сильно проигрывает – так там инструкции и на проверки возвращаемых значений и на поддержку исключений.

Тест без ресурсов


Так же провёл следующий тест. Функции аналогичные предыдущим, но не выделяются ресурсы – просто идёт много форвардов на другие функции, а те на другие и т.д.


с с++/rvс++/ex
msvc71 970404 746460 653144
msvc8 970404 746464 653144
gcc41 858432 858444 765124
gcc32 705457 633707 521712
Размер кода:
с с++/rvс++/ex
instr 22 21 6
size 59 58 25

Выводы

Тут картина уже интереснее – исключения значительно вырываются вперёд. На msvc на 50% (!) на gcc на 35% (!). По размеру код на 136% (!).
Тут можно сделать важный вывод – если есть функции, в которых нет локальных переменных/аргументов с нетривиальными деструкторами – при использовании исключений они будут работать до 50% быстрее и размер кода будет меньше до 136%.

smart_ptr vs. smart_ptr&

Попутно я исследовал следующий вопрос – имеет ли смысл передавать умные указатели по ссылке вместо передачи по значению. Мы зачастую (ну я по-крайней мере ) передаю просто boost::shared_ptr без ссылок – по значению.
Функции аналогичные функциям из предыдущего теста – просто много форвардинга вызовов функций, без выделения ресурсов, но при этом между функцими передавался один boost::intrusive_ptr, в одном случае по значению, в другом по ссылке.


boost::intrusive_ptr boost::intrusive_ptr
msvc71 2226100 746492
msvc8 2237212 746492
gcc41 3153288 783844
gcc32 2301066 550930
Размер кода:
boost::intrusive_ptr boost::intrusive_ptr
instr 76 17
size 231 45

Выводы

Разница поразительная. При передаче по ссылке скорость выросла в 4.18 раза, размер кода уменьшился в 5.13 раза. Накладные расходы идут не только на увеличения/уменьшения счётчика, но так же на поддержание фрейма на стеке, и на контроль конструирования объектов – что бы знать какие рушить при исключении.

Более реалистичный тест

Более реалистичный тест по количеству ресурсов и вызовов функций. С исключениями тестовые функции выглядят так:
void f6()
{
  obj o1, o2, o3;
  f5();
  f5();
}

f5() выглядит аналогично, только вызывает f4() и т.д. f0 ничего не делает. Код с возвращаемыми значениями аналогичный, только... переписан соответственно с возвращаемыми значениями. Получается 64 вызова самой вложенной функции и примерно 200 объектов с деструкторами на тест, что более менее сравнимо с некой функциональностью в современной программе.
Смотрим, что получилось:


с с++/rvс++/ex
msvc71 4772 4804 4652
msvc8 4768 4792 4704
gcc41 7604 9924 8924
gcc32 5510 5127 4451
Тут получается, что исключения чуточку впереди (не считая gcc41 под mingw, который опять неадекватно сгенерировал код).

Далее сделал следующее – из 100 вызовов функции 1 проваливается (кидается исключение, или возвращается код возврата с ошибкой), и я беру не менимальное из всех замеров время, а усредняю по всем 100 замерам. Т.о. эмулируется ситуация, что в программе иногда происходит ошибка.
Смотрим, что получилось:


с с++/rvс++/ex
msvc71 4816 5195 4946
msvc8 4813 5384 4843
gcc41 7682 10059 9276
gcc32 5976 5135 7505
Тут уже видно, что исключения и возвращаемые значения практически сравнялись – где-то уже немного отстали, где-то уже почти отстали. Соответственно, если увеличивать процент провалов, то исключения уже начнут существенно отставать.

Выводы

Общие выводы какие возникли – возвращаемые значения типа писсимистической стратегии – т.е. чуть что сделали сразу проверяем, а не плохо ли всё, исключения – оптимистическая стратегия – делаем всё подряд без разбора и проверок, авось всё хорошо.
В принципе возникает такое ощущение, что исключения всё-таки немного быстрее (если не происходит ошибок). Соответственно если для какой-то функции вероятность провала более 1%, то надо использовать коды возврата, если менее 1%, то надо использовать исключения для повышения производительности. Да-да, вы не ослышались – для поднятия производительности надо использовать исключения.
Так же стоит отметить, что в msvc8 по сравнению с msvc71 резко снизилась стоимость кидания исключения. Но тут у них есть предел, т.к. исключения реализованы поверх SEH, значит кидание исключения всегда будет связано с переходом в ядро.
Хочется ожидать большего от gcc, т.к. они не ограничены этим фактором и могут сделать действительно быстрые исключения. Сейчас уже есть некоторые исследования на тему реализации быстрых исключений, будем надеятся, что их воплотят в gcc в ближайшем будущем. Тогда чаша весов ещё более сильно перевесит в сторону исключений.
Так же совершенна непонятна ситуация с gcc4.1.1/mingw – и кодогенерация какая-то непонятная и исключения ооочень медленные.
Так же очевидно, что использование возвращаемых значений под С++ — это совсем плохая идея – издержки от двух стихий, а плюсов нет в противопоставление с возвращаемыми значениями под С.
Ещё момент — при использовании исключений принципиально различается кодогенерация в зависимости от того, есть ли в функции локальные объекты/аргументы с нетривиальными деструкторами — если нет, то просто идут вызовы других функций, если есть, то тут уже начинается: занесение фрейма на стек, подсчёт сконструированных объектов, снятие фрейма со стека. Получается значительная разница и по скорости и по размеру кода.

Ну вот собственно всё, что хотелось сказать. Коменты и замечания преведствуются Особенно интересно было бы услышать, если я пропустил какие-то важные аспекты в исследовании, которые могут сущуственно сказаться на производительности/размере кода/или ещё чём-то в разрезе исключения/возвращаемые значения.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: [Investigation] Exceptions vs. Return Values
От: Сергей Мухин Россия  
Дата: 31.03.07 05:44
Оценка:
Здравствуйте, remark, Вы писали:

работа проделана большая,

R>

Выводы

R>Общие выводы какие возникли – возвращаемые значения типа писсимистической стратегии – т.е. чуть что сделали сразу проверяем, а не плохо ли всё, исключения – оптимистическая стратегия – делаем всё подряд без разбора и проверок, авось всё хорошо.

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

R>В принципе возникает такое ощущение, что исключения всё-таки немного быстрее (если не происходит ошибок). Соответственно если для какой-то функции вероятность провала более 1%, то надо использовать коды возврата, если менее 1%, то надо использовать исключения для повышения производительности. Да-да, вы не ослышались – для поднятия производительности надо использовать исключения.


1% это очень много. Изначально использовал исключения и не сомневался, в этом. В обработке ошибок производительность занимает далеко не первое место.

R>Так же стоит отметить, что в msvc8 по сравнению с msvc71 резко снизилась стоимость кидания исключения. Но тут у них есть предел, т.к. исключения реализованы поверх SEH, значит кидание исключения всегда будет связано с переходом в ядро.


SEH для С++ с ядром не имеет ничего общего. Это всего лишь цепочка блоков. Вряд ли исключения изменились, возможно оптимизировали деструктор или вызовы его уменьшили. или FPO оптимизацию подняли.

R>Так же очевидно, что использование возвращаемых значений под С++ — это совсем плохая идея – издержки от двух стихий, а плюсов нет в противопоставление с возвращаемыми значениями под С.

R>Ещё момент — при использовании исключений принципиально различается кодогенерация в зависимости от того, есть ли в функции локальные объекты/аргументы с нетривиальными деструкторами — если нет, то просто идут вызовы других функций, если есть, то тут уже начинается: занесение фрейма на стек, подсчёт сконструированных объектов, снятие фрейма со стека. Получается значительная разница и по скорости и по размеру кода.
---
С уважением,
Сергей Мухин
Re: [Investigation] Exceptions vs. Return Values
От: minorlogic Украина  
Дата: 31.03.07 08:32
Оценка:
Здравствуйте, remark, Вы писали:

.....
R>Ну вот собственно всё, что хотелось сказать. Коменты и замечания преведствуются Особенно интересно было бы услышать, если я пропустил какие-то важные аспекты в исследовании, которые могут сущуственно сказаться на производительности/размере кода/или ещё чём-то в разрезе исключения/возвращаемые значения.

R>


1. Спасибо за проделаную работу. Я никогда не понимал , почему так распросранен миф среди С++ программистов , о "накладности" исключений. Это же очевидно что их импдементацию можно сделать не накладнее чем коды возврата. Но с учетом того что создатели компилятора могут использовать нетривиальные трюки.


2. Спасибо за исследование размера кода , это тоже один из мифов.


3. Не исследован случай когда идет передача кода возврата на несколько уровней вверх (хотя бы на три).


4. Самый большой недостакок и пожалуй единственный , а где код ? Думаю тут найдутся люди, которые помогут его причесать.


5. А после некоторого обсуждения на форуме , не написал бы ты статью с асемблерными листингами ?


6. Очень интересен анал хотя бы под одну embeded платформу.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: [Investigation] Exceptions vs. Return Values
От: Left2 Украина  
Дата: 31.03.07 12:13
Оценка: +1 :)
M>6. Очень интересен анал хотя бы под одну embeded платформу.

Несмотря на явную двусмысленность этого предложения , абсолютно полностью согласен с тем что было бы крайне интересно исследовать не-x86 процессоры, особенно — ARMы и иже с ними.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 31.03.07 12:39
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, remark, Вы писали:


СМ>работа проделана большая,


R>>

Выводы

R>>Общие выводы какие возникли – возвращаемые значения типа писсимистической стратегии – т.е. чуть что сделали сразу проверяем, а не плохо ли всё, исключения – оптимистическая стратегия – делаем всё подряд без разбора и проверок, авось всё хорошо.

СМ>Наоборот, при кидании исключения мы никогда не пройдем мимо ошибок (если конечно catch(...) не использовать). И будем обрабатывать ошибку на том уровне, на которм надо, а в случае возрата, нам еще надо передать управление на другой уровень, если обработка идет там.


Полностью согласен, тем не менее не понимаю, к чему относится "Наоборот"...

R>>В принципе возникает такое ощущение, что исключения всё-таки немного быстрее (если не происходит ошибок). Соответственно если для какой-то функции вероятность провала более 1%, то надо использовать коды возврата, если менее 1%, то надо использовать исключения для повышения производительности. Да-да, вы не ослышались – для поднятия производительности надо использовать исключения.


СМ>1% это очень много. Изначально использовал исключения и не сомневался, в этом. В обработке ошибок производительность занимает далеко не первое место.


Да, 1% это много. Сервера зачастую обрабатывают тысячи, десятки тысяч, сотни тысяч... транзакций без ошибок.
Тем не менее такие данные мне лично помогут более точно ориентироваться. А именно — допустим на сетевой сервер поступают некие "заявки". Если заявки приходят из доверенного источника и по надежному каналу, то типа как ошибок в данных быть не должно (ну то есть они бывают допустим в 0.001%) тут однозначно можно использовать исключения при валидации заявки. Если же заявки приходят от недоверенных источников и статистика такая, что ошибки при валидации заявки бывают в 5% случаев — т.е. "шлют всякую фигню" образно выражаясь — можно подумать о возвращаемом значении при валидации — иначе обработка ошибок для некорректных заявок может снизить пропускную способность и для корректных заявок.


R>>Так же стоит отметить, что в msvc8 по сравнению с msvc71 резко снизилась стоимость кидания исключения. Но тут у них есть предел, т.к. исключения реализованы поверх SEH, значит кидание исключения всегда будет связано с переходом в ядро.


СМ>SEH для С++ с ядром не имеет ничего общего. Это всего лишь цепочка блоков. Вряд ли исключения изменились, возможно оптимизировали деструктор или вызовы его уменьшили. или FPO оптимизацию подняли.


Тут я возможно ступил, у меня почему-то подсознательно SEH ассоциировался с ядром — надо будет ещё продебажить... хотя вроде я там видел переход в ядро... ладно ещё уточню...



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: [Investigation] Exceptions vs. Return Values
От: superlexx  
Дата: 31.03.07 12:45
Оценка:
Здравствуйте, remark, Вы писали:

R>У исключений значительно меньше инструкций, тем не менее размер кода равен размеру кода на С с возвращаемыми значениями. Как ни странно... Связано с тем, что команды там больше по размеру. Код на с возвращаемыми значениями тут сильно проигрывает – так там инструкции и на проверки возвращаемых значений и на поддержку исключений.


забыли сравнить с С++ кодом, генерированным без поддержки исключений

отключение поддержки исключений при генерации OS (WinCE 5.0, ARMV4I) экономит между прочим около 400кБ, так что здесь не всё так однозначно.
Re[2]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 31.03.07 12:55
Оценка:
Здравствуйте, minorlogic, Вы писали:

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


M>.....

R>>Ну вот собственно всё, что хотелось сказать. Коменты и замечания преведствуются Особенно интересно было бы услышать, если я пропустил какие-то важные аспекты в исследовании, которые могут сущуственно сказаться на производительности/размере кода/или ещё чём-то в разрезе исключения/возвращаемые значения.

R>>


M>1. Спасибо за проделаную работу. Я никогда не понимал , почему так распросранен миф среди С++ программистов , о "накладности" исключений. Это же очевидно что их импдементацию можно сделать не накладнее чем коды возврата. Но с учетом того что создатели компилятора могут использовать нетривиальные трюки.


Да, тут сейчас какая-то двойственность получается — если исключения не летят, то они на сколько-то быстрее, а если летят, то значительно медленнее. Тем не менее я не понимаю, почему кидание такое медленное. И я уверен, что тут есть простор для оптимизации и в будущем это будет _значительно_ быстрее.


M>2. Спасибо за исследование размера кода, это тоже один из мифов.


То, что меня удивило, что С код такой же по размеру, несмотря на то, что инструкций там значительно больше... но это если есть "ресурсы", если нет, то С код значительно больше.


M>3. Не исследован случай когда идет передача кода возврата на несколько уровней вверх (хотя бы на три).


А неважно, всё равно кидание будет значительно медленнее.


M>4. Самый большой недостакок и пожалуй единственный , а где код ? Думаю тут найдутся люди, которые помогут его причесать.


Ну там куски кода для случая с "ресурсами" я приводил. Я думаю, что там можно представить как он выглядел. Дело в том, что его очень много и реально он описан на макросах... поэтому там не особо есть что приводить.
Что я понял уже когда я это всё доделал, что надо было код не кустарным способом делать, а сделать генератор кода, которому задаёшь параметр — кол-во "ресурсов, кол-во уровней вызовов и т.д. и что бы он генерировал много красивого кода. И снабдить это ещё скриптами для автоматической сборки и что бы результаты выводились сразу в виде красивых табличек. Тогда бы я это выложил и все желающие запускали бы это на своих платформах и потом выкладывали бы сюда свои результаты... тогда и для ARM'ов бы можно было протестировать и более точно проследить зависимости скорости/размера кода от различных параметров типа кол-ва "ресурсов".


M>5. А после некоторого обсуждения на форуме , не написал бы ты статью с асемблерными листингами ?


Теоретически можно, я об этом думал, даже когда-то давно скачивал пак для написания статей. Но всё же времени это потребует значительно больше.

M>6. Очень интересен анал хотя бы под одну embeded платформу.


К сожалению это не ко мне. Может руки дойдут это оформить в виде набора файлов, который можно запустить на своей платформе и выложить результаты...



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 31.03.07 12:56
Оценка: :)
Здравствуйте, Left2, Вы писали:

M>>6. Очень интересен анал


L>Несмотря на явную двусмысленность этого предложения ,


Да, я тоже вначале смутился



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: [Investigation] Exceptions vs. Return Values
От: Vain Россия google.ru
Дата: 31.03.07 13:00
Оценка:
Здравствуйте, remark, Вы писали:

R>

Exceptions vs. Return Values

Интересно бы было ещё узнать статистику для retv в стиле Win32 SetLastError/GetLastError, имхо тоже было бы полезно.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 31.03.07 13:01
Оценка:
Здравствуйте, superlexx, Вы писали:

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


R>>У исключений значительно меньше инструкций, тем не менее размер кода равен размеру кода на С с возвращаемыми значениями. Как ни странно... Связано с тем, что команды там больше по размеру. Код на с возвращаемыми значениями тут сильно проигрывает – так там инструкции и на проверки возвращаемых значений и на поддержку исключений.


S>забыли сравнить с С++ кодом, генерированным без поддержки исключений


Я думаю, что это будет аналогично С коду. Единственное отличие — функции освобождения ресурсов будут вызываться неявно, но всё равно в тех же местах, где они в С коде вызываются явно.
Тем более я такую настройку лично не уважаю Т.к. получается, что нельзя использовать конструкторы, операторы и т.д.


S>отключение поддержки исключений при генерации OS (WinCE 5.0, ARMV4I) экономит между прочим около 400кБ, так что здесь не всё так однозначно.


А WinCE можно сгенерировать из исходников???



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: [Investigation] Exceptions vs. Return Values
От: Left2 Украина  
Дата: 31.03.07 13:12
Оценка:
R>А WinCE можно сгенерировать из исходников???

Там часть кода компилируется при билде системы, часть — линкуется из предоткомпилированных под конкретный проц библиотек.
Так что собрать под какой-то свой проц — не получится, только под те что поддерживаются MS.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: [Investigation] Exceptions vs. Return Values
От: Andrew S Россия http://alchemy-lab.com
Дата: 31.03.07 14:38
Оценка: 1 (1) +2 -1
R>Провёл на досуге исследование на тему сообщение об ошибках с помощью исключений против сообщения об ошибках с помощью возвращаемых значений с т.з. скорости выполнения кода и кодогенерации. Возможно кому-то ещё будет интересно.

Во-первых, нужен исходный код. А во-вторых, все зависит от величины прослойки, которая ведет к функции api. В зависимости от типа кода она будет разной. Если очень тонкой — тогда исключения просто не могут быть быстрее ввиду того, что функции апи используют возвращаемые значение, которые необходимо будет транслировать в исключения ровно такой же проверкой. Если же, наоборот, задача исключительно вычислительная — тогда конечно, исключения могут и выигрывать. В общем, все зависит от типа задачи, а такие тесты — средняя температура по больнице, которая ни о чем не говорит, на мой взгляд.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: [Investigation] Exceptions vs. Return Values
От: Сергей Мухин Россия  
Дата: 31.03.07 17:36
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Сергей Мухин, Вы писали:


R>Полностью согласен, тем не менее не понимаю, к чему относится "Наоборот"...


"наоборот" относится к фразе "делаем всё подряд без разбора и проверок, авось всё хорошо" т.к. по этой фразе можно понять, что исключения позволяют писать код в которм ошибки так и шастают а программист об этом и не знает.
---
С уважением,
Сергей Мухин
Re[3]: [Investigation] Exceptions vs. Return Values
От: Сергей Мухин Россия  
Дата: 31.03.07 17:39
Оценка: 9 (1)
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>SEH для С++ с ядром не имеет ничего общего. Это всего лишь цепочка блоков. Вряд ли исключения изменились, возможно оптимизировали деструктор или вызовы его уменьшили. или FPO оптимизацию подняли.


R>Тут я возможно ступил, у меня почему-то подсознательно SEH ассоциировался с ядром — надо будет ещё продебажить... хотя вроде я там видел переход в ядро... ладно ещё уточню...


вот хорошая стаья про SEH здесь
---
С уважением,
Сергей Мухин
Re[2]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 01.04.07 05:43
Оценка: +1
Здравствуйте, Vain, Вы писали:

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


R>>

Exceptions vs. Return Values

V>Интересно бы было ещё узнать статистику для retv в стиле Win32 SetLastError/GetLastError, имхо тоже было бы полезно.

Это уже просто надстройка над возвращаемыми значениями. В успешном случае производительность будет равна производительности с возвращаемыми значениями, а когда происходят ошибки, то добавляется небольшое пенальти на вызов функций SetLastError/GetLastError, но оно, конечно, не сравнимо с киданием исключений. Т.ч. я думаю, тут ничего принципиально не изменится.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: [Investigation] Exceptions vs. Return Values
От: remark Россия http://www.1024cores.net/
Дата: 01.04.07 15:19
Оценка:
Здравствуйте, Andrew S, Вы писали:

R>>Провёл на досуге исследование на тему сообщение об ошибках с помощью исключений против сообщения об ошибках с помощью возвращаемых значений с т.з. скорости выполнения кода и кодогенерации. Возможно кому-то ещё будет интересно.


AS>Во-первых, нужен исходный код.


Он там есть для случая с выделением "ресурса". Тривиальные случаи, я думал, не вызовут вопросов.
Пустая функция с возвращаемым значением выглядела вот так:
bool f()
{
  return true;
}


Вызывалась вот так:

if (!f())
  ++error_count;


Пустая функция с исключениями выглядела вот так:
void f()
{
}


Вызывалась вот так:

try
{
  f();
}
catch (...)
{
  ++error_count;
}




AS>А во-вторых, все зависит от величины прослойки, которая ведет к функции api.


Влияние именно этой величины я и исследовал. Т.е. вначале смотрел, когда эта величина 1 (функция), потом в асимптотическом случае, когда очень много функций, потом в случае, когда величина прослойки более-менее соизмерима с неким реальным проектом.
В принципе у меня есть идея на будущее сделать генератор кода и построить графики производительности в зависимости от "глубины" прослойки, "ширины" прослойки и кол-ва "ресурсов", которые выделяются в прослойке. Но пока получилось только так.

AS>В зависимости от типа кода она будет разной. Если очень тонкой — тогда исключения просто не могут быть быстрее ввиду того, что функции апи используют возвращаемые значение, которые необходимо будет транслировать в исключения ровно такой же проверкой.


Это всё есть. Если прослойка 0 — то одинаково, т.к ничего не различается. Если 1 — то исключения быстрее, Если много — то исключения ещё быстрее. Правда ситуация меняется, когда есть "ресурсы".


AS>Если же, наоборот, задача исключительно вычислительная — тогда конечно, исключения могут и выигрывать. В общем, все зависит от типа задачи, а такие тесты — средняя температура по больнице, которая ни о чем не говорит, на мой взгляд.


Естественно всё зависит от задачи. Но я то исследовал не задачи, а примитивы. Вычислительную сложность которых можно просто складывать и оценить результат.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: [Investigation] Exceptions vs. Return Values
От: Vain Россия google.ru
Дата: 01.04.07 18:10
Оценка:
Здравствуйте, remark, Вы писали:

R>>>

Exceptions vs. Return Values

V>>Интересно бы было ещё узнать статистику для retv в стиле Win32 SetLastError/GetLastError, имхо тоже было бы полезно.

R>Это уже просто надстройка над возвращаемыми значениями. В успешном случае производительность будет равна производительности с возвращаемыми значениями, а когда происходят ошибки, то добавляется небольшое пенальти на вызов функций SetLastError/GetLastError, но оно, конечно, не сравнимо с киданием исключений. Т.ч. я думаю, тут ничего принципиально не изменится.


Я имею ввиду ещё и использование TLS

R>
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: [Investigation] Exceptions vs. Return Values
От: MShura  
Дата: 01.04.07 18:21
Оценка: 1 (1)
R>Ну вот собственно всё, что хотелось сказать. Коменты и замечания преведствуются Особенно интересно было бы услышать, если я пропустил какие-то важные аспекты в исследовании, которые могут сущуственно сказаться на производительности/размере кода/или ещё чём-то в разрезе исключения/возвращаемые значения.

В gcc для оптимизации jmp можно использовать макросы likely/unlikely.
А для msvc эти макросы можно сделать пустышками.
Re[2]: [Investigation] Exceptions vs. Return Values
От: Сергей Мухин Россия  
Дата: 01.04.07 18:58
Оценка:
Здравствуйте, MShura, Вы писали:

R>>Ну вот собственно всё, что хотелось сказать. Коменты и замечания преведствуются Особенно интересно было бы услышать, если я пропустил какие-то важные аспекты в исследовании, которые могут сущуственно сказаться на производительности/размере кода/или ещё чём-то в разрезе исключения/возвращаемые значения.


MS>В gcc для оптимизации jmp можно использовать макросы likely/unlikely.

MS>А для msvc эти макросы можно сделать пустышками.

и какое это имеет отношение к subj?
---
С уважением,
Сергей Мухин
Re[3]: [Investigation] Exceptions vs. Return Values
От: Andrew S Россия http://alchemy-lab.com
Дата: 01.04.07 22:59
Оценка: +1
R>Вызывалась вот так:

R>
R>try
R>{
R>  f();
R>}
R>catch (...)
R>{
R>  ++error_count;
R>}
R>


AS>>А во-вторых, все зависит от величины прослойки, которая ведет к функции api.


R>Влияние именно этой величины я и исследовал. Т.е. вначале смотрел, когда эта величина 1 (функция), потом в асимптотическом случае, когда очень много функций, потом в случае, когда величина прослойки более-менее соизмерима с неким реальным проектом.

R>В принципе у меня есть идея на будущее сделать генератор кода и построить графики производительности в зависимости от "глубины" прослойки, "ширины" прослойки и кол-ва "ресурсов", которые выделяются в прослойке. Но пока получилось только так.

AS>>В зависимости от типа кода она будет разной. Если очень тонкой — тогда исключения просто не могут быть быстрее ввиду того, что функции апи используют возвращаемые значение, которые необходимо будет транслировать в исключения ровно такой же проверкой.


R>Это всё есть. Если прослойка 0 — то одинаково, т.к ничего не различается. Если 1 — то исключения быстрее, Если много — то исключения ещё быстрее. Правда ситуация меняется, когда есть "ресурсы".


Вот тут надо осторожнее в смысле организации цикла. Оптимизирующий компилятор вполне способен вынести установку фрейма исключений в "пустых" функциях за пределы цикла (тогда как для "нормальных" функций и тем более функций апи он этого делать не имеет права) — соответственно, такие тесты покажут фикцию. Как я понимаю, ты называешь эту ситуацию "ресурсы" (вообще, надо бы использовать нормальную терминологию — например, стек фрейм локальных переменных), тогда как на самом деле это вполне обычные локальные переменные — т.е. требование наличия своего стек фрейма, что скорее правило, а не исключение. В общем, надо моделировать _реальный_ код, а не пустые функции. А для этого надо иметь статистику по виду и функциональности функций. У тебя таковая есть?
А вообще, и замерять то особо ничего не надо — достаточно анализа ассемблерного листинга. Установка фрейма исключений в цикле — довольно дорогая операция, значительно дороже, чем проверка ошибки (особенно с учетом работающего механизма предсказания переходов). Поэтому обычно и стараются вынести это за пределы цикла — тогда, если код _только_ вычислительный, или же "толстая" прослойка до финальной функции (где проверка и генерация исключения) получится выигрыш. В общем, нужно нечто вроде fctest — где есть реальные паттерны работы дисковой подсистемы, поэтому и результаты реальны. А так — все это сферический конь в вакууме.

AS>>Если же, наоборот, задача исключительно вычислительная — тогда конечно, исключения могут и выигрывать. В общем, все зависит от типа задачи, а такие тесты — средняя температура по больнице, которая ни о чем не говорит, на мой взгляд.


R>Естественно всё зависит от задачи. Но я то исследовал не задачи, а примитивы. Вычислительную сложность которых можно просто складывать и оценить результат.


Не все так просто. Даже замеры времени по rdtsc — это неправильно (если уж придираться), поскольку учитывает не время потока, а все такты процессора. В случае многозадачной системы это как минимум неверно. Выложи исходники — я тебя уверяю, народ раскритикует по самые В общем, для начала неплохо бы тебе разобраться в механизме функционирования всего этого на самом низком уровне (тем более, даже для разных компиляторов он отличается — например, 6, 7.1 и 8 имеют разные механизмы раскрутки фрейма исключений), а потом уже, вооружившись знаниями о том, что и как делает компилятор (а также и ОС), писать паттерны поведения. Тогда бы действительно получилось интересное исследование на тему.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.