Before I get any further, just to answer the question in the subject
line (i.e., "are system calls sometimes costlier than library
calls"), the short answer is "yes". Of course, we also have to
define "system" vs "library" calls, and the short answer is useless,
because "sometimes" is not "always" and this does not really tell
us anything about any *particular* calls: a call to foo() may be
100 times slower than one to bar(), regardless of whether foo()
and/or bar() are "system calls" (whatever those are!).
On Tue, 06 Nov 2007 12:26:25 -0800, omkar pangarkar wrote:
I have two simple hello world programs one using printf()[a
library func] and other using write() [syscall] ...
then later added this clarification:
Well, if you code one call to printf(), and one to write(), then
*you* are behind it, and it is happening because that is what you
wrote.
If the question is "when and why does printf() choose to call the
underlying OS's `write' system call"...
as others have noted, [the system's stdio library] does buffering,
and may choose to write output in larger chunks than what is
initially passed to it.
I suspect, at least in the case of printf, that this buffering is usually
done until either:
the buffer is full;
a newline or similar is encountered.
The C Standard allows, but does not require, an implementation to
do this sort of buffering. The C Standard *does* require that the
library "transmit" buffered data to the "host environment" under
various conditions, including (but not limited to):
- printing a newline to a line-buffered stream;
- various calls to fflush().
Any given stdio implementation may choose not to do any buffering
at all, which will trivially satisfy these requirements. Most real
implementations at least do *some*, because the "transmission to
the host environment" is done with something that has some extra
overhead (e.g., a "system call").
On host systems that provide some kind of protection -- so that an
"ordinary user program" cannot crash the machine, for instance --
requests that we (library and/or system implementors) tend to label
"system calls" have to do something that we (system implementors)
call "crossing a protection domain", to use the fully generalized
term. More specifically, in a Unix-like OS, a "system call" switches
from "user mode" to "kernel mode", using some sort of CPU-dependent
mechanism. Depending on the hardware (and to some extent, software),
this mode switch has a minimum cost of tens to even thousands of
nanoseconds, which is the equivalent of a few dozen to a few thousand
"ordinary instruction" times. In these specific cases, a "system
call" may well be, on average, about 20 to 200 times slower than
an "ordinary" function (or "library") call. (That is, if the code
for the operation could be moved from the kernel to a user library, a
call to that code would take about 1/20th to 1/200th as much time.
Of course, this tends to depend greatly on the code, and in most
cases there is some good reason that it cannot be moved this way.)
(Other host systems have lighter-weight mechanisms. On such systems,
a "system call" may take about the same amount of time as a "library
call". In this case, there is little reason to bother with fancy
buffering schemes. Some such systems do it anyway, either because
the code was imported from some other system in which it *was* a good
idea to buffer, or just to mimic the behavior of those systems.)
for file IO, it is less clear if/when exactly contents are written,
but we do know at least that fflush and fclose cause contents to be
written.
(Or rather, "transmitted to the host environment", whatever that
ultimately means. Note that on some systems, a block of data sent
to the host, but not terminated with a newline, is simply buffered
inside the host, i.e., not yet presented to a human who may be
typing at a terminal. Fortunately, such systems are quite rare.)
More specifically, any stdio stream that is not connected to an
"interactive device" need not be line-buffered. Note that the
implementation -- whatever C system you are using -- determines
which stdio streams, if any, are connected to an "interactive
device". If the C system decrees that *all* output is to "interactive
devices", then *all* streams will, by default, be line-buffered or
unbuffered; if it decrees that *no* output is ever interactive, it
is possible that all output streams will be fully-buffered by
default.
In any case, you can call setbuf() or setvbuf() to control buffering.
Simply make an appropriate call before doing any output, and you
can arrange for a given output stream to be line-buffered or
un-buffered (or fully-buffered) at your choosing.
I am not sure if in general fflush has lower-level effects (for
example, if it also flushes OS-level file caching or commits changes
to the underlying filesystem, or if it only ensures that changes
are commited to the OS proper). this would mostly effect cases
like, say, one calls fflush, and then very shortly following, the
kernel crashes or the power fails or something...
This depends not only on the C implementation but also on the
underlying OS. Some OSes implement "reliable" file systems that
never lose data, some implement "fast" file systems that can lose
data in a crash, some provide hybrids ("semi-fast" file systems
with optional partial or complete journaling, for instance), and
some provide everything.