Ассемблерный код работает медленнее сишного!

Тема в разделе "WASM.A&O", создана пользователем Adrax, 30 сен 2007.

  1. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    считать в hex и переводить в десятичную систему будет быстрее, чем считать сразу в десятичной.
    1 000 000 000?
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    а деление через умножение не лучше ли сделать?
    http://wasm.ru/article.php?article=1010028
     
  3. AndNot

    AndNot New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2007
    Сообщения:
    49
    Adrax, может объяснишь нам дуракам, в чем проблема? Скомпилил я код, который ты выдрал с VC++ (он находится здесь, просто тогда времени совсем не было разбираться http://forum.sources.ru/index.php?showtopic=201879 ). Сравнил с тем, что я выложил здесь. Сишный вариант оказался в 1.8 раз медленнее, считай как и Борландовский вариант, поскольку оптимизация у них еще та :lol: Так с чего ты взял, что он быстрее???
    Было бы лучше, если бы не нужен был остаток от деления, а его так просто не получишь ;)
     
  4. Mikl_

    Mikl_ New Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2006
    Сообщения:
    907
    AndNot
    Нахождение остатка от деления X на 10 используя умножение
    Код (Text):
    1. mov eax,X
    2. mov edi,eax;сохраняем X
    3. mov edx,1999999Ah;умножаем на 2^32/10
    4. mul edx;в edx частное
    5. lea edx,[edx+edx*4];умножаем edx на 5
    6. add edx,edx;умножаем edx на 2, теперь edx=edx*10
    7. sub edi,edx;в edi остаток
    8. sbb edx,edx;коррекция остатка для X>40000004h
    9. and edx,10;если edi<0, тогда edx=10 иначе edx=0
    10. add edi,edx;в edi скорректированный остаток
     
  5. AndNot

    AndNot New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2007
    Сообщения:
    49
    Что то подсказывает мне, что получится тот же вариант, что и с заменой условных переходов, т.е. ничего не даст, поскольку инструкций море и каждая зависит от предыдущей.
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    А вот так делит на 10 компилятор VC8:
    Код (Text):
    1. mov ecx, X
    2. mov eax, 1717986919            
    3. imul    ecx
    4. sar edx, 2
    5. mov eax, edx
    6. shr eax, 31
    7. add eax, edx ; результат в eax
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    можно эффективнее =)
    у фога как раз пример есть на 10.
     
  8. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    n0name
    Беззнаковое деление на 10 по VC:
    Код (Text):
    1. mov eax, -858993459
    2. mul X
    3. shr edx, 3
    4. mov eax, edx ; результат в eax
     
  9. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    угу, помнится так и было.
     
  10. Adrax

    Adrax Алексей

    Публикаций:
    0
    Регистрация:
    14 окт 2006
    Сообщения:
    135
    Адрес:
    г. Курск
    Уважаемые программисты!
    Прошу прощения, что давно не появлялся в этой теме, начатой мной же самим

    2 AndNot
    У меня ассемблерный вариант оказался медленнее сишного - потому и встал вопрос низкоуровневой оптимизации. Неужели, код получился настолько процессорозависимым, что на одном проце обгоняет сишный, а на другом - безбожно отстаёт?

    И ещё... Ваш код намного компактнее и продуманнее моего, но пытаясь его использовать, я столкнулся с проблемой: проверка на минус, 0, 1 проходит нормально, а любое другое число даёт один и тот же результат 2009262131 (т.е. вообще цикл не выполняется, тупо выдаётся значение какой-то ячейки)
    Исходник вот:
    Код (Text):
    1. format PE console
    2. include 'win32axp.inc'
    3. .data
    4.         dllka db 'msvcrt.dll',0
    5.         name1 db 'scanf',0
    6.         scanf dd ?
    7.         name2 db 'printf',0
    8.         printf dd ?
    9.         inp db 'Input N:',0
    10.         d db '%d',0
    11.         d4 db '%04d',0
    12.         crlf db 13,10,0
    13.         N dd ?
    14.  
    15.         array dw 1
    16.               dw 999999 dup 0
    17.  
    18. .code
    19. fuck:
    20.         xor edi,edi
    21.         xor ecx,ecx
    22.         xor esi,esi
    23.         inc ecx
    24.         inc esi
    25.         mov ebp,2710h
    26.  
    27.         invoke LoadLibrary,dllka
    28.         push eax
    29.         invoke GetProcAddress,eax,name1
    30.         mov [scanf],eax
    31.         pop eax
    32.         invoke GetProcAddress,eax,name2
    33.         mov [printf],eax
    34.         cinvoke printf,inp
    35.         cinvoke scanf,d,N
    36.  
    37.         mov eax,[N]
    38.         test eax,eax
    39.         jl konets
    40.  
    41.         dec eax
    42.         test eax,eax
    43.         jle mtk1
    44.  
    45.         _loop:
    46.                 xor ebx,ebx
    47.  
    48.         _do:
    49.                 movzx eax,word[array+ebx*2]
    50.                 imul ecx
    51.                 add eax,edi
    52.                 xor edx,edx
    53.                 div ebp
    54.                 inc ebx
    55.                 mov edi,eax
    56.                 mov word[array+ebx*2-2],dx
    57.                 cmp ebx,esi
    58.                 jb _do
    59.                 or eax,eax
    60.                 jnz _do
    61.                 inc ecx
    62.                 mov esi,ebx
    63.                 cmp ecx,[N]
    64.                 jbe _loop
    65.  
    66. mtk1:
    67.         dec esi
    68.         movzx eax,word [array+esi*2]
    69.         cinvoke printf,d,eax
    70.         jz konets
    71.  
    72. mtk2:
    73.         dec esi
    74.         movzx ecx,word[array+esi*2]
    75.         cinvoke printf,d4,ecx
    76.         test esi,esi
    77.         jnz mtk2
    78.  
    79. konets:
    80.         cinvoke printf,crlf
    81.         invoke ExitProcess,0
    82. .end fuck
    Если ошибка очевидна, а я её не нашёл - не бейте ногами, пожалуйста. Просто сейчас на кофеиновом марафоне, пару суток вообще не спал, оттого могу тупить, сам того не осознавая
     
  11. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    После invoke значение ecx портится.
    А вообще неплохо бы иметь оталдчик.

    [+]
    флаги тоже портятся:
    Код (Text):
    1. mtk1:
    2.         dec esi
    3.         movzx eax,word [array+esi*2]
    4.         cinvoke printf,d,eax
    5.         jz konets
     
  12. Adrax

    Adrax Алексей

    Публикаций:
    0
    Регистрация:
    14 окт 2006
    Сообщения:
    135
    Адрес:
    г. Курск
    2 KeSqueer
    Огромное спасибо!
    Чёрт побери, я и забыл, что кроме eax что-то может меняться:)
     
  13. AndNot

    AndNot New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2007
    Сообщения:
    49
    Adrax, скачай с этого сайта Олю, проблем не будешь знать. Очень удобный отладчик, да еще и установки не требует.
     
  14. Adrax

    Adrax Алексей

    Публикаций:
    0
    Регистрация:
    14 окт 2006
    Сообщения:
    135
    Адрес:
    г. Курск
    2 AndNot
    Олькой и дебажу...
    Просто в этот раз конкретно протупил
     
  15. Adrax

    Adrax Алексей

    Публикаций:
    0
    Регистрация:
    14 окт 2006
    Сообщения:
    135
    Адрес:
    г. Курск
    2 All
    Ё ммоё!Сейчас стал перемерять скорость выполнения скомпиленных экзешников, вычисляя 150000! (AMD64 2800+XP S-754 1024Mb-DDR400 WinXP SP1 Pro)
    Сишный код (из первого поста) выполняется за 5:41
    Ассемблерный по советам AndNot
    Код (Text):
    1. format PE console
    2. include 'win32axp.inc'
    3. .data
    4.         dllka db 'msvcrt.dll',0
    5.         name1 db 'scanf',0
    6.         scanf dd ?
    7.         name2 db 'printf',0
    8.         printf dd ?
    9.         inp db 'Input N:',0
    10.         d db '%d',0
    11.         d4 db '%04d',0
    12.         crlf db 13,10,0
    13.         N dd ?
    14.  
    15.         array dw 1
    16.               dw 999999 dup 0
    17.  
    18. .code
    19. fuck:
    20.         invoke LoadLibrary,dllka
    21.         push eax
    22.         invoke GetProcAddress,eax,name1
    23.         mov [scanf],eax
    24.         pop eax
    25.         invoke GetProcAddress,eax,name2
    26.         mov [printf],eax
    27.         cinvoke printf,inp
    28.         cinvoke scanf,d,N
    29.  
    30.         mov eax,[N]
    31.         test eax,eax
    32.         jl konets
    33.  
    34.         xor edi,edi
    35.         xor ecx,ecx
    36.         xor esi,esi
    37.         inc ecx
    38.         inc esi
    39.         mov ebp,2710h
    40.  
    41.         dec eax
    42.         test eax,eax
    43.         jle mtk1
    44.  
    45.         _loop:
    46.                 xor ebx,ebx
    47.  
    48.         _do:
    49.                 movzx eax,word[array+ebx*2]
    50.                 imul ecx
    51.                 add eax,edi
    52.                 xor edx,edx
    53.                 div ebp
    54.                 inc ebx
    55.                 mov edi,eax
    56.                 mov word[array+ebx*2-2],dx
    57.                 cmp ebx,esi
    58.                 jb _do
    59.                 or eax,eax
    60.                 jnz _do
    61.                 inc ecx
    62.                 mov esi,ebx
    63.                 cmp ecx,[N]
    64.                 jbe _loop
    65.  
    66. mtk1:
    67.         movzx eax,word [array-2+esi*2]
    68.         cinvoke printf,d,eax
    69.         mov edi,esi
    70.         dec edi
    71.         jz konets
    72.  
    73. mtk2:
    74.         dec edi
    75.         movzx ecx,word[array+edi*2]
    76.         cinvoke printf,d4,ecx
    77.         test edi,edi
    78.         jnz mtk2
    79.  
    80. konets:
    81.         cinvoke printf,crlf
    82.         invoke ExitProcess,0
    83. .end fuck
    выполнился за 5:38

    А вот этот
    Код (Text):
    1. format PE console
    2. include 'win32axp.inc'
    3. .data
    4.         dllka db 'msvcrt.dll',0
    5.         name1 db 'scanf',0
    6.         scanf dd ?
    7.         name2 db 'printf',0
    8.         printf dd ?
    9.         inp db 'Input N:',0
    10.         d db '%d',0
    11.         d4 db '%04d',0
    12.         crlf db 13,10,0
    13.         N dd ?
    14.         len dd 1
    15.  
    16.         array dw 1
    17.               dw 999999 dup 0
    18.  
    19. .code
    20. fuck:
    21.         invoke LoadLibrary,dllka
    22.         push eax
    23.         invoke GetProcAddress,eax,name1
    24.         mov [scanf],eax
    25.         pop eax
    26.         invoke GetProcAddress,eax,name2
    27.         mov [printf],eax
    28.         cinvoke printf,inp
    29.         cinvoke scanf,d,N
    30.  
    31.         mov ebx,[N]
    32.         test ebx,ebx
    33.         jl konets
    34.  
    35.         mov edi,[len]
    36.         xor esi,esi
    37.         inc esi
    38.         xor eax,eax
    39.         cmp ebx,esi
    40.         jb mtk1
    41.  
    42.         mtk0:
    43.                 xor ecx,ecx
    44.  
    45.         mtk:
    46.                 movzx edx,word [array+ecx*2]
    47.                 imul edx,esi
    48.                 add eax,edx
    49.                 xor edx,edx
    50.                 mov ebp,2710h
    51.                 div ebp
    52.                 mov word[array+ecx*2],dx
    53.                 inc ecx
    54.                 cmp ecx,edi
    55.                 jb mtk
    56.                 test eax,eax
    57.                 jnz mtk
    58.                 inc esi
    59.                 cmp esi,ebx
    60.                 mov edi,ecx
    61.                 jbe mtk0
    62.                 mov [len],edi
    63.  
    64. mtk1:
    65.         movzx eax,word [array-2+edi*2]
    66.         cinvoke printf,d,eax
    67.         mov esi,[len]
    68.         dec esi
    69.         jz konets
    70.  
    71. mtk2:
    72.         dec esi
    73.         movzx ecx,word[array+esi*2]
    74.         cinvoke printf,d4,ecx
    75.         test esi,esi
    76.         jnz mtk2
    77.  
    78. konets:
    79.         cinvoke printf,crlf
    80.         invoke ExitProcess,0
    81. .end fuck
    выполнился за 5:27, став чемпионом по скорости!

    А теперь объясните мне, почему так? Ведь последний исходник реально коряв (честно - я выдрал его из дизасма сишного кода с минимальными изменениями), там даже присвоение в цикле выполняется! Так почему оптимизированный вариант проигрывает корявому?
     
  16. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    хз, у меня сишный (msvc 2005) в два раза быстрее выполняется. Машина пень celeron 2ghz
     
  17. AndNot

    AndNot New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2007
    Сообщения:
    49
    Adrax, я же говорил, что это неоптимизированный вариант. Замени:
    Код (Text):
    1. imul ecx
    на
    Код (Text):
    1. imul eax, ecx
    Скорость возрастет.
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    vc++ 7.0 делает достаточно быстрый код, чтобы его обогнать, косметических улучшений типа замены imul ecx на imul ecx,eax недостаточно.
    Переводя "в лоб" код на ассемблер, практически всегда будет получаться чуть более медленный код, чем прототип.
    Чтобы достичь реального прироста, нужно оптимизировать алгоритм, а не способ его реализации.

    Может, стоит посмотреть, как калькулятор считает факториал?
    На моей (гораздо проще, чем AMD64 2800+XP S-754 1024Mb) машине calc.exe считает факториал 150000 за 4:40.
    Для сравнения код из поста №1 считает за 6:05.
     
  19. Adrax

    Adrax Алексей

    Публикаций:
    0
    Регистрация:
    14 окт 2006
    Сообщения:
    135
    Адрес:
    г. Курск
    2 cresta
    В том-то и дело, что calc.exe использует аппроксимирующие формулы. Там гамма-функция Эйлера используется: калькулятор даёт 32 первых цифры результата, десятичный его порядок и может вычислять факториала дробных чисел
    А мне нужен точный результат. Потому алгоритм только один - "умножение в лоб". Весь вопрос в том, как его максимально оптимизировать...
     
  20. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Может стоит поискать какую-нибудь либу для работы с длинными числами?

    С кода в первом посте можно скинуть 5% времени, перейдя от
    unsigned short array[1000000] = {1};
    к
    unsigned int array[1000000] = {1};
    Думаю, это распространяется и на асм-клоны.