8

I am reading about 3 million rows from a file and inserting them into STL maps. So, inside my while loop where I read each line from the file, I also print to console what row number it is through a simple cout statement. One of my friends recently pointed out that this makes code slower. I was wondering whether it is true and if it is why?

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
Zanam
  • 4,607
  • 13
  • 67
  • 143

3 Answers3

7

As already mentioned, writing to the terminal is almost definitely going to be slower. Why?

  • Buffering:

Writing to the terminal uses line buffering* by default. This means the contents of the buffer are transmitted everytime a newline is encountered. When writing to a file, the buffer is flushed only when the buffer becomes full or when you flush the stream manually. This is the main reason for the difference as the number of I/O operations is significantly different.

*: This is true for Unix implementations, but other implementations may be unbuffered (see discussion in comments).

  • Rendering:

When you write to a terminal, this involves rendering on the screen, and depending on the terminal could involve other operations that can slow your program down (not all terminals are made the same, you might find significant differences in speed by just switching to a different one).

Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • "Writing to the terminal uses line buffering by default" - can you back that up with some evidence? To the best of my knowledge, `cout` typically defaults to fully buffered, `cerr` line buffered. Still, some people have the hideous habit of using `std::endl` unnecessarily which flushes the stream. Using `\n` is normally more appropriate. – Tony Delroy Jan 29 '13 at 01:21
  • @TonyD: That is talked about in [this SO question](http://stackoverflow.com/questions/3723795/is-stdout-line-buffered-unbuffered-or-indeterminate-by-default). The standard only says that `cout` may not be fully buffered when connected to a terminal, but AFAIK it is line buffered on Unix and Windows. – Jesse Good Jan 29 '13 at 01:38
  • That's question's for C99. I've just inspected every mention of cout in the C++11 Standard, and there's no requirements re buffering at all (except for the tie to `cin`). It does say 27.4.2.3 "The object cout controls output to a stream buffer associated with the object stdout, declared in (27.9.2).". But - at least for UNIX stdout is line buffered when pointed at a terminal, so what you've written's good there providing `cout` passes data through without further buffering.... – Tony Delroy Jan 29 '13 at 02:03
  • @TonyD: They share the same buffer, by default the C++ streams are synchronized with stdout, etc. (Please read [std::ios_base::sync_with_stdio](http://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio)). Quote: `If the synchronization is turned off, the C++ standard streams are allowed to buffer their I/O independently, which may be considerably faster in some cases.` – Jesse Good Jan 29 '13 at 02:24
  • Ok, that all hangs together. +1 for your answer then. BTW - on some VS/Windoze combinations, it'll be unbuffered rather than line buffered: see "As documented at http://msdn.microsoft.com/en-us/library/86cebhfs.aspx , our C Standard Library implementation isn't capable of line buffering, only full buffering or no buffering." at https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance-bug-in-c-library – Tony Delroy Jan 29 '13 at 02:47
7

As already mentioned, writing to the terminal is almost definitely going to be slower. Why?

  • depending on your OS, std::cout may use line buffering - which means each line may be sent to the terminal program separately. When you use std::endl rather than '\n' it definitely flushes the buffer. Writing the data in smaller chunks means extra system calls and rendering efforts that slow things down significantly.

  • some operating systems / compilers are even slower - for example, Visual C++: https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance-bug-in-c-library

  • terminals displaying output need to make calls to wipe out existing screen content, render the fonts, update the scroll bar, copy the lines into the history/buffer. Especially when they get new content in small pieces, they can't reliably guess how much longer they'd have to wait for some more and are likely to try to update the screen for the little bit they've received: that's costly, and a reason excessive flushing or unbuffered output is slow.

    • Some terminals offer the option of "jump scrolling" which means if they find they're say 10 pages behind they immediately render the last page and the earlier 9 pages of content never appear on the screen: that can be nice and fast. Still, "jump scrolling" is not always used or wanted, as it means output is never presented to the end users eyes: perhaps the program is meant to print a huge red error message in some case - with jump scrolling there wouldn't even be a flicker of it to catch the user's attention, but without jump scrolling you'd probably notice it.

    • when I worked for Bloomberg we had a constant stream of log file updates occupying several monitors - at times the displayed output would get several minutes behind; a switch from the default Solaris xterm to rxvt ensured it always kept pace

  • redirecting output to /dev/null is a good way to see how much your particular terminal is slowing things down

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
5

It's almost certainly true. Writing to the terminal is notorious for slowing things down. Run your program and redirect the output to a file and see how much faster it is. Then take out the output statement entirely and measure again. You'll see the behaviour immediately.

Here's a braindead example:

#include <stdio.h>

int main(void)
{
    int i;

    for (i = 0; i < 10000; i++)
    {
        printf("Hello, world!\n");
    }
    return 0;
}

I built this program unoptimized and ran it, once with output to the terminal, and once with output to a file. Results for the terminal output:

real 0m0.026s
user 0m0.003s
sys  0m0.007s

Results for redirected I/O:

real 0m0.003s
user 0m0.001s
sys  0m0.001s

There you go, ~8x faster. And that's for a very small number of prints!

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Thanks! that is an empirical proof. But, so far no one has explained the reason. Why should writing to file be faster than printing to console? – Zanam Jan 29 '13 at 00:10
  • 1
    Can you also do a test when redirecting to `/dev/null`? That would be an interesting comparison. – leemes Jan 29 '13 at 00:11
  • Because writing to a file requires a lot less effort. In fact it's probably all in-memory operations, since your OS presumably has a filesystem cache. Writing to the monitor requires interacting with real hardware. – Carl Norum Jan 29 '13 at 00:11
  • `/dev/null` redirecting improved things about 1 ms. This is all pretty gross measurement given how fast the test program runs. – Carl Norum Jan 29 '13 at 00:12
  • I guess 1 ms faster in comparison to redirecting to a file. – leemes Jan 29 '13 at 00:12
  • 2
    Why no optimizations? Profiling (even a simple example like this) is pointless without them. – GManNickG Jan 29 '13 at 00:13
  • I just tried with `-O3`, and I get the same results. Looks like I/O bottlenecks are the wait here anyway. @leemes - yes, 2 ms vs 3 ms. – Carl Norum Jan 29 '13 at 00:14
  • 2
    @GManNickG I don't think that optimizing the *program* improves the *rendering time of the terminal*. Or can stuff like buffering be optimized? I don't think so but I can be wrong. – leemes Jan 29 '13 at 00:14
  • @leemes, the buffering is done by the C library or the kernel, so they're presumably already optimized. I don't compile the source for those in my program. – Carl Norum Jan 29 '13 at 00:16
  • @leemes: Why even wonder? Just do optimizations like all profiled programs should and see what happens. – GManNickG Jan 29 '13 at 01:17