
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.30] |
![]() |
|
Страницы: (2) 1 [2] все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались.
|
Сообщ.
#17
,
|
|
|
Цитата x0ras @ Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались. Насчёт накладных расходов. Решила наконец, что If in doubt, check it out Сравниваем. Проект без SEH ![]() ![]() PUBLIC _main PUBLIC ??_C@_02DPKJAMEF@?$CFd?$AA@ ; `string' PUBLIC ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ ; `string' EXTRN _printf:NEAR EXTRN _scanf:NEAR ; COMDAT ??_C@_02DPKJAMEF@?$CFd?$AA@ ; File d:\myprojects\4test\4test.cpp CONST SEGMENT ??_C@_02DPKJAMEF@?$CFd?$AA@ DB '%d', 00H ; `string' CONST ENDS ; COMDAT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ CONST SEGMENT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ DB 'should no' DB 't be here. Maybe zero division?', 00H ; `string' ; Function compile flags: /Ogty CONST ENDS ; COMDAT _main _TEXT SEGMENT _a$ = -4 ; size = 4 _main PROC NEAR ; COMDAT ; 8 : { push ecx ; 9 : int a = 10; ; 10 : a = 15; ; 11 : a += 20; ; 12 : a -= 40; ; 13 : printf( "%d", a ); push -5 ; fffffffbH push OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@ mov DWORD PTR _a$[esp+12], -5 ; fffffffbH call _printf ; 14 : scanf( "%d", &a ); lea eax, DWORD PTR _a$[esp+12] push eax push OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@ call _scanf ; 15 : if( a > 0 ) mov eax, DWORD PTR _a$[esp+20] add esp, 16 ; 00000010H test eax, eax jle SHORT $L58684 ; 16 : printf( "should not be here. Maybe zero division?" ); push OFFSET FLAT:??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ call _printf add esp, 4 $L58684: ; 17 : return 0; xor eax, eax ; 18 : } pop ecx ret 0 _main ENDP _TEXT ENDS END А теперь c SEH( ветка, которая раньше была в обработчике IF вынесена в EXCEPT_HANDLER Проект скомпилирован с теми же стандартными настройками на VS .NET ![]() ![]() PUBLIC _main PUBLIC ??_C@_02DPKJAMEF@?$CFd?$AA@ ; `string' PUBLIC ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ ; `string' EXTRN _printf:NEAR EXTRN _scanf:NEAR EXTRN __except_handler3:NEAR EXTRN __except_list:DWORD ; COMDAT CONST ; File d:\myprojects\4test\4test.cpp CONST SEGMENT $T58689 DD 0ffffffffH DD FLAT:$L58683 DD FLAT:$L58684 CONST ENDS ; COMDAT ??_C@_02DPKJAMEF@?$CFd?$AA@ CONST SEGMENT ??_C@_02DPKJAMEF@?$CFd?$AA@ DB '%d', 00H ; `string' CONST ENDS ; COMDAT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ CONST SEGMENT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ DB 'should no' DB 't be here. Maybe zero division?', 00H ; `string' ; Function compile flags: /Ogty CONST ENDS ; COMDAT _main _TEXT SEGMENT _a$ = -28 ; size = 4 [COLOR=red]__$SEHRec$ = -24 [/COLOR] ; size = 24 _main PROC NEAR ; COMDAT ; 8 : { [COLOR=red] push ebp mov ebp, esp push -1 push OFFSET FLAT:$T58689 push OFFSET FLAT:__except_handler3 mov eax, DWORD PTR fs:__except_list push eax mov DWORD PTR fs:__except_list, esp sub esp, 12 ; 0000000cH push ebx push esi push edi mov DWORD PTR __$SEHRec$[ebp], esp[/COLOR] ; 9 : int a = 10; mov DWORD PTR _a$[ebp], 10 ; 0000000aH ; 10 : __try [COLOR=red]mov DWORD PTR __$SEHRec$[ebp+20], 0[/COLOR] ; 11 : { ; 12 : a = 15; mov DWORD PTR _a$[ebp], 15 ; 0000000fH ; 13 : a += 20; mov DWORD PTR _a$[ebp], 35 ; 00000023H ; 14 : a -= 40; mov DWORD PTR _a$[ebp], -5 ; fffffffbH ; 15 : printf( "%d", a ); push -5 ; fffffffbH push OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@ call _printf ; 16 : scanf( "%d", &a ); lea eax, DWORD PTR _a$[ebp] push eax push OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@ call _scanf add esp, 16 ; 00000010H jmp SHORT $L58693 $L58683: ; 17 : } ; 18 : __except(EXCEPTION_EXECUTE_HANDLER) [COLOR=red]mov eax, 1 $L58685: ret 0 $L58684: mov esp, DWORD PTR __$SEHRec$[ebp][/COLOR] ; 19 : { ; 20 : printf( "should not be here. Maybe zero division?" ); push OFFSET FLAT:??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ call _printf add esp, 4 $L58693: mov DWORD PTR __$SEHRec$[ebp+20], -1 ; 21 : } ; 22 : return 0; xor eax, eax ; 23 : } [COLOR=red] mov ecx, DWORD PTR __$SEHRec$[ebp+8] mov DWORD PTR fs:__except_list, ecx pop edi pop esi pop ebx mov esp, ebp pop ebp[/COLOR] ret 0 _main ENDP _TEXT ENDS END Бросаются в глаза две вещи: 1) большие накладные расходы на начало\завершение функции, где используются исключения 2) то, что оптимизация при использовании SEH, если и не отключается, то сильно сдаёт. 2-ое мне откровенно непонятно, в то время как первое заставило иначе взглянуть на своё использовании исключений. -юсртыхэю Цитата amk @ Раскрутка стека программы операционной системой затруднена хотя бы потому, что программа может использовать какую-то свой, не определённый в системе метод хранения необходимой информации. А так и получится, если программа строится компилятором/сборщиком сторонних фирм, а не создателя ОС. В случае с Windows это особенно актуально, так как MS известна своим пристрастием включать в свои ОС недокументированные возможности. Но многие используют VisualStudio, который вполне от производителя ОС. А Borland тоже получил какое-то тайное знания от Microsoft касательно того, как реализовать обработку исключений ( по крайней мере, Matt Pietrek так считал ). Что же до Intel-овского компилятора, то у них замечательная дружба с Microsoft и они лучше многих знают внутренние структуры ( посмотреть хотя бы на VTune ). А какие ещё компиляторы популярны под Windows, чтобы считать эту проблему актуальной? |
Сообщ.
#18
,
|
|
|
Продолжаем эксперемент:
VC 7.1 Код без исключений ![]() ![]() void main() { 00401000 push ecx 00401001 push esi //PerformanceTest(); int a = 10; a = 15; a += 20; a -= 40; printf( "%d", a ); 00401002 mov esi,dword ptr [__imp__printf (402064h)] 00401008 push 0FFFFFFFBh 0040100A push offset string "%d" (4020D8h) 0040100F mov dword ptr [esp+0Ch],0FFFFFFFBh 00401017 call esi scanf( "%d", &a ); 00401019 lea eax,[esp+0Ch] 0040101D push eax 0040101E push offset string "%d" (4020D8h) 00401023 call dword ptr [__imp__scanf (402068h)] if (a > 0) 00401029 mov eax,dword ptr [esp+14h] 0040102D add esp,10h 00401030 test eax,eax 00401032 jle main+3Eh (40103Eh) printf( "should not be here. Maybe zero division?" ); 00401034 push offset string "should not be here. Maybe zero d"... (4020ACh) 00401039 call esi 0040103B add esp,4 return; } 0040103E xor eax,eax 00401040 pop esi 00401041 pop ecx 00401042 ret Он же, но с С++-исключениями ![]() ![]() void main() { 00401000 push ecx //PerformanceTest(); int a = 10; try { a = 15; a += 20; a -= 40; printf( "%d", a ); 00401001 push 0FFFFFFFBh 00401003 push offset string "%d" (4020ACh) 00401008 mov dword ptr [esp+8],0FFFFFFFBh 00401010 call dword ptr [__imp__printf (402064h)] scanf( "%d", &a ); 00401016 lea eax,[esp+8] 0040101A push eax 0040101B push offset string "%d" (4020ACh) 00401020 call dword ptr [__imp__scanf (402068h)] } catch (...) { printf( "should not be here. Maybe zero division?" ); } return; } 00401026 xor eax,eax 00401028 add esp,14h 0040102B ret Он же, но с SEH ![]() ![]() void main() { 00401000 push ebp 00401001 mov ebp,esp 00401003 push 0FFFFFFFFh 00401005 push 4020E0h 0040100A push offset _except_handler3 (40114Eh) 0040100F mov eax,dword ptr fs:[00000000h] 00401015 push eax 00401016 mov dword ptr fs:[0],esp 0040101D sub esp,0Ch 00401020 push ebx 00401021 push esi 00401022 push edi 00401023 mov dword ptr [ebp-18h],esp //PerformanceTest(); int a = 10; 00401026 mov dword ptr [a],0Ah __try 0040102D mov dword ptr [ebp-4],0 { a = 15; 00401034 mov dword ptr [a],0Fh a += 20; 0040103B mov dword ptr [a],23h a -= 40; 00401042 mov dword ptr [a],0FFFFFFFBh printf( "%d", a ); 00401049 push 0FFFFFFFBh 0040104B push offset string "%d" (4020D8h) 00401050 call dword ptr [__imp__printf (402064h)] scanf( "%d", &a ); 00401056 lea eax,[a] 00401059 push eax 0040105A push offset string "%d" (4020D8h) 0040105F call dword ptr [__imp__scanf (402068h)] 00401065 add esp,10h 00401068 jmp $L39474+11h (401081h) } __except(EXCEPTION_EXECUTE_HANDLER) 0040106A mov eax,1 $L39481: 0040106F ret $L39474: 00401070 mov esp,dword ptr [ebp-18h] { printf( "should not be here. Maybe zero division?" ); 00401073 push offset string "should not be here. Maybe zero d"... (4020ACh) 00401078 call dword ptr [__imp__printf (402064h)] 0040107E add esp,4 00401081 mov dword ptr [ebp-4],0FFFFFFFFh } return; } 00401088 xor eax,eax 0040108A mov ecx,dword ptr [ebp-10h] 0040108D mov dword ptr fs:[0],ecx 00401094 pop edi 00401095 pop esi 00401096 pop ebx 00401097 mov esp,ebp 00401099 pop ebp 0040109A ret Что называется, почувствуйте разницу... Добавлено В связи с чем предлагаю следующее дополнение к правилам раздела: Цитата Если кто-то берется утвержать, что та или иная языковая конструкция неэффективна, неоптимальна, просаживает производительность кода, и т. д. и т. п., то любое такое утверждение должно быть подкреплено не только кодом на С++, но и ассемблерным листингом (полученным по приведенному коду), иллюстрирующим утверждение, замерами производительности или любыми другими весомыми доказательствами. Иначе имеет смысл сразу же закрывать тему за недоказанностью "обвинений". |
Сообщ.
#19
,
|
|
|
Flex Ferrum
Дополнение к правилам шикарное, за одним НО. Есть знание теоретическое и знание практическое. Может конкретно на этом примере так случилось, что результаты оказались такими неэффективными. А вдруг например на kernel-space или на другом компиляторе картина будет прямо противоположная. Если когда-нибудь занимался попыткамиотносительно точно замерить производительность, то поймёшь... Когда два теста без перекомпиляции но при перезагрузке ОС давали диаметрально разные результаты... |
Сообщ.
#20
,
|
|
|
Цитата TrefptYc @ Дополнение к правилам шикарное, за одним НО. Есть знание теоретическое и знание практическое. Так потому и предлагается спорить не голословно, а с подобающей аргументацией. Кстати, если кто-то соберется выкинуть исключение, то код main начинает выглядеть так: ![]() ![]() void main() { 00401020 push ebp 00401021 mov ebp,esp 00401023 push 0FFFFFFFFh 00401025 push offset __ehhandler$_main (401580h) 0040102A mov eax,dword ptr fs:[00000000h] 00401030 push eax 00401031 mov dword ptr fs:[0],esp 00401038 sub esp,8 0040103B push ebx 0040103C push esi 0040103D push edi 0040103E mov dword ptr [ebp-10h],esp //PerformanceTest(); int a = 10; try { a = 15; a += 20; a -= 40; printf( "%d", a ); 00401041 push 0FFFFFFFBh 00401043 push offset string "%d" (4020E8h) 00401048 mov dword ptr [ebp-4],0 0040104F mov dword ptr [a],0FFFFFFFBh 00401056 call dword ptr [__imp__printf (40206Ch)] scanf( "%d", &a ); 0040105C lea eax,[a] 0040105F push eax 00401060 push offset string "%d" (4020E8h) 00401065 call dword ptr [__imp__scanf (402070h)] 0040106B add esp,10h a /= foo___(); 0040106E jmp foo___ (401000h) printf( "%d", a ); } catch (...) { printf( "should not be here. Maybe zero division?" ); 00401073 push offset string "should not be here. Maybe zero d"... (4020BCh) 00401078 call dword ptr [__imp__printf (40206Ch)] 0040107E add esp,4 } 00401081 mov eax,offset $L37751 (401087h) 00401086 ret return; } 00401087 mov ecx,dword ptr [ebp-0Ch] 0040108A pop edi 0040108B pop esi 0040108C xor eax,eax 0040108E mov dword ptr fs:[0],ecx 00401095 pop ebx 00401096 mov esp,ebp 00401098 pop ebp 00401099 ret |
Сообщ.
#21
,
|
|
|
Flex Ferrum
Ну всё правильно. В твоём первом примере с С++-исключениями по ветке catch(...) пойти не могли, ведь, насколько я помню, С++ обработчтик не перехватывает железные исключения, а софтверных ты не кидал и деления на константук у тебя не было. поэтому компилятор просто убрал обработку исключений, как если бы он убрал конструкцию if(0){}. Так что адекватное практическое знание ещё получить нужно... |
Сообщ.
#22
,
|
|
|
Из этого, кстати, следует весьма интересный вывод. Пустой спецификатор исключений - вполне хороший способ избежать оверхеда. Т. е. если нетривиальный метод гарантирует, что не выкинет исключений (гарантия отсутствия ошибок), то имеет смысл помечать его как throw(), что позволит компилятору опимизировать его вызов.
Добавлено Вот еще два примера кода. В обоих случаях вызывается метод foo___. Но в первом случае он может кидать любые исключения, а во втором случае помечен как throw(). ![]() ![]() void main() { push ebp mov ebp,esp push 0FFFFFFFFh push offset __ehhandler$_main (4015A0h) mov eax,dword ptr fs:[00000000h] push eax mov dword ptr fs:[0],esp sub esp,8 push ebx push esi //PerformanceTest(); int a = 10; try { a = 15; a += 20; a -= 40; printf( "%d", a ); mov esi,dword ptr [__imp__printf (40206Ch)] push edi mov dword ptr [ebp-10h],esp push 0FFFFFFFBh push offset string "%d" (4020E8h) mov dword ptr [ebp-4],0 mov dword ptr [a],0FFFFFFFBh call esi scanf( "%d", &a ); lea eax,[a] push eax push offset string "%d" (4020E8h) call dword ptr [__imp__scanf (402070h)] add esp,10h a /= foo___(); call foo___ (401000h) mov ecx,eax mov eax,dword ptr [a] cdq idiv eax,ecx printf( "%d", a ); push eax push offset string "%d" (4020E8h) mov dword ptr [a],eax call esi add esp,8 return; } mov ecx,dword ptr [ebp-0Ch] pop edi pop esi xor eax,eax mov dword ptr fs:[0],ecx pop ebx mov esp,ebp pop ebp ret } catch (...) { printf( "should not be here. Maybe zero division?" ); push offset string "should not be here. Maybe zero d"... (4020BCh) call dword ptr [__imp__printf (40206Ch)] add esp,4 } mov eax,offset $L37743 (40108Bh) ret ![]() ![]() void main() { push ecx push esi //PerformanceTest(); int a = 10; try { a = 15; a += 20; a -= 40; printf( "%d", a ); mov esi,dword ptr [__imp__printf (40206Ch)] push 0FFFFFFFBh push offset string "%d" (4020BCh) mov dword ptr [esp+0Ch],0FFFFFFFBh call esi scanf( "%d", &a ); lea eax,[esp+0Ch] push eax push offset string "%d" (4020BCh) call dword ptr [__imp__scanf (402070h)] a /= foo___(); call foo___ (401000h) mov ecx,eax mov eax,dword ptr [esp+14h] cdq idiv eax,ecx printf( "%d", a ); push eax push offset string "%d" (4020BCh) mov dword ptr [esp+1Ch],eax call esi add esp,18h } catch (...) { printf( "should not be here. Maybe zero division?" ); } return; } xor eax,eax pop esi pop ecx ret |
Сообщ.
#23
,
|
|
|
Цитата Flex Ferrum @ Судя по листингу, никакой обработки нет - компилятор выкинул.Он же, но с С++-исключениями Да и с POD-типами не совсем честно. Надо внутрь try засунуть какой-нибудь не-POD тип, например, vector. ![]() Добавлено меня опередили ![]() |