printf more than 5 times faster than std::cout?
Asked Answered
A

6

15
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>

int main(int argc, char* argv[])
{
    std::clock_t start;
    double duration;    

    std::cout << "Starting std::cout test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
    {
        std::cout << "Hello, World! (" << i << ")" << std::endl;
    }

    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Ending std::cout test." << std::endl;
    std::cout << "Time taken: " << duration << std::endl;

    std::system("pause");

    std::cout << "Starting std::printf test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
    {
        std::printf("Hello, World! (%i)\n", i);
        std::fflush(stdout);
    }

    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Ending std::printf test." << std::endl;
    std::cout << "Time taken: " << duration << std::endl;

    system("pause");

    return 0;
}

Now, here are the times for the first five runs:

  • std::cout test: 1.125 s ; printf test: 0.195 s
  • std::cout test: 1.154 s ; printf test: 0.230 s
  • std::cout test: 1.142 s ; printf test: 0.216 s
  • std::cout test: 1.322 s ; printf test: 0.221 s
  • std::cout test: 1.108 s ; printf test: 0.232 s

As you can see, using printf and then fflushing takes about 5 times less time than using std::cout.

Although I did expect using std::cout's << operator to be perhaps a little slower (almost minimal) , I wasn't prepared for this huge difference. Am I making a fair test? If so, then what makes the first test so much slower than the second one, if they essentially do the exact same thing?

Aleece answered 20/8, 2012 at 20:6 Comment(8)
std::endl in every iteration is a bad idea. Use '\n'. They're not the same thing.Rota
He did flush in the printf version too though, so that can't be it?Bloomsbury
The possible duplicate question does not answer my main question, **what makes** the first test so much slower than the second one... i.e why exactly is the printf faster?Aleece
@ApprenticeHacker, it depends on realization: For me cout faster then printf, but only if I set -std=c++0x.Cinnamon
There may not be a single correct answer other than the quality of the library implementation you're using. There have been similar questions such as this linked one. Read it and the related questions it links to.Confident
Note that std::cout << "Hello, World! (" << i << ")" << std::endl; is 4 function calls, while printf is only one. Try doing printf 5 times, like with cout and see what happens. Then you'll realize how much of the performance fail is due to function calls, and how much due the library itself.Pudgy
Your current timings are meaningless as the std::cout is synced with stdout and thus does a lot of "extra" work to maintain synchronization. If you decouple them you will see a speedup (it is still slower) std::cout.sync_with_stdio(false);Triadelphous
It is quite unfair to flush stdout for each printf. Without the std::fflush(stdout); the printf loop executes much faster. While it is idiomatic to << std::endl, it is not idiomatic to fflush(stdout). Unsuspecting C++ programmers are likely to use cout much less inefficiently then stdoutBabylon
D
10

For a true apples-to-apples comparison, re-write your test so that the only thing changing between the test cases is the print function being used:

int main(int argc, char* argv[])
{
    const char* teststring = "Test output string\n";
    std::clock_t start;
    double duration;

    std::cout << "Starting std::cout test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
        std::cout << teststring;
    /* Display timing results, code trimmed for brevity */

    for (int i = 0; i < 1000; i++) {
        std::printf(teststring);
        std::fflush(stdout);
    }
    /* Display timing results, code trimmed for brevity */
    return 0;
}

With that, you will be testing nothing but the differences between the printf and cout function calls. You won't incur any differences due to multiple << calls, etc. If you try this, I suspect that you'll get a much different result.

Diplodocus answered 20/8, 2012 at 20:45 Comment(6)
Hmm, now it's only a difference of about 0.06 s. Guess that answers my question.Aleece
@bta, it seems to be an unfair test. For printf section you are flushing stdout after each iteration, but the std::cout code is not. Should probably add << std::flush(); to the std::cout section.Tiruchirapalli
Add the following: std::cout.sync_with_stdio(false);Triadelphous
This is not a useful comparison if the performance difference between cout and printf is due to the formatting of the number i to a string.Pilar
@joydeepb- Probably not, but in this case my testing was showing that the multiple << operators were the likely culprit so I didn't bother showing sample code that tested for other things. You could, however, apply the same general principle (eliminate variables to simplify the problem) to solve the problem if the int-to-string conversion was the culprit.Diplodocus
If the difference is due to requiring many more << calls than printf calls, it's totally appropriate to compare them that way. It's not realistic to simplify the test to the extent that you have.Vociferate
T
12

Try this:

#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <iostream>

int main(int argc, char* argv[])
{
#if defined(NOSYNC)
    std::cout.sync_with_stdio(false);
#endif

    std::cout << "Starting std::cout test." << std::endl;

    std::clock_t start = std::clock();

    for (int i = 0; i < 1000; i++)
    {   
        std::cout << "Hello, World! (" << i << ")" << std::endl;
    }   

    clock_t mid = std::clock();

    for (int i = 0; i < 1000; i++)
    {   
        std::printf("Hello, World! (%i)\n", i); 
        std::fflush(stdout);
    }   

    std::clock_t end = std::clock();

    std::cout << "Time taken: P1 " << ((mid-start)*1.0/CLOCKS_PER_SEC) << std::endl;

    std::cout << "Time taken: P2 " << ((end-mid)*1.0/CLOCKS_PER_SEC) << std::endl;


    return 0;
}

Then I get:

> g++ -O3 t13.cpp
> ./a.out
# lots of lines deleted
Time taken: P1 0.002517
Time taken: P2 0.001872

> g++ -O3 t13.cpp -DNOSYNC   
> ./a.out
# lots of lines deleted
Time taken: P1 0.002398
Time taken: P2 0.001878

So the P2 times do not change.
But you get an improvement of the P1 times (ie std::cout) using std::cout.sync_with_stdio(false);. Becuase the code no longer tries to keep the two stream (std::cout stdout) synchronized. Which if you are writing pure C++ and only using std::cout not a problem.

Triadelphous answered 20/8, 2012 at 21:33 Comment(0)
D
10

For a true apples-to-apples comparison, re-write your test so that the only thing changing between the test cases is the print function being used:

int main(int argc, char* argv[])
{
    const char* teststring = "Test output string\n";
    std::clock_t start;
    double duration;

    std::cout << "Starting std::cout test." << std::endl;
    start = std::clock();

    for (int i = 0; i < 1000; i++)
        std::cout << teststring;
    /* Display timing results, code trimmed for brevity */

    for (int i = 0; i < 1000; i++) {
        std::printf(teststring);
        std::fflush(stdout);
    }
    /* Display timing results, code trimmed for brevity */
    return 0;
}

With that, you will be testing nothing but the differences between the printf and cout function calls. You won't incur any differences due to multiple << calls, etc. If you try this, I suspect that you'll get a much different result.

Diplodocus answered 20/8, 2012 at 20:45 Comment(6)
Hmm, now it's only a difference of about 0.06 s. Guess that answers my question.Aleece
@bta, it seems to be an unfair test. For printf section you are flushing stdout after each iteration, but the std::cout code is not. Should probably add << std::flush(); to the std::cout section.Tiruchirapalli
Add the following: std::cout.sync_with_stdio(false);Triadelphous
This is not a useful comparison if the performance difference between cout and printf is due to the formatting of the number i to a string.Pilar
@joydeepb- Probably not, but in this case my testing was showing that the multiple << operators were the likely culprit so I didn't bother showing sample code that tested for other things. You could, however, apply the same general principle (eliminate variables to simplify the problem) to solve the problem if the int-to-string conversion was the culprit.Diplodocus
If the difference is due to requiring many more << calls than printf calls, it's totally appropriate to compare them that way. It's not realistic to simplify the test to the extent that you have.Vociferate
S
4

use

cout << "\n";

to prevent buffering. much faster

Slipway answered 28/4, 2017 at 14:37 Comment(0)
T
2

About 10 years ago, Scott Meyers tested the efficiency of iostream and scanf/printf. Depends on the compiler and environment, sometimes scanf/printf is 20% faster than iostream, sometimes even 200% faster. But iostream was never faster than scanf/printf. According to other two given examples, scanf/printf is still faster than iostream. However, Meyers said that "On a really useful program, there would be no differences." According to Google''s programming style([http://google-styleguide.googlecode.com/svn/trunk/cppguide.html]), streams should not be used except for logging. A replacement for iostream is to encapsule scanf/printf yourself.

Tripody answered 28/4, 2017 at 14:59 Comment(0)
F
0

I only have a programming range of 1 computer, so not much testing. Anyhow, std::cout is way more faster on my build using the exact verbose code. I am using Cpp14.

I just think certain people have a pick for C++. Yes C is great language but logically I don't see how printf can be faster than std cout. Printf has to do type conversions from void pointer on runtime. Cout does that at compile time.

Forereach answered 22/5, 2018 at 2:22 Comment(3)
If iostreams are in fact faster on your platform, it would be useful to know what that platform is. The reason that iostreams tend to be a lot slower than printf is that iostreams use a huge number of function calls, including a lot of virtual function calls (an iostream doesn't do anything by itself, it forwards everything to a streambuf virtual function). That's very useful if you have a need to redirect the streams, but wasteful if you aren't using it.Wino
Okay I don't really know what platform you refer to, but I am using Win 10, Intel Celeron CPU G3900, 4 gigs Ram, CPP 14. You should remember CPP evolves every three years. A lot of function calls are compiled away.Forereach
Which compiler and which C++ standard library are very important details of the platform... the CPU (which you mentioned, and also contains cache information) and the RAM (which you mentioned only size but not clock rate, DDR generation, number of channels, or latency) are less important in this case but can sometimes have a big effect on performance and optimization.Wino
N
0

I tried this test on my laptop, running Windows 10, WSL Ubuntu, CLion 2018, GCC. No optimization:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>

int main(int argc, char *argv[]) {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::clock_t start;
    double duration1, duration2;

    std::cout << "Starting std::cout test.\n";
    start = std::clock();

    for (int i = 0; i < 100000; i++) {
        std::cout << "Hello, World! (" << i << ")" << std::endl;
    }

    duration1 = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Starting std::printf test.\n";
    start = std::clock();

    for (int i = 0; i < 100000; i++) {
        std::printf("Hello, World! (%i)\n", i);
        std::fflush(stdout);
    }

    duration2 = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    std::cout << "Time taken: cout " << duration1 << std::endl;
    std::cout << "Time taken Printf: " << duration2 << std::endl;

    return 0;
}

Results:

Test1: Cout: 2.25, Printf: 2.45312  (Cout run first)
Test2: Cout: 2.42188, Printf: 2.07812 (Printf Run first)
Test3: Cout: 2.26562, Printf: 2.25 (Cout run first)
Test4: Cout 2.46875, Printf: 2.57812 (Printf run first)

TL;DR: Using std::ios_base::sync_with_stdio(false) and std::cin.tie(nullptr) brings both functions to almost the same stand.

Normandnormandy answered 23/3, 2019 at 22:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.