1

Update

@Ruslan pointed me to Why is snprintf consistently 2x faster than ostringstream for printing a single number? which provides an answer and a link to a bug report.

Original question

My general feeling indicates that using C++ ofstream and << operators should be of similar performance, provided I do not use endl but literal "\n" instead to skip the implicit flushing.

Also, this question supports my thought.

So, in the following example I'd expect the runtime to be genrally similar with slight advantages on the streaming side.

#include <cstdio>
#include <string>
#include <fstream>

#include <boost/timer/timer.hpp>

using namespace std;

const int LOOPS = 10000000;
const double d = 1.231;
const float f = 1.232;
const char *s = "1.233";

void stream_out() {
    boost::timer::auto_cpu_timer t;

    ofstream out;
    out.open("ofstream");
    for(int i = 0; i < LOOPS; ++i) {
        out << d << "\n";
        out << f << "\n";
        out << s << "\n";
    }
}

void print_out() {
    boost::timer::auto_cpu_timer t;

    FILE* fout = fopen("fprintf", "w");
    for(int i = 0; i < LOOPS; ++i) {
        fprintf(fout, "%g\n", d);
        fprintf(fout, "%g\n", f);
        fprintf(fout, "%s\n", s);
    }
}

int main() {
    stream_out();
    print_out();
    return 0;
}

However, that does not appear to be the case. When built with g++ and run on my RHEL7 box this shows:

$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -O2 -o test test.cpp -lboost_timer -lboost_system

$ ./test
 7.697337s wall, 6.660000s user + 0.160000s system = 6.820000s CPU (88.6%)
 4.724694s wall, 4.580000s user + 0.130000s system = 4.710000s CPU (99.7%)

So, what is my misunderstanding here? Shouldn't ofstream be ever-so-slightly faster since it doesn't need to parse format strings and variadic args at runtime? Do I miss something obvious?

It'd be a shame to revert to fprintf() just of such performance differences.

resi
  • 1,738
  • 2
  • 13
  • 14
  • Don't forget to `fclose(fout)`. – John Kugelman Sep 19 '19 at 14:06
  • It does indeed seem to be twice as slow: http://coliru.stacked-crooked.com/a/7927c96b84ec21f7 – rubenvb Sep 19 '19 at 14:14
  • 3
    iostreams formatting is slow and clunky, just because of the way things are. Nobody really cares anymore. It is probably going to be replaced with a new formatting library [fmtlib](https://github.com/fmtlib/fmt). You can use it today. It is somewhat faster than `printf` on my system. It's not a shame to use `printf` either. Modern compilers make `printf` typesafe in all cases worth caring about. – n. m. could be an AI Sep 19 '19 at 14:46
  • Related (duplicate-ish) [Does the C++ standard mandate poor performance for iostreams, or am I just dealing with a poor implementation?](https://stackoverflow.com/q/4340396/103167) – Ben Voigt Sep 19 '19 at 20:47
  • @Ruslan Thanks! I guess this is the answer: https://stackoverflow.com/a/49064900/203515 . It even links to a bug report for that effect. – resi Sep 20 '19 at 06:26
  • @n.m. I wasn't aware of iostream deprecation, I just thought more and more devs dislike the bitshift syntax. – resi Sep 20 '19 at 06:27
  • It is not yet formally deprecated, but std::format is going to be a part of C++20 and fmtlib is an implementation of it. – n. m. could be an AI Sep 20 '19 at 07:31
  • I'm actually no longer sure that your question is a duplicate of mine: in this question you don't use high-precision (>40 digits) output, which was the prerequisite to getting the slowdown in my case. – Ruslan Sep 20 '19 at 08:22
  • Thanks for pointing that out, I might've overreacted ... Still, the answer gives some clues about what might be lurking in the dark corners with multiple vsnprintf()s – resi Sep 20 '19 at 08:48

1 Answers1

2

Edit: As commented my original answer is only applicable to stdout and cout, not to files. Some testing on my side seems to indicate that the default double to string conversion of cout is to blame.

file << std::to_string(d) << '\n';

Seems to halve the difference already.

Original answer:

Standard C streams and standard C++ streams are two different systems. On default the two are being synchronized to be able to mix printf and cout, essentially doubling the copying for iostream calls.

This will disable the extra synchronization, and should reduce the difference in speed:

std::ios::sync_with_stdio(false);

https://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio

Wolfgang Brehm
  • 1,491
  • 18
  • 21
  • This only affects `printf` and `cout`, but OP is doing I/O to files and this will have no effect at all. – Ben Voigt Sep 19 '19 at 20:48
  • @Ben Voigt You're right, I did not look carefully enough. But for files it is just as fast on my system, at least when writing integers or chars. The difference seems to be the doube and float to string conversion... – Wolfgang Brehm Sep 19 '19 at 21:10
  • @BenVoigt I tried that, I didn't notice much of a difference. – resi Sep 20 '19 at 06:23