Because of stdin and stdout buffering sometimes printf, scanf and getchar are not executed. I usually flush output buffer using fflush(stdout) but code can become very unreadable because of that. If I set stdin and stdout unbuffered using setbuf(stdin, NULL) and setbuf(stdout, NULL) will I make my program perform better or worse?
In C, file output is block buffered. Output to stdout is line buffered. The stderr device is unbuffered.
Default Buffering modes: stdin is buffered (line buffering doesn't affect stdin) stdout is buffered (line buffered if connected to a terminal) stderr is unbuffered.
Use fflush(FILE *stream) with stdout as the parameter. This does not turn off buffering, it flushes the buffer once.
The main reason why buffering exists is to amortize the cost of these system calls. This is primarily important when the program is doing a lot of these write calls, as the amortization is only effective when the system call overhead is a significant percentage of the program's time.
Making stdin or stdout completely unbuffered can make your program perform worse if it handles large quantities of input / output from and to files. Most I/O requests will be broken down as system calls on a byte by byte basis.
Note that buffering does not cause printf, scanf and getchar to not be executed: printf output to the final destination can just be delayed, so the input operation via scanf or getchar may occur without a prompt.
Note also that setting intput as unbuffered may not be effective from the terminal because the terminal itself performs its own buffering controlled via stty or ioctl.
Most C libraries have a hack that causes stdout to be flushed when reading from stdin requires getting data from the system, but this behavior is not specified in the C Standard, so some libraries do not implement it. It is safe to add calls to fflush(stdout); before input operations, and after transitory messages such as progress meters. For most purposes, it is best to let the C startup determine the appropriate buffering strategy depending upon the type of system handle associated with the stdin and stdout streams. The common default is line buffered for devices and fully buffered with a size of BUFSIZ for files.
To get an idea of the potential performance hit, compile this naive ccat program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int c, size;
if (argc > 1) {
if (!strcmp(argv[1], "BUFSIZ"))
size = BUFSIZ;
else
size = strtol(argv[1], NULL, 0);
if (size == 0) {
/* make stdin and stdout unbuffered */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
} else
if (size > 0) {
/* make stdin and stdout fully buffered */
setvbuf(stdin, NULL, _IOFBF, size);
setvbuf(stdout, NULL, _IOFBF, size);
} else {
/* make stdin and stdout line buffered */
setvbuf(stdin, NULL, _IOLBF, -size);
setvbuf(stdout, NULL, _IOLBF, -size);
}
}
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}
Time program execution copying a large file several times to minimize file caching side effects.
On a Debian linux box I get these timings for a 3.8MB text file:
chqrlie@linux:~/dev/stackoverflow$ time wc w
396684 396684 3755392 w
real 0m0.072s
user 0m0.068s
sys 0m0.000s
chqrlie@linux:~/dev/stackoverflow$ time cat < w > ww
real 0m0.008s
user 0m0.000s
sys 0m0.004s
chqrlie@linux:~/dev/stackoverflow$ time ./ccat < w > ww
real 0m0.060s
user 0m0.056s
sys 0m0.000s
chqrlie@linux:~/dev/stackoverflow$ time ./ccat 0x100000 < w > ww
real 0m0.060s
user 0m0.058s
sys 0m0.000s
chqrlie@linux:~/dev/stackoverflow$ time ./ccat 0 < w > ww
real 0m5.326s
user 0m0.632s
sys 0m4.684s
chqrlie@linux:~/dev/stackoverflow$ time ./ccat -0x1000 < w > ww
real 0m0.533s
user 0m0.104s
sys 0m0.428s
As you can see:
stdin and stdout to unbuffered causes the program to slow down by a factor of almost 100,cat utility uses faster APIs for 6 times faster execution times.As a conclusion: do not set stdin and stdout to unbuffered, it will impact performance significantly for even moderately large files.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With