News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Quicker Printf

Started by Twister, August 14, 2010, 05:45:40 AM

Previous topic - Next topic

Twister

Has anyone tried optimizing CRT's printf function? About how much quicker would it be if it used just the m32lib? (szLen, alloc$, ect.)


quick_printf_ proc C lpszFormat:DWORD, nData:VARARG
    pushad
    mov ecx, FUNC(szLen, lpszFormat)
    mov esi, lpszFormat
    mov edi, FUNC(crt_malloc, 5120)
    mov eax, DWORD PTR [lpszFormat]
    xor ebx, ebx

    .WHILE 1
        .BREAK .IF AL == 0
        .IF AL == '%'
            inc eax
           
            .IF AL == 'i'
                mov edx, nData[ebx]
                inc ebx
                push eax
                itoa edx
                pop eax
            .ELSEIF
            .ENDIF
        .ENDIF
        inc eax
        inc edi
    .ENDW

    print edi
    invoke crt_free, edi
    popad
    ret
quick_printf_ endp

jj2007

Eventually, any print function will end up with a call to WriteFile, which is orders of magnitude slower than the cycles you could shave off with some tricks...

clive

I suspect it would be better to use the stack for dynamic storage than malloc/free. If you don't have to deal with threaded or re-entrant behaviour a static buffer would also work more efficiently.

In the vain of JJ's suggestion, the other trick is to print to a very deep buffer and only flush to WriteFile (or stdout abstraction) when you have accumulated a significant amount of data. The sprintf library function permits accumulation to a buffer, you just have to watch the bounds and flush thresholds.

ie str += sprintf(str, fmt, ...);

If speed is of the essence you should move away from a general format processor, and call explicit routines (or inline) to output constant string data, and custom number formats (ie _printf05d, _printf7_4lf, _printf08X, etc)

Using PUSHAD/POPAD seems like overkill for ABI compliant code.
It could be a random act of randomness. Those happen a lot as well.

jj2007

Quote from: clive on August 14, 2010, 12:20:10 PMIn the vain of JJ's suggestion, the other trick is to print to a very deep buffer and only flush to WriteFile (or stdout abstraction) when you have accumulated a significant amount of data.

Writing to a buffer helps if you are printing to a file. The OP prints to the console.

include \masm32\MasmBasic\MasmBasic.inc
Init
Recall "\Masm32\include\Windows.inc", L$(), -1, ct

Open "O", #1, "MyCopy.txt"
push Timer()
For_ n=0 To ct-1
Print #1, L$(n), CrLf$
Next
Close #1
void Timer()
pop edx
Print Str$("Writing to file item by item took %i ms\n", eax-edx)

Open "O", #1, "MyCopy.txt"
push Timer()
Store #1, L$(), ct ; write ct strings to file
Close #1
void Timer()
pop edx
Inkey Str$("Writing to file en bloc took %i ms\n", eax-edx)

push Timer()
For_ n=0 To ct-1
Print L$(n), CrLf$
Next
void Timer()
pop edx
Inkey Str$("Writing to console took %i ms\n", eax-edx)
Exit
end start


Result:
Writing to file item by item took 110 ms
Writing to file en bloc took 31 ms
...
Writing to console took 31640 ms


With some effort, you may come down to 31500 ms :wink