Byte to Hex Chars

Тема в разделе "WASM.A&O", создана пользователем xdev86_, 3 окт 2006.

  1. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    Доброе время суток. Необходима функция, которая преобразует байт в строку(2 hex символа), к примеру 0xAA -> "AA\0". Я сделал так:

    Код (Text):
    1. section '.text' code readable executable
    2.  
    3.  public ByteToChar as '@ByteToChar@4'
    4.  
    5.  ByteToChar:
    6.         mov     esi,hexTable
    7.         mov     edi,strBuf
    8.  
    9.         xor     ebx,ebx
    10.         mov     bl,cl
    11.         and     bl,0xF0
    12.         shr     bl,4
    13.         mov     al,[esi+ebx]
    14.  
    15.         mov     bl,cl
    16.         and     bl,0x0F
    17.         mov     ah,[esi+ebx]
    18.  
    19.         mov     [edi],ax
    20.  
    21.         mov     eax,strBuf
    22.         ret
    23.  
    24. section '.data' data readable writeable align 16
    25.  hexTable db "0123456789ABCDEF",0
    26.  strBuf   dd 0
    В результате получил ~17500 тактов (PentiumD930) на 1024 байт, ~17 тактов на байт. Как можно улучшить данный код?
     
  2. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    на разных процах разный результат будет, можно только ориентироваться на "больше-меньше"

    Твой вариант дает 8 тиков (тестилкой от bogrus)

    такой вариант дает 4 тика (в масм-синтаксисе):

    Код (Text):
    1.     mov     eax,offset strBuf
    2.     movzx   edx,cl
    3.     and     ecx,0Fh
    4.     shr     edx,4
    5.     movzx   ecx,byte ptr[hexTable+ecx]
    6.     movzx   edx,byte ptr[hexTable+edx]
    7.     mov     [eax+1],cl
    8.     mov     [eax],dl
    регистров меньше используется - не надо сохранять esi edi ebx.

    P.S.
    а если расположить инструкции в несколько ином порядке, то получается вообще 3 тика (за счет экономии на ожидании результата)

    Код (Text):
    1.     movzx   edx,cl
    2.     and     ecx,0Fh
    3.     shr     edx,4
    4.     mov     eax,offset strBuf
    5.     movzx   ecx,byte ptr[hexTable+ecx]
    6.     movzx   edx,byte ptr[hexTable+edx]
    7.     mov     [eax+1],cl
    8.     mov     [eax],dl
     
  3. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    Превосходно! :) Большое спасибо! :)

    Решил тоже прогнать тестом bogrus'a, и получил интересные результаты:

    1) AMD Athlon (на работе машина)
    Мой вариант: 8 тактов
    cresta (1й вариант): 4 такта
    cresta (2й вариант): 3 такта(!), замечательно :)

    2) Pentium MMX
    Мой вариант: 18-20 (чередуется)
    cresta (1й вариант): 33-35 тактов (чередуется)
    cresta (2й вариант): 32-34 такта (чередуется)

    3) PentiumD (всеми любимый netbusrt)), перед тестом вызываю SetProcessAffinityMask)
    Мой вариант: 540 тактов (это как так???)
    cresta (1й вариант): 945 тактов
    cresta (2й вариант): 975 тактов

    Если тестировать из C-проги то получается так:
    Мой вариант: ~17560 тактов на 1024 байт
    cresta (1й вариант): ~16800 тактов на 1024 байт
    cresta (2й вариант): ~17200 тактов на 1024 байт


    Теперь вопрос: Почему так? :) Почему на netburst'e такие результаты странные, и почему тест bogrus'a выдает так много тактов, когда прога на C++ вызывает функцию 1024 раза, и получается не >17000 тактов? Что-то я ничего не понимаю...


    А вот на такую последовательность
    pxor mm3,mm6
    paddb mm3,mm6
    psubd mm6,mm3
    тест выдает:
    2805
    0
    15
    0
    0
    15
    0
    15
    0
    0

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

    А если переместить переменную и таблицу в секцию '.data' то результаты вообще такие:
    75
    остальное - нули.... Интересные фокусы....
     
  4. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    у меня Athlon XP 2400, под него я и попытался сделать быстрее (твой тест тоже подтверждает это). Что для атлона хорошо - для пня смерть :)
    Чтобы сделать быстро на пне, или какой-то универсальный (компромиссный) вариант, нужно несколько разных процессоров. У меня их нет :dntknw:
    Чтобы добиться скорости везде, надо в первую очередь оптимизировать алгоритм, а не набор инструкций, которыми он реализован. А функция у тебя простейшая, особо с алгоритмами не развернешься.
    Если эта процедура настолько критична, делай два разных кода под разные процы, и вызывай тот или иной в зависимости от процессора.
    И когда вызываешь из Си-проги процедуру, как ты учитываешь время на организацию самого вызова? Одна только пара call/ret будет больше времени занимать, чем собственно сам код перевода числа в строку. Может не надо её отдельной функцией?

    Моя асмовая тестилка затерялась в дебрях винта, вот приаттачиваю сишную, посмотри, как устроена. Всё инлайн, никаких вызовов функций. Эта тестилка показывает 5 тиков. Почему у тебя сишный показывает 16 - не знаю, смотри свой код, сравнивай с аттачем.
     
  5. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    Спасибо, сейчас потестирую.... Сишная показывает ~240-255 тактов в Debug'e и 30-45 в Release'e... Что с результатами такое? Почему они везде разные? (я не про Debug и Release, а вообще). В тесте bogrus'a, к примеру бывает, что блок выполняется за 0 тактов.... Что это вообще происходит? )
     
  6. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    трудно сказать, почему у тебя нули. Тот mmx-код, который ты привел, показывает устойчиво 7 тиков, как в асм-тестилке bogrus'a, так и в моей сишной (из аттача).
    Может, какие-нибудь некорректности в коде приводят к каким-то исключительным ситуациям? Я с mmx никогда не работал, не знаю...
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    xdev86_
    Это ваши совместные фокусы с Intel Corp. ;)
    Фокус №1. В NetBurst запись в секцию кода в одном килобайте с исполняемым кодом приводит к сбросу Т-кэша и ес-но к большим штрафам. По видимому этим объясняются твои 500-900 тиков на Pentium D - кури мануалы и без особой необходимости ничего не пиши в секцию кода ;)
    Фокус №2 - недокументированный, но подтверждаемый на практике. RDTSC выдает результаты с дискретом: 4 тика на первых моделях P4, 8 тиков на P4E и 15 тиков в Pentium D (да еще и скачет на +-15 если включены оба ядра). Поскольку у тебя задержка меньше 15 и второе ядро ты не отключал, то и получаешь болтанку между 0 и 15
     
  8. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    OK, спасибо, теперь понятно. Я когда перенес в секцию данных оно стало нули показывать :) Теперь ясно почему. Я теперь замеряю время 100 вызовов, и просто получает среднее арифметическое. Только не понимаю, зачем нужно было так rdtsc уродовать?

    ЗЫ: Все-таки какие-то кривые эти p4. Мне P6 всегда больше нравилась...
     
  9. MikDay

    MikDay New Member

    Публикаций:
    0
    Регистрация:
    5 май 2005
    Сообщения:
    32
    Адрес:
    Minsk
    Интересно, какую скорость покажет такой вариант:

    add al,90h
    daa
    adc al,40h
    daa
    mov strBuf+1,al
    add al,90h
    daa
    adc al,40h
    daa
    mov strBuf,al
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    MikDay
    Черепашью ;) На атлонах одна DAA кушает 7-8 тактов, а на P4, если верить Фогу, от 29 до 100 тиков в завис-ти от модели
     
  11. masquer

    masquer wasm.ru

    Публикаций:
    0
    Регистрация:
    13 сен 2002
    Сообщения:
    890
    Адрес:
    Николаев
    xdev86_
    не знаю как ты там меряешь, на х2 твой код показал 15, варианты cresta 4 и 3 соотв. MikDay - 24 (все в тактах ес-но)
     
  12. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    Я писал выше, как и чем я меряю, и почему у меня такие результаты. И что такое есть x2, Athlon X2? Что-то много, 15 тактов... Так же интересно посмотреть на твой метод тестирования.
     
  13. MikDay

    MikDay New Member

    Публикаций:
    0
    Регистрация:
    5 май 2005
    Сообщения:
    32
    Адрес:
    Minsk
    Приведенный мной алгоритм был когда-то в BIOS старых компьютеров.
    Вероятно там упор был не на скорость, а на минимальный код. Выглядел он
    приблизительно так:

    hex proc
    push ax
    shr al,4
    call hex2
    pop ax
    and al,0Fh
    hex2 proc
    add al,90h
    daa
    adc al,40h
    daa
    mov ah,0Eh
    int 10h
    ret
    hex2 endp
    hex endp

    Я, кстати, сделал ошибки в своем примере - не выделил старшую тетраду.
     
  14. xdev86_

    xdev86_ New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2006
    Сообщения:
    13
    Интересный вариант :) Попробую разобраться, как он работает.
     
  15. masquer

    masquer wasm.ru

    Публикаций:
    0
    Регистрация:
    13 сен 2002
    Сообщения:
    890
    Адрес:
    Николаев
    профилировщик (с) Maverick

    я не смотрел как именно bogrus сделал профилировщик, но не может быть разница на порядок, согласись. Да, х2 это атлон х2.