5

i wonder why is this happening all the time...!! I wrote two programs one in c and the other in c++.. Both performs the same action. i.e prints numbers from 1 to 2000000. Also i am setting the timer at the begtinning of execution.. and after printing all the numbers time elapsed is also printed.. The time elapsed for a c++ program is always greater than for a c program. i feel the difference in time is significant. I am curious to know what is the cause for this..????..

Here are the two programs

//iotest.c

#include<stdio.h>
#include<time.h>

clock_t start=clock();

int main()
{
for(int i=0;i<2000000;i++)

printf("%d\n",i);

printf("Time Elapsed: %f\n",((double)clock()-start)/CLOCKS_PER_SEC);

return 0;

}

//iotest.cpp

#include<iostream>

#include<time.h>

using namespace std;

clock_t start=clock();

int main()
{
    for(int i=0;i<2000000;i++)

    cout<<i<<endl;

    cout<<"Time elapsed "<<((double)clock()-start)/CLOCKS_PER_SEC<<endl;

    return 0;

}

// ver C++ 4.3.2 Compiling c program by issuing the command

g++ iotest.c

Execution gives

1

.

.

2000000

Time Elapsed: 5.410000(Not always same..)

Executing the second program

1

.

.

2000000

Time elapsed: 5.81(Not always same..)

Gabe
  • 84,912
  • 12
  • 139
  • 238
Xplore
  • 53
  • 5
  • 1
    What are your compilation commands and what are the actual run times? – Tugrul Ates Mar 03 '11 at 12:28
  • How much time is elapsed for each? Which C compiler are you using? Which C++ compiler are you using? Which operating system are you executing these in? – Bob Kaufman Mar 03 '11 at 12:29
  • 1
    try replacing `<< endl` by `<< '\n'`. `endl` also flushes the stream. Don't forget to tell us the results :) – davka Mar 03 '11 at 12:29
  • Well, your C++ program has more overhead? I mean, you just measured that, so what exactly IS the question :) – Mörre Mar 03 '11 at 12:29
  • 12
    These are both C++ programs. You're comparing stdio and iostream, not C and C++. – aschepler Mar 03 '11 at 12:31
  • possible duplicate of [How to get IOStream to perform better ?](http://stackoverflow.com/questions/5166263/how-to-get-iostream-to-perform-better) – AProgrammer Mar 03 '11 at 12:31
  • The "C program" is not really a C program (there is no "using namespace" in C). – Juliano Mar 03 '11 at 12:31
  • Probable duplicate: http://stackoverflow.com/questions/5166263/how-to-get-iostream-to-perform-better – AProgrammer Mar 03 '11 at 12:32
  • @AProgrammer: No; you're only saying that because of what you think the answer is. In fact there are several potential causes of differences here, not all of which have anything to do with `iostream`. IMO the biggest problem here is a lack of understanding: the two pieces of code are not equivalent. – Lightness Races in Orbit Mar 03 '11 at 12:33
  • 1
    Can you actually `clock_t start=clock();` outside of a function in C? Is that one of the new things in C1x, or a gcc extension? – paxdiablo Mar 03 '11 at 13:22
  • @paxdiablo: He's actually compiling both in C++, but writing in a "C style" for the first one. – Lightness Races in Orbit Mar 03 '11 at 15:40

7 Answers7

18

The difference between the two programs is that the C++ version uses endl, which not only inserts a newline but flushes the buffer. The slow part of doing any output is flushing the buffer.

Both programs would probably be about the same speed if you made your C++ program use

count << i << "\n";

The following two programs achieve a similar execution time:

C-program (a.c):

#include <stdio.h>
#include <time.h>

int main()
{
    clock_t start=clock();
    for (int i=0; i<2000000; i++) printf("%d\n",i);
    clock_t end=clock();

    fprintf(stderr, "Time Elapsed: %f\n",((double)end-start)/CLOCKS_PER_SEC);
    return 0;
}

Compile with: gcc -O3 -std=c99 a.c

C++-program (b.cpp):

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
    clock_t start=clock();
    for (int i=0;i<2000000;i++) cout << i << '\n';
    clock_t end=clock();

    cerr << "Time elapsed " << ((double)end-start)/CLOCKS_PER_SEC << endl;

    return 0;
}

Compile with g++ -O3 b.cpp

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • 1
    But C uses line buffering anyway if the output device can be determined to be a terminal, so there's more to it than that, assuming output is not being redirected. – paxdiablo Mar 03 '11 at 12:43
  • @paxdiablo: Did you see Magnus's edit? Changing `endl` to `'\n'` makes the programs perform the same. – Gabe Mar 03 '11 at 12:48
  • Yes, but based on my knowledge of the standard, I think it's something _other_ than just flushing. I could be wrong, it wouldn't be the first time but empirical evidence is just that - empirical. I don't believe the sun will rise every morning just because it always have, but because I understand the science behind it. – paxdiablo Mar 03 '11 at 12:52
  • After monkeying around, I've found that forcing a flush for each line in both programs, and then running with redirect to `/dev/null` gives `a.c` the lead with about 12%. Avoiding flush in both programs and redirecting to `/dev/null` makes the runtime identical (or if there is a difference, it's in b.cpp's favour. I'm not a statistician). This corroborates @paxdiablo's analysis. – Magnus Hoff Mar 03 '11 at 13:15
  • @Magnus: Doesn't that just imply that C++'s buffer management is slightly different from C's? I'm guessing that the extra 12% is really just a few hundred nanoseconds per flush of the buffer. – Gabe Mar 03 '11 at 13:22
  • 2
    I've seen this `endl` surprise so many times now that I cannot help to wonder if packing `EOL` and `flush` in the same object is not a design error. No beginner gets it, and experts have learned it the hard way. – Matthieu M. Mar 03 '11 at 14:11
  • @Gabe: C++ also has a *lot* of virtual function calls inside the bowels of iostreams in order to work. @Matthieu: If it had been done the other way, you'd have just as many users going "my program crashed, but the last line printed is nowhere near the crash location...". If the user of the language isn't going to take the 20 seconds to look up a piece of documentation, then they deserve to be confused. – Billy ONeal Mar 03 '11 at 21:16
  • @Billy: When neither program is flushing their output, C++ isn't any slower, so the virtual dispatch overhead isn't an issue (unless it slows down flushing the buffer). – Gabe Mar 03 '11 at 21:18
8

You've started the clock at static-initialisation time, and your C++ standard library may have more work to do during static initialisation.

You're also flushing your stream repeatedly, and iostreams are a bit slow.

Do this:

#include <iostream>
#include <ctime>

int main()
{
    std::clock_t start = std::clock();
    for (int i=0;i<2000000;i++)
       std::cout << i << '\n';
    std::cout << "Time elapsed " << (static_cast<double>(std::clock()-start)/CLOCKS_PER_SEC) << std::endl;
    return 0;
}

A proper benchmark would involve you running this program a number of times and then taking the average of the results. The results you have are not at all reliable.

(Also notice how I changed time.h to its C++ counterpart, ctime.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Very observant. Starting the clock at static initialization will indeed be a major difference between C and C++, so big a difference I'd regard it as a severe bug. I suspect this has far more impact on efficiency than buffer flushing issues. – Lundin Mar 03 '11 at 12:54
  • @Xplore: Did you selectively ignore the other issues I pointed out? – Lightness Races in Orbit Mar 03 '11 at 15:38
  • Correct me if I'm wrong, but I believe it has to be `std::clock_t start = std::clock();` (`` puts the contents of `` into namespace `std`). – Billy ONeal Mar 03 '11 at 21:17
  • @Billy: Actually, you're right. I'm too used to taking liberties with GCC, sorry. :) – Lightness Races in Orbit Mar 04 '11 at 01:51
  • @tomalak. At first i ignored thinking that it would not make much difference.. After editing, both the programs are giving similar(more or less) results.. thanks for notifying... – Xplore Mar 04 '11 at 02:39
  • @Xplore: No problem. It's worth not ignoring the answers you get here; after all, if you knew what would and would not make a difference, then you would not have asked the question. :) – Lightness Races in Orbit Mar 04 '11 at 10:06
6

Using cout << endl will force a flush. Likely the difference will be lower if you use cout << "\n"

That said, iostreams are (in my personal opinion) not the most effective mechanism, and I'd expect the printf to still be faster. If output speed is the performance bottleneck for an application, you should likely fwrite to stdout, otherwise just stick to the typesafe cout.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • Your second paragraph is probably right but C uses line buffering on stdout if it's a terminal. So I suspect the flushing is not the issue unless you're redirecting stdout. – paxdiablo Mar 03 '11 at 12:45
1

It's because std::cout is designed differently than printf(). What you lose in performance you gain back in maintainability (e.g. type safety, flexibility in usage, structured syntax, etc). The iostream library is one of the bulkiest parts of the C++ standard library, so this is not surprising.

Take a look at the assembly output and you'll see this with your own eyes.

tenfour
  • 36,141
  • 15
  • 83
  • 142
1

C++ is somewhat higher-level, the way the streams work seems very different from printf and the C and C++ compilers will both produce different code.

ryuslash
  • 1,232
  • 11
  • 11
1

I believe that the bottleneck is in the formatting of the data. I changed Gabe's example to output a constant array of characters to the console (to minimize effects due to formatting of integers):

a.c

include <stdio.h>
#include <time.h>

int main()
{
    static const char   hello[] = "hello\n";
    clock_t start=clock();
    for (int i=0; i<2000000; i++) printf("%s",hello);
    clock_t end=clock();

    fprintf(stderr, "Time Elapsed: %f\n",((double)end-start)/CLOCKS_PER_SEC);
    return 0;
}

b.cpp:

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
    static const char   hello[] = "hello\n";
    clock_t start=clock();
    for (int i=0;i<2000000;i++) cout << hello;
    clock_t end=clock();

    cerr << "Time elapsed " << ((double)end-start)/CLOCKS_PER_SEC << endl;

    return 0;
}

Compilation statements:

gcc -mno-cygwin -O3 -std=c99 a.c
g++ -mno-cygwin -O3 -o b.exe b.cpp

Executable sizes:

# ls -al *.exe
-rwxr-xr-x 1 Thomas root  49052 Mar  3 12:00 a.exe
-rwxr-xr-x 1 Thomas root 503195 Mar  3 12:01 b.exe

Performance (run on a standalone XP, with minimal OS and applications):

a.c:  Time elapsed: 187.359
b.cpp: Time elapsed: 120.718

The C++ program may be running faster because it is invoking methods tailored to the data. The printf still has to scan the format string before it prints.

Before any substantial conclusions are drawn, one should profile "fwrite" versus "cout.write()" to get a baseline. This would be the time to subtract from other comparisons since it represents the I/O overhead of the system. (I'm assuming that these functions use minimal code to output to the console).

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0

Unfortunately, the reason is that streams are slower than printf()

You may consider putting a breakpoint and see whats going on underneath those calls ;)

+

The pros and cons of using cout vs printf is already took humanity to spend a decade. I didn’t want to copy past some sort of a long discussion like the one below: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/77637c6bf362a01c?pli=1

The reality is that cout is slower (if you want me to be precise I can put here: in general) than printf.
Yes, streams are designed to adopt and benefit from higher level software design paradigms.
Yes, they are type safe.
Yes, they are more flexible.
Yes, there is bunch of extremely useful stuff like boost's lexical_cast depending on them.
Yet, give me as many -1 us you like guys, but still it won't change the fact that streams are slower than printf ;)

You may ask, why?
C++ cout printing slowly
cout or printf which of the two has a faster execution speed C++?
mixing cout and printf for faster output

Community
  • 1
  • 1
Hovhannes Grigoryan
  • 1,151
  • 1
  • 8
  • 11
  • 2
    -1 for FUD: Even if this was true for all cases (it is not), saying library A is slower than library B without 1. benchmarks, or 2. explanation as to why, is FUD. – Billy ONeal Mar 03 '11 at 21:19
  • @Billy ONeal Fair enough. Probably the answer was short, but it reflects the reality ;) Thanks for -1 anyways :) – Hovhannes Grigoryan Mar 04 '11 at 09:12