[net.unix-wizards] line buffering in stdio

bobl@aeolus.UUCP (Bob Lewis) (04/26/85)

I just came across some rather interesting behavior in stdio that I think
deserves greater dissemination.  It isn't a bug, but it something that
people should be aware of.

Whenever you have a line-buffered output file, that means that stdio
flushes the buffer whenever (a) the buffer overflows or (b) you output a
newline.

The interesting behavior is in the putc(3S) macro in /usr/include/stdio.h
and in the function _flsbuf() that it calls.  With line buffering, _flsbuf
always resets the file's i/o buffer structure in such a way that putc will
call _flsbuf for every output character sent to it so that _flsbuf can
flush the buffer if that character is a newline.

This means that every time you use putc, it costs a function call.

In particular, note that standard out defaults to line buffering if it's a
tty.

One easy workaround is to disable line buffering.  You can do this by
installing your own buffer via setbuffer(3S), as shown in the program
below.  Interestingly, (in 4.2bsd at least) there is a function
setlinebuf(3S) to enable line buffering, but none to turn it off
explicitly.

A procedure call per character is not trivial.  The program below spends
about 10% of its (VAX 780, 4.2bsd) time in _flsbuf when compiled without
"-DFASTER".  Terminal I/O-bound programs should behave similarly.

	- Bob Lewis
	  ...!tektronix!teklds!bobl

----------------------- cut here ----------------------------
#include <stdio.h>

main()
{
	char buf[64];
	char outbuf[1024];
	int i, j;

#ifdef FASTER
	setbuffer(stdout, outbuf, sizeof(outbuf));
#endif
	for (j = 0; j < 64; j++) {
		for (i = 0; i < 63; i++)
			buf[i] = 'a' + (random() % 26);
		buf[63] = '\n';
		fwrite(buf, 1, 64, stdout);
#ifdef FASTER
		fflush(stdout);	/* be fair and do our own line flushing */
#endif
	}

	exit(0);
}

chris@umcp-cs.UUCP (Chris Torek) (04/29/85)

4.3 has a much larger and grottier putc macro that avoids calling _flsbuf
when an output file is unbuffered.  However, I still favor using setbuf
(not setlinebuf) and calling fflush whenever appropriate.

By the way, in 4.3 stderr is also line buffered.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland