C++ оптимизация. 5 вопросов

Тема в разделе "WASM.A&O", создана пользователем cresta, 10 мар 2005.

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Код, созданный компилятором из Visual C++ Toolkit 2003

    Ключ cl /G7 minimal.exe (G7 - optimized for Pentium 4 or Athlon)


    Код (Text):
    1. 00401000  /$ 55             PUSH EBP
    2. 00401001  |. 8BEC           MOV EBP,ESP
    3. 00401003  |. 83EC 14        SUB ESP,14
    4. 00401006  |. 56             PUSH ESI
    5. 00401007  |. 8B45 10        MOV EAX,DWORD PTR SS:[EBP+10]
    6. 0040100A  |. 2B45 0C        SUB EAX,DWORD PTR SS:[EBP+C]
    7. 0040100D  |. D1F8           SAR EAX,1
    8. 0040100F  |. 0345 0C        ADD EAX,DWORD PTR SS:[EBP+C]
    9. 00401012  |. 8945 FC        MOV DWORD PTR SS:[EBP-4],EAX
    10. 00401015  |. 8B4D FC        MOV ECX,DWORD PTR SS:[EBP-4]
    11. 00401018  |. 8B55 08        MOV EDX,DWORD PTR SS:[EBP+8]
    12. 0040101B  |. 8B048A         MOV EAX,DWORD PTR DS:[EDX+ECX*4]
    13. 0040101E  |. 8945 F4        MOV DWORD PTR SS:[EBP-C],EAX
    14. 00401021  |. 8B4D FC        MOV ECX,DWORD PTR SS:[EBP-4]
    15. 00401024  |. 8B55 08        MOV EDX,DWORD PTR SS:[EBP+8]
    16. 00401027  |. 8B45 0C        MOV EAX,DWORD PTR SS:[EBP+C]
    17. 0040102A  |. 8B75 08        MOV ESI,DWORD PTR SS:[EBP+8]
    18. 0040102D  |. 8B0486         MOV EAX,DWORD PTR DS:[ESI+EAX*4]
    19. 00401030  |. 89048A         MOV DWORD PTR DS:[EDX+ECX*4],EAX
    20. 00401033  |. 8B4D 0C        MOV ECX,DWORD PTR SS:[EBP+C]
    21. 00401036  |. 83C1 01        ADD ECX,1
    22. 00401039  |. 894D F8        MOV DWORD PTR SS:[EBP-8],ECX
    23. 0040103C  |. 8B55 10        MOV EDX,DWORD PTR SS:[EBP+10]
    24. 0040103F  |. 8955 EC        MOV DWORD PTR SS:[EBP-14],EDX
    25. 00401042  |> B8 01000000    /MOV EAX,1
    26. 00401047  |. 85C0           |TEST EAX,EAX
    27. 00401049  |. 0F84 8D000000  |JE minimal.004010DC
    28. 0040104F  |> 8B4D F8        |/MOV ECX,DWORD PTR SS:[EBP-8]
    29. 00401052  |. 3B4D EC        ||CMP ECX,DWORD PTR SS:[EBP-14]
    30. 00401055  |. 7D 19          ||JGE SHORT minimal.00401070
    31. 00401057  |. 8B55 F8        ||MOV EDX,DWORD PTR SS:[EBP-8]
    32. 0040105A  |. 8B45 08        ||MOV EAX,DWORD PTR SS:[EBP+8]
    33. 0040105D  |. 8B4D F4        ||MOV ECX,DWORD PTR SS:[EBP-C]
    34. 00401060  |. 3B0C90         ||CMP ECX,DWORD PTR DS:[EAX+EDX*4]
    35. 00401063  |. 7E 0B          ||JLE SHORT minimal.00401070
    36. 00401065  |. 8B55 F8        ||MOV EDX,DWORD PTR SS:[EBP-8]
    37. 00401068  |. 83C2 01        ||ADD EDX,1
    38. 0040106B  |. 8955 F8        ||MOV DWORD PTR SS:[EBP-8],EDX
    39. 0040106E  |.^EB DF          |\JMP SHORT minimal.0040104F
    40. 00401070  |> 8B45 EC        |/MOV EAX,DWORD PTR SS:[EBP-14]
    41. 00401073  |. 3B45 F8        ||CMP EAX,DWORD PTR SS:[EBP-8]
    42. 00401076  |. 7C 19          ||JL SHORT minimal.00401091
    43. 00401078  |. 8B4D EC        ||MOV ECX,DWORD PTR SS:[EBP-14]
    44. 0040107B  |. 8B55 08        ||MOV EDX,DWORD PTR SS:[EBP+8]
    45. 0040107E  |. 8B048A         ||MOV EAX,DWORD PTR DS:[EDX+ECX*4]
    46. 00401081  |. 3B45 F4        ||CMP EAX,DWORD PTR SS:[EBP-C]
    47. 00401084  |. 7E 0B          ||JLE SHORT minimal.00401091
    48. 00401086  |. 8B4D EC        ||MOV ECX,DWORD PTR SS:[EBP-14]
    49. 00401089  |. 83E9 01        ||SUB ECX,1
    50. 0040108C  |. 894D EC        ||MOV DWORD PTR SS:[EBP-14],ECX
    51. 0040108F  |.^EB DF          |\JMP SHORT minimal.00401070
    52. 00401091  |> 8B55 F8        |MOV EDX,DWORD PTR SS:[EBP-8]
    53. 00401094  |. 3B55 EC        |CMP EDX,DWORD PTR SS:[EBP-14]
    54. 00401097  |. 7C 02          |JL SHORT minimal.0040109B
    55. 00401099  |. EB 41          |JMP SHORT minimal.004010DC
    56. 0040109B  |> 8B45 F8        |MOV EAX,DWORD PTR SS:[EBP-8]
    57. 0040109E  |. 8B4D 08        |MOV ECX,DWORD PTR SS:[EBP+8]
    58. 004010A1  |. 8B1481         |MOV EDX,DWORD PTR DS:[ECX+EAX*4]
    59. 004010A4  |. 8955 F0        |MOV DWORD PTR SS:[EBP-10],EDX
    60. 004010A7  |. 8B45 F8        |MOV EAX,DWORD PTR SS:[EBP-8]
    61. 004010AA  |. 8B4D 08        |MOV ECX,DWORD PTR SS:[EBP+8]
    62. 004010AD  |. 8B55 EC        |MOV EDX,DWORD PTR SS:[EBP-14]
    63. 004010B0  |. 8B75 08        |MOV ESI,DWORD PTR SS:[EBP+8]
    64. 004010B3  |. 8B1496         |MOV EDX,DWORD PTR DS:[ESI+EDX*4]
    65. 004010B6  |. 891481         |MOV DWORD PTR DS:[ECX+EAX*4],EDX
    66. 004010B9  |. 8B45 EC        |MOV EAX,DWORD PTR SS:[EBP-14]
    67. 004010BC  |. 8B4D 08        |MOV ECX,DWORD PTR SS:[EBP+8]
    68. 004010BF  |. 8B55 F0        |MOV EDX,DWORD PTR SS:[EBP-10]
    69. 004010C2  |. 891481         |MOV DWORD PTR DS:[ECX+EAX*4],EDX
    70. 004010C5  |. 8B45 EC        |MOV EAX,DWORD PTR SS:[EBP-14]
    71. 004010C8  |. 83E8 01        |SUB EAX,1
    72. 004010CB  |. 8945 EC        |MOV DWORD PTR SS:[EBP-14],EAX
    73. 004010CE  |. 8B4D F8        |MOV ECX,DWORD PTR SS:[EBP-8]
    74. 004010D1  |. 83C1 01        |ADD ECX,1
    75. 004010D4  |. 894D F8        |MOV DWORD PTR SS:[EBP-8],ECX
    76. 004010D7  |.^E9 66FFFFFF    \JMP minimal.00401042
    77. 004010DC  |> 8B55 0C        MOV EDX,DWORD PTR SS:[EBP+C]
    78. 004010DF  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
    79. 004010E2  |. 8B4D EC        MOV ECX,DWORD PTR SS:[EBP-14]
    80. 004010E5  |. 8B75 08        MOV ESI,DWORD PTR SS:[EBP+8]
    81. 004010E8  |. 8B0C8E         MOV ECX,DWORD PTR DS:[ESI+ECX*4]
    82. 004010EB  |. 890C90         MOV DWORD PTR DS:[EAX+EDX*4],ECX
    83. 004010EE  |. 8B55 EC        MOV EDX,DWORD PTR SS:[EBP-14]
    84. 004010F1  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
    85. 004010F4  |. 8B4D F4        MOV ECX,DWORD PTR SS:[EBP-C]
    86. 004010F7  |. 890C90         MOV DWORD PTR DS:[EAX+EDX*4],ECX
    87. 004010FA  |. 8B45 EC        MOV EAX,DWORD PTR SS:[EBP-14]
    88. 004010FD  |. 5E             POP ESI
    89. 004010FE  |. 8BE5           MOV ESP,EBP
    90. 00401100  |. 5D             POP EBP
    91. 00401101  \. C3             RETN




    Несколько вопросов:



    1. Для чего строки
    Код (Text):
    1. 00401042  |> B8 01000000    /MOV EAX,1
    2. 00401047  |. 85C0           |TEST EAX,EAX
    3. 00401049  |. 0F84 8D000000  |JE minimal.004010DC


    Ведь переход никогда не будет осуществлен? Лишние 11 байт и некоторое кол-во тактов



    2. Строки 00401007-00401021 - расчет среднего арифметического и сохранение на стеке [EBP-4]. Значение используется как промежуточное для вычисления другого, которое происходит следом за промежуточным. Зачем делать на стеке переменную, сохранять в неё промежуточное значение и тут же его снова извлекать для последующего расчета с ней? Почему бы промежуточный результат не держать в регистре, это бы дало экономию двух пересылок? Тем более, что до конца процедуры эта величина более не задействуется.



    3. Вот такая конструкция используется вместо обычного inc:
    Код (Text):
    1. MOV EDX,DWORD PTR SS:[EBP-8]
    2. ADD EDX,1
    3. MOV DWORD PTR SS:[EBP-8],EDX


    это опять же две лишних пересылки, и такой фрагмент повторяется несколько раз. Почему?



    4. Почему пустуют регистры edi ebx? В них можно было бы один раз загрузить и держать некоторые базовые адреса/значения, которые не меняются в процедуре. Вместо этого раз за разом эти адреса загружаются то в edx, то в ecx, то в eax. Непонятно.



    5. Почему в eax два раза подряд загружается [EBP-8]? Ведь аккумулятор не поменялся, и значение в нем прежнее:[EBP-8]. Такие фрагменты повторяются несколько раз. Это опять же лишние байты и время.
    Код (Text):
    1. 0040109B  |> 8B45 F8        |MOV EAX,DWORD PTR SS:[EBP-8]
    2. 0040109E  |. 8B4D 08        |MOV ECX,DWORD PTR SS:[EBP+8]
    3. 004010A1  |. 8B1481         |MOV EDX,DWORD PTR DS:[ECX+EAX*4]
    4. 004010A4  |. 8955 F0        |MOV DWORD PTR SS:[EBP-10],EDX
    5. 004010A7  |. 8B45 F8        |MOV EAX,DWORD PTR SS:[EBP-8]




    Или оптимизация подразумевает не уменьшение кода и ускорение работы?
     
  2. Narkomanius

    Narkomanius New Member

    Публикаций:
    0
    Регистрация:
    14 апр 2003
    Сообщения:
    144
    может она отключена?



    кстати ты еще не видел что делает borland c++5.02
     
  3. Narkomanius

    Narkomanius New Member

    Публикаций:
    0
    Регистрация:
    14 апр 2003
    Сообщения:
    144
    там он операцию такого же вида растянул на 8 инструкций.

    MOV EDX,DWORD PTR SS:[EBP-8]

    ADD EDX,1

    MOV DWORD PTR SS:[EBP-8],EDX



    if(*b_ptr<depth){]

    ...

    }

    было что то вроде



    mov eax,[esi]

    mov edx,eax

    mov eax,depth

    cmp eax,edx

    setng al



    mov ebp,eax;

    mov eax,ebp;этм две шли друг за другом!



    test al,al

    jz

    он конечно между ними еще штук 20 инструкций из цикла влепил но....

    короче я после этого и стал учить асм как следует.
     
  4. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    ?cresta

    /G7 -- это единственный ключ, использовавшийся при компиляции ?
     
  5. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    Покажи исходный код на Си/Си++.
     
  6. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Непохоже... я смотрел оптимизированный код много раз (VC++ 6.0) - очень неплохо. Наверное в опциях проблема...



    Narkomanius

    кстати ты еще не видел что делает borland c++5.02



    Ты имеешь в виду Borland хуже или лучше?
     
  7. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    cresta

    Используй хотя бы опцию /Ox



    AsmGuru62

    Борланд по-моему совсем ничего не оптимизирует :)
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    q_q



    Вот исходник на Си: процедура достаточно известная, на мой взгляд (часть процесса сортировки).


    Код (Text):
    1. tblIndex partition(T *a, tblIndex lb, tblIndex ub) {
    2.     item t, pivot;
    3.     tblIndex i, j, p;
    4.    /**********************************
    5.     *  разделение массива a[lb..ub]  *
    6.     **********************************/
    7.     /* Выбираем центр - pivot*/
    8.     p = lb + ((ub - lb)>>1);
    9.     pivot = a[p];
    10.     a[p] = a[lb];
    11.  
    12.     /* сортируем lb+1..ub относительно центра */
    13.     i = lb+1;
    14.     j = ub;
    15.     while (1) {
    16.         while (i < j && pivot>a[i]) i++;
    17.         while (j >= i && a[j]>pivot) j--;
    18.         if (i >= j) break;
    19.         t = a[i];
    20.         a[i] = a[j];
    21.         a[j] = t;
    22.         j--; i++;
    23.     }
    24.  
    25.     /* центр в a[j] */
    26.     a[lb] = a[j];
    27.     a[j] = pivot;
    28.  
    29.     return j;




    green



    Опции компилятора только G7, больше ничего

    cl /G7 minimal.cpp

    link minimal.obj minimal.res /subsystem:windows



    Narkomanius

    Я понимаю, что это все-таки не асм, а яву, но не до такой же степени. Есть ведь минимум три регистра, которые вполне могут заменить локальные переменные, почему не воспользоваться этим, исключив кучу ненужных пересылок.



    Или

    MOV EAX,1

    TEST EAX,EAX

    JE minimal.004010DC

    - нельзя же настолько буквально понимать while(1).

    Это даже противоречит смыслу while
     
  9. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    S_T_A_S_



    С /Ox лучше, код меньше, используются ebx и edi, дурной while исчез, фиксированные адреса сидят постоянно в одном регистре (ecx), размер сократился с 101h до 61h. Практически как в асме написан.



    А тогда вопрос: почему не заложена по умолчанию генерация нормального кода? Всё-таки считается что один из лучших компиляторов...
     
  10. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    /G7 только определяет модель процессора, из которой, в частности, должен исходить компилятор, если включен какой-либо режим оптимизации.
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine


    "нормальный" - понятие весьма субъективное.

    Компилятор с пом. опций позволяет весьма точно задать свойства генерируемого кода.

    И вообще-то в основном приходится компилить без оптимизации, иначе отлаживать очень трудно.

    Так что выбор дефолта оправдан, IMHO
     
  12. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    cresta

    Потому что по умолчанию оптимизаций нет, а ключом /G7 ты только указал процессор, но не сказал ничего оптимизировать. К /Ox можно еще добавить /Oa /vd0 /Qifist(тока нужны они в более серьезных программах), если тока для п4 то и /arch:sse2
     
  13. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    1. Для чего строки
    Код (Text):
    1.  
    2. 00401042  |> B8 01000000    /MOV EAX,1
    3. 00401047  |. 85C0           |TEST EAX,EAX
    4. 00401049  |. 0F84 8D000000  |JE minimal.004010DC


    Используй другой код.
    Код (Text):
    1. ...
    2. do
    3. {
    4.   while (a[i] < pivot) i++;
    5.   while (pivot < a[j]) j--;
    6.  
    7.   if (i <= j)
    8.   {
    9.     t = a[i]; a[i] = a[j]; a[j] = t;
    10.     i++; j--;
    11.   }
    12. } while (i <= j);
    13. ...
     
  14. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Угу, значит к /G7 нужно ещё дополнительно оговаривать ключи.

    А возможны случаи, когда оптимизация не нужна, (ну например она может привести к каким-то ошибкам)?



    q_q

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

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    cresta





    вообще-то да.

    Например, если не-volatile переменная используется несколькими потоками, а компилятор закэшировал её в регистре.

    Или необоснованное применение /Oa - подобных оптимизаций.

    Т.е. в большинстве случаев это ошибки программиста...
     
  16. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    cresta



    Наоборот, я бы сказал /G7 модификатор к ключам оптимизации и влияет только riscification\ciscification т.е. для старых процов он киск инструкции рабивает на несколько риск...