5

I am printing progress of many iterations of a computation and the output is actually the slowest part of it, but only if I use Visual C++ compiler, MinGW works fine on the same system.

Consider following code:

#include <iostream>
#include <chrono>

using namespace std;
#define TO_SEC(Time) \
    chrono::duration_cast<chrono::duration<double> >(Time).count();
const int REPEATS = 100000;

int main() {
    auto start_time = chrono::steady_clock::now();

    for (int i = 1; i <= REPEATS; i++) 
        cout << '\r' << i << "/" << REPEATS;

    double run_time = TO_SEC(chrono::steady_clock::now() - start_time);
    cout << endl << run_time << "s" << endl;
}

Now the output I get when compiled with MinGW ("g++ source.cpp -std==c++11") is:

100000/100000 
0.428025s

Now the output I get when compiled with Visual C++ Compiler November 2013 ("cl.exe source.cpp") is:

100000/100000
133.991s

Which is quite preposterous. What comes to mind is that VC++ is conducting unnecessary flushes.

Would anybody know how to prevent this?

EDIT: The setup is:

gcc version 4.8.2 (GCC), target i686-pc-cygwin

Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86

Windows 7 Professional N 64-bit with CPU i7-3630QM, 2.4GHz with 8.00GB RAM

Adam Streck
  • 340
  • 2
  • 15
  • 5
    What compiler options you use in both cases? Are they the same? – Kiril Kirov Mar 25 '14 at 11:49
  • Is it a Release or a Debug build in VS? – lethal-guitar Mar 25 '14 at 11:56
  • It's default options, i.e.: "g++ source.cpp -std=c++11" and "cl.exe source.cpp" – Adam Streck Mar 25 '14 at 12:00
  • By default vc++ uses `/Od` where it [disables](http://msdn.microsoft.com/en-us/library/aafb762y.aspx) any optimization for faster debugging. – Kenneth Bastian Mar 25 '14 at 12:05
  • Compiled "cl.exe /O2 source.cpp", runtime: 135.549s – Adam Streck Mar 25 '14 at 12:08
  • 2
    I get significantly different numbers: MinGW: 21.6672s. cl.exe: 53.1926s. Which version of MinGW's g++ are you using? – Bart van Nierop Mar 25 '14 at 12:21
  • I'm surprised nobody has asked this yet: What are the version numbers of g++ and cl that you are using? Also since this is a pointless benchmark: what hardware setup are you running on? – Mgetz Mar 25 '14 at 12:28
  • 2
    The only way that this program can take only 0.38 seconds is when output is buffered, like when it is redirected to a file. That speeds up the MSVC++ build as well, 0.64 sec on my machine. Writing sane code is the primary directive here, write output tuned to the human eye. – Hans Passant Mar 25 '14 at 12:45
  • gcc version 4.8.2 (GCC) Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 on Windows 7 Professional N 64-bit with CPU i7-3630QM, 2.4GHz with 8.00GB RAM – Adam Streck Mar 25 '14 at 12:46
  • @HansPassant would you have a suggestion on how to enforce this behaviour? – Adam Streck Mar 25 '14 at 13:01
  • I think HansPassant has hit the nail on the head, however this is comparing apples to oranges. You cannot compare a 64bit application to a 32bit one when trying to benchmark behavior. You need to isolate variables if you're going to benchmark. – Mgetz Mar 25 '14 at 13:40
  • @Mgetz I have edited the post to use 32bit Gcc as well, however I did not feel that neither the precise version of the compiler nor the target platform are really important since the results are just completely different, suggesting that there is completely different semantic action when the above is invoked. – Adam Streck Mar 25 '14 at 13:54
  • @PunyOne actually your updated numbers show that it was, albeit minor. 32bit applications on a 64bit machine have an impedance that doesn't occur for 64bit applications. If this were a floating point test however the difference would most likely be dramatic. That said I think HansPassant is correct, something is fishy here. – Mgetz Mar 25 '14 at 13:57
  • that's odd, don't you get a compile error in VS? you are missing a return value – AndersK Mar 25 '14 at 14:02
  • @Claptrap no, should it? From standard (draft N3690): "If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;" – Adam Streck Mar 25 '14 at 14:07
  • @PunyOne well VS gave me a syntax error – AndersK Mar 25 '14 at 14:15
  • @Claptrap Interesting, however it works for me with the above listed compiler. – Adam Streck Mar 25 '14 at 14:23

2 Answers2

12

std::cout in MSVC is slow (https://web.archive.org/web/20170329163751/https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance-bug-in-c-library).

It is an unfortunate consequence of how our C and C++ Standard Library implementations are designed. The problem is that when printing to the console (instead of, say, being redirected to a file), neither our C nor C++ I/O are buffered by default. This is sometimes concealed by the fact that C I/O functions like printf() and puts() temporarily enable buffering while doing their work.

Microsoft suggests this fix (to enable buffering on cout/stdout):

setvbuf(stdout, 0, _IOLBF, 4096)

You could also try with:

cout.sync_with_stdio(false);

but probably it won't make a difference.

Yusuf Tarık Günaydın
  • 3,016
  • 2
  • 27
  • 41
manlio
  • 18,345
  • 14
  • 76
  • 126
0

avoid using std::endl but use instead "\n". std::endl is supposed to flush according to the standard.