На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> Исключения и производительность , практика
    Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались.
      Цитата x0ras @
      Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались.

      Насчёт накладных расходов. Решила наконец, что If in doubt, check it out
      Сравниваем.

      Проект без SEH
      ExpandedWrap disabled
        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
      ExpandedWrap disabled
        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, чтобы считать эту проблему актуальной?
        Продолжаем эксперемент:
        VC 7.1 Код без исключений
        ExpandedWrap disabled
          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

        Он же, но с С++-исключениями
        ExpandedWrap disabled
          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
        ExpandedWrap disabled
          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


        Что называется, почувствуйте разницу...

        Добавлено
        В связи с чем предлагаю следующее дополнение к правилам раздела:
        Цитата

        Если кто-то берется утвержать, что та или иная языковая конструкция неэффективна, неоптимальна, просаживает производительность кода, и т. д. и т. п., то любое такое утверждение должно быть подкреплено не только кодом на С++, но и ассемблерным листингом (полученным по приведенному коду), иллюстрирующим утверждение, замерами производительности или любыми другими весомыми доказательствами. Иначе имеет смысл сразу же закрывать тему за недоказанностью "обвинений".
          Flex Ferrum

          Дополнение к правилам шикарное, за одним НО.
          Есть знание теоретическое и знание практическое. Может конкретно на этом примере так случилось, что результаты оказались такими неэффективными. А вдруг например на kernel-space или на другом компиляторе картина будет прямо противоположная. Если когда-нибудь занимался попыткамиотносительно точно замерить производительность, то поймёшь... Когда два теста без перекомпиляции но при перезагрузке ОС давали диаметрально разные результаты...
            Цитата TrefptYc @
            Дополнение к правилам шикарное, за одним НО.
            Есть знание теоретическое и знание практическое.

            Так потому и предлагается спорить не голословно, а с подобающей аргументацией. Кстати, если кто-то соберется выкинуть исключение, то код main начинает выглядеть так:
            ExpandedWrap disabled
              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
              Flex Ferrum

              Ну всё правильно. В твоём первом примере с С++-исключениями по ветке catch(...) пойти не могли, ведь, насколько я помню, С++ обработчтик не перехватывает железные исключения, а софтверных ты не кидал и деления на константук у тебя не было. поэтому компилятор просто убрал обработку исключений, как если бы он убрал конструкцию if(0){}. Так что адекватное практическое знание ещё получить нужно...
                Из этого, кстати, следует весьма интересный вывод. Пустой спецификатор исключений - вполне хороший способ избежать оверхеда. Т. е. если нетривиальный метод гарантирует, что не выкинет исключений (гарантия отсутствия ошибок), то имеет смысл помечать его как throw(), что позволит компилятору опимизировать его вызов.

                Добавлено
                Вот еще два примера кода. В обоих случаях вызывается метод foo___. Но в первом случае он может кидать любые исключения, а во втором случае помечен как throw().
                ExpandedWrap disabled
                  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


                ExpandedWrap disabled
                  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
                  Цитата Flex Ferrum @
                  Он же, но с С++-исключениями
                  Судя по листингу, никакой обработки нет - компилятор выкинул.

                  Да и с POD-типами не совсем честно. Надо внутрь try засунуть какой-нибудь не-POD тип, например, vector. :)

                  Добавлено
                  меня опередили :)
                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0414 ]   [ 15 queries used ]   [ Generated: 18.07.25, 03:14 GMT ]