Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

C/C++における最速の標準出力

Last updated at Posted at 2024-12-15

この記事は「大分高専 Advent Calendar 2024」の18日の記事です。

はじめに

大分高専 Advent Calendar 2024 に参加させていただきました、大分高専 2年 機械工学科のkazuma11121125です。

動作環境

・Ubuntu 22.04 LTS

このページの内容

printfstd::coutなどの実行速度の比較。

きっかけ

ターミナルで動画を再生できるものをC++で開発した際に、printfの速度が足りないという問題が発生しました。これをどうにかするべく、std::coutなどあらゆるものを比較し、最速なものを探しだそうとしました。

計測方法

以下のコードを実行し、計測しました。

output_speed_test.cpp
#include <iostream>
#include <unistd.h>    // write
#include <cstdio>      // printf, fprintf
#include <fcntl.h>     // syscall
#include <chrono>
  
// 時間計測用関数
template <typename Func>
double measure_time(Func func) {
    auto start = std::chrono::high_resolution_clock::now();
    func();
    auto end = std::chrono::high_resolution_clock::now();
    return std::chrono::duration<double>(end - start).count();
}
 
// printfを使用した出力
void test_printf() {
    for (int i = 0; i < 100000; i++) {
        printf("Hello, World!\n");
    }
    fflush(stdout);
}

// fprintfを使用した出力
void test_fprintf() {
    for (int i = 0; i < 100000; i++) {
        fprintf(stdout, "Hello, World!\n");
    }
    fflush(stdout);
}
 
// writeを使用した出力
void test_write() {
    for (int i = 0; i < 100000; i++) {
        write(1, "Hello, World!\n", 14);
    }
}
 
// std::coutを使用した出力
void test_cout() {
    for (int i = 0; i < 100000; i++) {
        std::cout << "Hello, World!\n";
        std::cout.flush();
    }
}
 
// std::wcoutを使用した出力
void test_wcout() {
    for (int i = 0; i < 100000; i++) {
        std::wcout << L"Hello, World!\n";
        std::wcout.flush();
    }
}
 
// アセンブリでのsyscallを使用した出力
void test_syscall() {
    const char *msg = "Hello, World!\n";
    for (int i = 0; i < 100000; i++) {
        asm volatile (
            "mov $1, %%rax\n\t"  // syscall番号: write
            "mov $1, %%rdi\n\t"  // ファイルディスクリプタ: stdout
            "mov %0, %%rsi\n\t"  // 出力文字列
            "mov $14, %%rdx\n\t" // 出力文字数
            "syscall"
            :
            : "r"(msg)
            : "%rax", "%rdi", "%rsi", "%rdx"
        );
    }
}
 
int main() {
    std::cout << "Measuring output methods with 100,000 iterations:\n";
 
    double time_printf = measure_time(test_printf);
    double time_fprintf = measure_time(test_fprintf);
    double time_write = measure_time(test_write);
    double time_cout = measure_time(test_cout); 
    double time_wcout = measure_time(test_wcout); 
    double time_syscall = measure_time(test_syscall);
    std::cout << "printf:         " << time_printf << " seconds\n";
    std::cout << "fprintf:        " << time_fprintf << " seconds\n";
    std::cout << "write:          " << time_write << " seconds\n";
    std::cout << "std::cout:      " << time_cout << " seconds\n";
    std::cout << "std::wcout:     " << time_wcout << " seconds\n";
    std::cout << "syscall:        " << time_syscall << " seconds\n";
 
    return 0;
}

コンパイル

g++ -o output_speed_test output_speed_test.cpp

実行

./output_speed_test

複数の出力方法を用いて同じ文字列を100,000回出力し、それぞれの処理時間を比較しています。

結果

Alacrittyというターミナルで実行

seconds
printf 0.100653
fprintf 0.0965482
write 0.0775186
std::cout 0.114578
std::wcout 0.134293
syscall 0.108151

1位 write
2位 fprintf
3位 printf
4位 syscall
5位 std::cout
6位 std::wcout

!注意!
ターミナルや実行環境、出力するものによって前後します。
参考程度にしてください。最適化設定などは特にしていません。
恐らくした場合、相当変わると思います。
コードも参考程度にしてください。初心者のコードです。

使用しているターミナルについて

Bad Apple !!や今回の検証で使ったものは「Alacritty」というRustで開発されているものを使っています。これは物凄く速いです。

Bad Apple!!

これにはwrite関数を使用しています。〜60FPSは1フレームあたり大体200万文字が限界で、120fpsに設定すると100万文字が限界でした。
これは実行しているパソコンのスペック不足であるかなと思っています。(メモリ容量不足)
現状、1フレームあたり数百万文字を、7000フレームぐらいメモリ上に全て保存しているので30GBは最低でも必要です。

結論

出力するものによりますが、速いものがいる場合、write関数fprintf関数が良いと思います。
他にも出力系はありますので、この記事は参考程度にしてください。

なにか間違っているところ、誤字脱字があればkazuma11121125までよろしくおねがいします。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?