C++ Logo

sg16

Advanced search

Re: Why stdout is the default in std::print? (P2093)

From: Dimitrij Mijoski <dim.mj.p_at_[hidden]>
Date: Sun, 30 Jan 2022 21:41:02 +0100
In my first message my benchmark code got messed up. I'll resend it
with some results on Linux.

// Filename: cout.cpp
#include <cstdio>
#include <iostream>
#include <benchmark/benchmark.h>

void bm_printf_with_number(benchmark::State& s) {
 while (s.KeepRunning())
  std::printf("The answer is %d.\n", 42);
}
BENCHMARK(bm_printf_with_number);

void bm_printf_with_string(benchmark::State& s) {
 while (s.KeepRunning())
  std::printf("The answer is 42.\n");
}

BENCHMARK(bm_printf_with_string);

void bm_fwrite(benchmark::State& s) {
 const char str[] = "The answer is 42.\n";
 while (s.KeepRunning())
  std::fwrite(str, sizeof(str)-1, 1, stdout);
}
BENCHMARK(bm_fwrite);

void bm_fwrite_2(benchmark::State& s) {
 const char str[] = "The answer is 42.\n";
 while (s.KeepRunning())
  std::fwrite(str, 1, sizeof(str)-1, stdout);
}
BENCHMARK(bm_fwrite_2);

void bm_fputs(benchmark::State& s) {
 const char str[] = "The answer is 42.\n";
 while (s.KeepRunning())
  std::fputs(str, stdout);
}
BENCHMARK(bm_fputs);

void bm_puts(benchmark::State& s) {
 const char str[] = "The answer is 42.";
 while (s.KeepRunning())
  std::puts(str);
}
BENCHMARK(bm_puts);


void bm_ostream_with_number(benchmark::State& s) {
 std::ios::sync_with_stdio(false);
 while (s.KeepRunning())
  std::cout << "The answer is " << 42 << ".\n";
}

BENCHMARK(bm_ostream_with_number);

void bm_ostream_with_string(benchmark::State& s) {
 std::ios::sync_with_stdio(false);
 while (s.KeepRunning())
  std::cout << "The answer is 42.\n";
}
BENCHMARK(bm_ostream_with_string);

void bm_ostream_write(benchmark::State& s) {
 std::ios::sync_with_stdio(false);
 const char str[] = "The answer is 42.\n";
 while (s.KeepRunning())
  std::cout.write(str, sizeof(str) - 1);
}
BENCHMARK(bm_ostream_write);

BENCHMARK_MAIN();
// End file.

/*
Compile with:
g++ -O2 cout.cpp -lbenchmark

Run with:
./a.out --benchmark_out=result.txt --benchmark_out_format=console > /dev/null && cat result.txt
./a.out --benchmark_out=result.txt --benchmark_out_format=console && cat result.txt
./a.out --benchmark_out=result.txt --benchmark_out_format=console > temp.txt && cat result.txt && rm temp.txt
./a.out --benchmark_out=result.txt --benchmark_out_format=console | grep -v "^T" && cat result.txt
*/

-----------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------
bm_printf_with_number 104 ns 104 ns 7428758
bm_printf_with_string 45.5 ns 45.5 ns 15267117
bm_fwrite 50.0 ns 50.0 ns 13921136
bm_fwrite_2 46.2 ns 46.2 ns 14932751
bm_fputs 56.9 ns 56.9 ns 12337150
bm_puts 59.4 ns 59.4 ns 11907507
bm_ostream_with_number 103 ns 103 ns 6799495
bm_ostream_with_string 26.5 ns 26.5 ns 28268226
bm_ostream_write 31.6 ns 31.6 ns 24615044

-----------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------
bm_printf_with_number 4810 ns 3224 ns 215014
bm_printf_with_string 4310 ns 2744 ns 243378
bm_fwrite 4467 ns 2865 ns 239828
bm_fwrite_2 4486 ns 2889 ns 244876
bm_fputs 4376 ns 2821 ns 235285
bm_puts 4510 ns 2910 ns 240914
bm_ostream_with_number 2554 ns 709 ns 985007
bm_ostream_with_string 2293 ns 669 ns 1003185
bm_ostream_write 2506 ns 662 ns 1033553

-----------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------
bm_printf_with_number 171 ns 171 ns 4000761
bm_printf_with_string 104 ns 104 ns 8242506
bm_fwrite 113 ns 112 ns 7902372
bm_fwrite_2 97.0 ns 97.0 ns 8481752
bm_fputs 105 ns 105 ns 6125860
bm_puts 103 ns 101 ns 7913004
bm_ostream_with_number 162 ns 162 ns 4610915
bm_ostream_with_string 70.3 ns 70.2 ns 9950739
bm_ostream_write 81.9 ns 81.8 ns 8891294

-----------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------
bm_printf_with_number 217 ns 178 ns 3510624
bm_printf_with_string 103 ns 66.1 ns 11562315
bm_fwrite 96.7 ns 54.3 ns 12877529
bm_fwrite_2 92.3 ns 55.4 ns 13292303
bm_fputs 106 ns 62.3 ns 10677187
bm_puts 88.3 ns 65.3 ns 10452497
bm_ostream_with_number 294 ns 210 ns 3161670
bm_ostream_with_string 101 ns 55.3 ns 11991978
bm_ostream_write 87.6 ns 53.6 ns 13036317



On Sat, 2022-01-29 at 06:39 -0800, Victor Zverovich wrote:
> It has been discussed at length and polled in LEWG and there was a
> pretty strong preference for stdout. There are many reasons to prefer
> it including but not limited to:
> 1. Better interoperability with C and other languages.

What about better interoberablity with C++? Becuase this is a C++
proposal.

> 2. Better performance. iostreams have an inherent interoperability /
> performance tradeoff which is why we have sync_with_stdio in the
> first place. It applies to both formatted and unformatted output.

As you can see above, at least on Linux, C++ iostreams are faster than
C streams.

> 3. Implementation experience.

No comment here. True, maybe you have more experience with C stdout in
fmt::print.

>
> Additionally I think others mentioned static initialization as
> another drawback of cout.

Well this is a drawback that exists since iostreams were invented, it
is there. std::print won't solve it. All users of cout already have it.
If one wants to solve it one has to invent new IO facilities.

Received on 2022-01-30 20:41:05