printf disadvantages?

Started by
16 comments, last by Antheus 12 years, 6 months ago

I was ouputting from many points in my physics calcs per frame and my fps chunked down hard. the enitre game slowed considerably. it may have also been extra memory allocations occurring to field the ever expanding list of string forming console history.


If the buffer gets filled printf and cout << will block until everything is printed, printing to a console window or file might require a context switch(someone with more knowledge should know this i guess) (which is fairly expensive),

With C++ you can obtain the streambuf object for your stream by using the rdbuf method and then replace the buffer with a larger one by using the pubsetbuf method on the streambuf object.
With C you can use setvbuf to change buffering mode on stdout to full buffering (standard is usually line buffering which means it pushes it out once a newline occurs) and setbuf to change the buffer to a larger one if needed.

Also, remember that in C++ std:endl flushes the buffer aswell, use \n instead to avoid it if you want to buffer more than one line.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Advertisement
I worked for a company in the early Windows days (windows 1 ) that was actually a DOS program (with Tesseract for thread switching)
and they didnt want any printf in the program as it WAS a performance driven real time system (multiple phone audio app) and
we used strcpy() strcat() and itoa() in its place. Just had to do the equivalent of what the printf did. If I had been more experienced at
that time I probably would have made C macros to make it easier.

Interpretation always adds more CPU work even as simple as printf's interpretor is
--------------------------------------------[size="1"]Ratings are Opinion, not Fact
Did you have some reason for not just using sprintf()? I have a hard time believing your hand-rolled solution based on strcat() of all things could outperform a decent library implementation of sprintf().

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I think he meant replacing:

printf("Hello %s stuff %d.\n", someString, someNumber);

With something like (forgive my C, it may be rusty):

char buffer[N] = "Hello ";
char *pointer = buffer;
char intBuf[M];

pointer = strcat(pointer, someString);
pointer = strcat(pointer, " stuff ");
itoa(intBuf, someNum, M);
pointer = strcat(pointer, intBuf);
strcat(pointer, ".\n");

// Output "buffer"

Essentially, it sounds like the printf formatting logic was inlined into every call site.


Interpretation always adds more CPU work even as simple as printf's interpretor is
[/quote]
Doing something is always slower than doing nothing, certainly. I could see how such a level of optimisation would be necessary for a real time system like the phone system described, but it is unlikely to be the bottleneck, or even particularly problematic, in the OP's case.

It must be noted that hard-coding these things does not allow an application to have the string format externalised (and then internationalised/localised), which can end up being a bigger concern than performance for many commercial applications.
Either way, a decent (even a naive) implementation of the printf() family (including sprintf) would handily beat that. You have 4 calls to strcat() alone, which means walking the output string 4 times to find its length, strip the null terminator, then copy the new data to the end of the string; even a good strcat() implementation is going to struggle to beat a single pass through the input format specifier and a single pass at constructing the output buffer.

There are ways to make this faster, such as not using strcat() or itoa() and basically reimplementing sprintf() at every call site as you allude to, but that's just begging for binary code bloat and is likely not going to be any faster than a decent function call.


This kind of thing is why "optimizing" code without profiling evidence to prove that you're doing the right thing is generally very, very unwise.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Either way, a decent (even a naive) implementation of the printf() family (including sprintf) would handily beat that. You have 4 calls to strcat() alone, which means walking the output string 4 times to find its length, strip the null terminator, then copy the new data to the end of the string; even a good strcat() implementation is going to struggle to beat a single pass through the input format specifier and a single pass at constructing the output buffer.
[/quote]
Whoops. I was trying to do as described here, but I forgot that regular strcat() does the retarded thing (I warned you my C was rusty!).
Was fairly simple error/log string building wih static buffers and very few string variable appending to other strings (thus fixed offsets in the string buffers could be hard coded)

char strx[100];
strcpy(strx, "the error number is ");
itoa( varx, &strx[20], 10); // will end with its own null termiantor...

strx sent to output call for that buffer to file or whereever (often an internal debug msg stack)


so not all that many sub calls
and it skips the interpretation of that base string char by char done by printf or sprintf

its so long ago I forget if I did memcpy instead of strcpy
--------------------------------------------[size="1"]Ratings are Opinion, not Fact
A while back I was dealing with pushing throughput of text output as far as I could for a text processing app.

In rough order fwrite < printf < iostream::write < cout.

In all cases, buffer size was crucial. Depending on output target (disk/memory), the overall cost of performing IO was orders of magnitude more expensive than any formatting. I ended up with buffers going up to 64 megabytes that would be dumped to output in single IO. The buffers were written to using sprintf. cout/basic_stream was always inferior due to occasional heap allocation of passed arguments.


For comparison, IO devices are limited by IO operations per second, even SSDs. Highest end SSDs reach some 100k IOPS. Rotary drives reach 10k tops. Console tends to have huge overhead as well.

We also had a discussion about this.

For comparison, sprintf has no problem formatting data comparable to memory bandwidth, so gigabyte per second is perfectly fine.

tl;dr; printf or cout doesn't matter, buffer size limit throughput, might be necessary to buffer several megabytes before reaching limits on desktop systems.

I also remember once dabbling in a templated printf that would resolve format and generate layout at compile time. In assembly, things ended looking like this:fancy_cout << 1234;
// in assembly
buffer[0] = 1;
buffer[1] = 2;
buffer[2] = 3;
buffer[3] = 4;
Don't remember where things eventually broke down and why. Maybe it even worked I just decided it was too much magic going on. Either way, it was never the bottleneck.

This topic is closed to new replies.

Advertisement