15

I'm very new to c and c++ programming, so I'm starting with the basics. I wrote identical Fibonacci loop programs for both c and c++ to test relative speed. I thought they'd be about the same for something so simple, but the c++ version is 60x slower. All they do is loop through and print the first 14 Fibonacci numbers 10,000 times. Here is the c version:

#include <stdio.h>

int main (){
    int c = 0;
    int x, y, z;

    while(c < 10000)
    {
        x = 0;
        y = 1;
        while(x < 255)
        {
            printf("%d\n", x);
            z = x + y;
            x = y;
            y = z;
        }
        c++;
    }
    return 0;
}

and here is the c++ version:

#include <iostream>
using namespace std;

int main()
{
    int c = 0, x = 0, y = 0, z = 0;
    while(c < 10000)
    {
        x = 0;
        y = 1;
        while(x < 255)
        {
            cout << x << endl;
            z = x + y;
            x = y;
            y = z;
        }
        c++;
    }
    return 0;
}

I wrote both in notepad++ and compiled them using g++ from the mingw that comes with codeblocks:

g++ -o fibc.exe fib.c -s
g++ -o fibcpp.exe fib.cpp -s

The executables are very different in size: the c is 8.5KB and the c++ is 784KB! I used powershell to time them:

Measure-Command {start-process "C:\Path\fibcpp.exe" -RedirectStandardOutput "C:\Path\cpp.txt" -Wait}

The files produced are identical, but the c version took 1 sec and the c++ verison took 60sec! (In fact, putting a loop of 1 million for the c program still only took 13sec). I also wrote the c++ in Visual Studio 17 and compiled it there with an x86 release config. The program size is now 9.5KB, but the run time is the same as the g++ version: 62sec. Why is this happening for such a simple program?

machine_1
  • 4,266
  • 2
  • 21
  • 42
MrPuzzler
  • 321
  • 3
  • 7
  • 6
    Try to use the same header as the C code in the C++ code. Remove `using namespace std;` and use `printf` instead of `cout` and check again the difference between them. When you run such an experiment you should have the closests codes as you can. – andresantacruz Aug 23 '19 at 11:08
  • 11
    Try using `'\n'` instead of `std::endl` for starters, you don't need to flush every time. Have you tryed to compile with optimizations, like e.g. `-O2`? – Bob__ Aug 23 '19 at 11:09
  • 11
    You're not comparing equivalent code. C++ streams (`std::cout`, etc) are synchronised with their C equivalents by default - which means a performance hit by default. Try doing `std::ios::sync_with_stdio(false)` before performing output - then the C++ version will be closer (albeit not completely equivalent) to the C version. Also, the `endl` stream manipulator flushes the stream buffer, which is not done when supplying a `'\n'` to `printf()`. Also, benchmarking is usually pointless on unoptimised code. – Peter Aug 23 '19 at 11:15
  • 1
    could you replace cout with printf? – Mike Aug 23 '19 at 11:15
  • @Peter you mean _" when supplying a '\n' to cout"_, don't you? – Jabberwocky Aug 23 '19 at 11:16
  • @Jabberwocky - I was just pointing out a few differences differences between the allegedly equivalent C and C++ code. Yeah, but you're right - `printf()` does flush when there is a newline in the format string. – Peter Aug 23 '19 at 11:20
  • Have a look: https://stackoverflow.com/questions/43051948/why-is-stdcout-so-time-consuming?rq=1 – Mike Aug 23 '19 at 11:22
  • Please also note this: https://gcc.gnu.org/onlinedocs/gcc/Invoking-G_002b_002b.html – Bob__ Aug 23 '19 at 11:23
  • 3
    Well, you guys solved my problem in 2 minutes- thank you. Switching to stdio and printf in the c++ code was everything- the new exe is the same size and performance as the c version. As you can see, I'm VERY new to this. – MrPuzzler Aug 23 '19 at 11:23
  • Hi @MrPuzzler, Are you satisfied with the answers? I mean, there was such a massive performance difference! I simply copied your c++ code and my binary is 12.8 kB. while you said yours was 700+ kB. if `iostream` and `cout`s were that big deal in size and performance issue, then why are they extensively used... **I'm puzzled TBH** – RC0993 Aug 23 '19 at 11:31
  • @RC0993: `std::cout << "hi" << 42;` works, whereas `printf` would require correct format. `std::cout` handles locale, ... – Jarod42 Aug 23 '19 at 11:49
  • If the difference was truly that big, that would cast serious doubts on your environment for me. You might want to build both the C and C++ code with maximum optimizations to hopefully get a more "fair" comparison. – Sander De Dycker Aug 23 '19 at 11:49
  • @Jarod42 : sure, there'll be a performance impact, but 60x slower, and 90x binary size ? That's a bit extreme don't you think ? – Sander De Dycker Aug 23 '19 at 11:51
  • 1
    @SanderDeDycker: It's indeed sad that, for a language for which lot of people claim its speed and its "don't pay for that you don't use", there is no simple and fast (C++) ways to do I/O. :-/ – Jarod42 Aug 23 '19 at 11:59
  • Are you running on a toaster? This takes [0.5 seconds](http://coliru.stacked-crooked.com/a/670a11b5f7e7fdc0) as is. – n. m. could be an AI Aug 23 '19 at 12:06
  • 1
    @Jarod42 : sure there is - just use `std::ios::sync_with_stdio(false)`, and use `"\n"` instead of `std::endl`. My point wasn't that though - it was that I've never seen the impact of those specific C++ features be that big (maybe I've been lucky). – Sander De Dycker Aug 23 '19 at 12:06
  • 1
    @Jarod42 Well, not [yet](https://github.com/fmtlib/fmt). – Bob__ Aug 23 '19 at 12:06
  • @SanderDeDycker: Even with that, there are still some required overheads (handling locale for example) which is not really in C++ philosophy. `std::cout` is more convenient than performant. (Not an issue for me BTW). – Jarod42 Aug 23 '19 at 12:21

3 Answers3

6

You are benchmarking printf vs cout, since these are the major bottlenecks in your program.

printf is a terribly slow function, but probably still faster than osteam, which will have to maintain its own private hell of template meta programming, to keep it as flexible as required by the C++ standard. cout is definitely far more flexible and complex than printf. More features means slower code.

If you truly want to compare the two languages, drop the print functions and replace them with a dummy function "foo", with external linkage:

void foo (int x);
...

while(x < 255)
{
  foo(x);

When benchmarking that code with gcc -O3 for x86, I get almost identical code for C version and C++ version.

The only notable difference is the "CRT" goo that C++ added at the end of main(). It is calling atexit and various other clean-up that C will do too, but perhaps outside the application code. Still there will always be overhead in C++, because it has to call constructs and clean-up destructors of objects with static storage duration. C doesn't have to do this.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • If you don't include iostream then the two are actually identical (aside from name mangling of `foo`). The key takeaway is that just _including_ iostream contributes some (small) overhead to your program. – Miles Budnek Aug 23 '19 at 11:55
  • @MilesBudnek I'd rather suspect that including anything with static storage duration objects creates overhead. – Lundin Aug 23 '19 at 12:33
  • 3
    Template meta programming does not affect execution speed. Things like buffering strategies, flushing, and synchronization do. – aschepler Aug 23 '19 at 23:32
  • @aschepler All manner of overhead code affects execution speed. Things that can be resolved at compile-time don't, but meta programming almost always means overhead code. And so `ostream` is dreadfully slow. – Lundin Aug 25 '19 at 19:34
2

The reason why C++ cout is slow is explained in here.

By default, iostream objects and cstdio streams are synchronized (as if this function was called with true as argument).

So by default cout is synced with stdio.

Try executing the following to speed up.

ios_base::sync_with_stdio(false)

But be careful, this code will print something you don't expect.

#include <iostream>
#include <cstdio>

int main()
{
    std::ios::sync_with_stdio(false);
    std::cout << "a\n";
    std::printf("b\n");
    std::cout << "c\n";
}
prosti
  • 42,291
  • 14
  • 186
  • 151
0

Compiling

#include <iostream>
using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    int c = 0, x = 0, y = 0, z = 0;
    while(c < 10000)
    {
        x = 0;
        y = 1;
        while(x < 255)
        {
            cout << x << '\n';
            z = x + y;
            x = y;
            y = z;
        }
        c++;
    }
    return 0;
}

with basic modern optimizations (-Os) gets

$ ls -l bin/c?
-rwxr-xr-x 1 jthill jthill 16592 Feb 29 12:47 bin/c1
-rwxr-xr-x 1 jthill jthill 17176 Feb 29 12:53 bin/c2
-rwxr-xr-x 1 jthill jthill 17088 Feb 29 12:49 bin/c3
$ 

(your C version is c1, your C++ version is c2, the above C++ version is c3).

Averaging the timing for 100 runs each,

$ for x in {1..100}; do time bin/c1; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.00862
$ for x in {1..100}; do time bin/c2; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.0428
$ for x in {1..100}; do time bin/c3; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.00743

Used properly, C++'s iostreams are faster than C's stdio.

jthill
  • 55,082
  • 5
  • 77
  • 137