Testbug's speed tests

Comparing ASM and other functions

Writing decimal
These tests were set up to compare the speed of various methods of converting a 32 bit number to a decimal string for writing to the screen. [For methods of converting 64 bit numbers to a decimal string see also FPU v CPU speeds]. Here two different methods using assembler are compared with one of the Win32 APIs, wsprintfA. On my machine wsprintfA works quickly when doing this particular job (although it is much slower when writing hex - see writing hex with leading zeroes). This is one of those handy APIs which you can call in Win32 and which have the same names as some "C" functions and which save a lot of coding.
Each of the assembler methods rely on the usual way of converting to ascii by dividing by 10, taking the remainder, adding 48 to convert to ascii, reversing the string and then writing to the screen. The only difference between the assembler versions is the method used to reverse the string. The first, DECWRITE, just runs back down the list re-writing it in the correct place. The second procedure DECWRITE2 is a variation on this as it puts each digit on the stack and then peels them off again in reverse order. The stack is a handy tool here as it naturally reverses the order of the data when PUSH and POP are used. The processor is optimised to write data to the stack and to read data from the stack, so this second procedure is likely to win on speed.
In each case the number in eax is 75EC9310h, and the procedure is carried out 1,000 times. The time output in tick counts is measured using QueryPerformaceCounter.

Here is the first assembler procedure (reversing of digits done by reading memory):-

DECWRITE:         ;write decimal number in EAX to [EDI]
MOV EBX,EDI       ;save start point
XOR EDX,EDX
MOV ECX,10        ;ready for each divide by 10
L20:
DIV ECX           ;div edx:eax by 10 = quot in eax, rem in edx
ADD DL,48         ;convert remainder to ascii
MOV [EDI],DL
INC EDI
XOR EDX,EDX       ;zero edx
CMP EAX,EDX       ;see if any more to do
JNZ L20           ;yes
PUSH EDI          ;now reverse the order of the digits save one after end
L22:
DEC EDI           ;ready for next to do
CMP EDI,EBX       ;see if met in middle yet
JNA >L23          ;yes
MOV AL,[EDI]      ;get digit to move
XCHG [EBX],AL     ;insert it and get other
MOV [EDI],AL      ;insert other moved digit was
INC EBX           ;ready for next to do
JMP L22
L23:
POP EDI           ;return with edi at one after end
RET
Here is the second assembler procedure (reversing of digits done by peeling off the stack in reverse order):-
DECWRITE2:              ;write decimal number in EAX to [EDI]
XOR EDX,EDX
XOR ECX,ECX             ;used as a counter
MOV EBX,10
L30:
DIV EBX                 ;div edx:eax by 10 = quotient in eax, remainder in edx
PUSH EDX                ;keep result on the stack
INC ECX                 ;count how many are done
XOR EDX,EDX
CMP EAX,EDX             ;see if any more to do
JNZ L30                 ;yes
L31:                    ;now reverse the order of the digits
POP EAX                 ;peel one off from the stack
ADD AL,48               ;convert to ascii
STOSB                   ;write to memory
LOOP L31                ;continue till all done
RET
And here is the very simple API which can be used instead. Unfortunately it does require a control string to be declared as follows:-
DCONTROL_STRING DB '%lu',0
this control string instructs the function to write in decimal
MOV EAX,75EC9310h
MOV EDI,ADDR BUFFER
PUSH EAX                ;send number to be written as an argument
PUSH ADDR DCONTROL_STRING     ;control input
PUSH EDI                ;address of output string
CALL wsprintfA
ADD ESP,12D             ;this is required for this API but most unusual in Win32