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.
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