1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C】printfのバッファサイズによる処理速度の変化

Posted at

TLDR

setvbufで標準出力にバッファを設定して処理時間を計測するだけです。
バッファは大きいほうがいいけど処理速度の向上が期待できるのはある程度の大きさまで。

printfの仕様

知っている人には当たり前のことですがprintfは直接コンソールに文字列を出力させる関数ではありません。まずバッファへと内容を書き込み、そののちにバッファからコンソールに出力がなされます。

バッファからコンソールに出力されるタイミングですがデフォルトでは

  • バッファサイズを上回る文字数を入力する
  • 改行文字を入力する
  • fflush(stdout)を使う
  • プロセスが終了する(このときは文字化けする。なんでだろ)

となっていることが多いです。これは行バッファリングに相当します。
C言語では他に改行文字での出力を行わない完全バッファリングと一切バッファリングを行わないバッファリングなしモードがあります。

自分でバッファを設定する

setvbufという関数を使います。第1引数でバッファを設定するストリームを指定し、第2引数で自分で用意したバッファを渡し、第3引数でバッファリングモードを指定します。

  • _IONBFがバッファリングなし
  • _IOLBFが行バッファリング
  • _IOFBFが完全バッファリング

となっています。第4引数はバッファの大きさです。

format
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int type, size_t size);

例えば標準出力(stdout)に対して2文字分4バイトのバッファを設定するとこんな感じです。

char streamBuf[2];
if(setvbuf(stdout,streamBuf,_IOFBF,sizeof(streamBuf)) != 0){
    perror("ERROR\n");
    return 0;
}

バッファサイズによる処理速度の変化

バッファのサイズを変更しながらそれぞれについてprintfで"Hello World!"を1万回表示し、その処理時間を計測します。

test.c
#include<stdio.h>
#include<time.h>

#define LOOP_MAX 10000
#define BUF_MAX 1024*4

int main(void){
	clock_t cpu_time_start;
	clock_t cpu_time_end;
	double result_time;
	FILE *fp;

	fp = fopen("test.txt","w");
	if(fp == NULL){
		perror("ERROR\n");
		return 0;
	}

	for(int buffer_size = 1 ;buffer_size <= BUF_MAX ;buffer_size *= 2){
		char streamBuf[buffer_size];
		if(buffer_size == 1){
			if(setvbuf(stdout,NULL,_IONBF,0) != 0){
				perror("ERROR\n");
				return 0;
			}
		}else{
			if(setvbuf(stdout,streamBuf,_IOFBF,sizeof(streamBuf)) != 0){
				perror("ERROR\n");
				return 0;
			}
		}
		cpu_time_start = clock();
		for(int i = 0;i < LOOP_MAX;i++){
			printf("Hello World!");
		}
		fflush(stdout);
		cpu_time_end = clock();
		result_time = (double)(cpu_time_end - cpu_time_start)/CLOCKS_PER_SEC;
		fprintf(fp,"%d,%f\n",buffer_size,result_time);
	}
	fclose(fp);
	return 0;
}

実行結果

注 2バイトに対応するところはバッファなしの結果(_IONBF)
graph1.png
少し見にくいですがバッファが小さいうちはバッファサイズを倍にすると処理時間がおよそ半分になっているのが確認できます。

これはバッファはRAM上にあり、バッファへのアクセス速度は出力(今回は画面)へのアクセス速度に比べて非常に速いために起こっていると考えられます。
例えばバッファが4バイト(2文字分)の場合バッファなしの場合に比べて出力へのアクセス回数は半減しますからそれにより処理時間も半減しています。

横軸は指数オーダーなので縦軸もそれに揃えます。
graph2.png
バッファが大きくなるにつれ傾きが緩やかになっていくのが確認できます。これはバッファサイズが大きくなるにつれバッファへの書き出しにかかる時間が大きくなって無視できなくなることや、その他オーバーヘッドによるものと考えられます。

バッファとして使える領域は有限ですしただひたすらに大きく設定すればいいってもんでもなさそうです。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?