C言語におけるファイル入出力の高速化

Similar documents
slide4.pptx

1 $ cat aboutipa 2 IPA is a Japanese quasi-government 3 organization established in accor- 4 dance with The Law for Information 5 Processing Technolog

ファイル入出力と プロセス間通信 \(1\)

全体ロードマップ インターネット電話 音の符号化 ( 信号処理 ) 今日 音の録音 再生 ネットワーク ( ソケット ) プログラミング ファイル入出力 インターネットの基礎 C プログラミング基礎

ファイル入出力

ファイル入出力

Microsoft Word - Cプログラミング演習(10)

02: 変数と標準入出力

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

memo

02: 変数と標準入出力

2006年10月5日(木)実施

計算機プログラミング

gengo1-12

ファイルシステム

Taro-ファイル処理(公開版).jtd

gengo1-12

Prog1_12th

Microsoft Word - Cプログラミング演習(9)

Microsoft PowerPoint pptx

gengo1-12

プログラミング基礎

演算増幅器

C言語講座 ~ファイル入出力編~

Microsoft PowerPoint - 第3回目.ppt [互換モード]

PowerPoint Presentation

PowerPoint プレゼンテーション

情報処理演習 B8クラス

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

PowerPoint プレゼンテーション

FORTRAN( と C) によるプログラミング 5 ファイル入出力 ここではファイルからデータを読みこんだり ファイルにデータを書き出したりするプログラムを作成してみます はじめに テキスト形式で書かれたデータファイルに書かれているデータを読みこんで配列に代入し 標準出力に書き出すプログラムを作り

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

Microsoft PowerPoint - CproNt11.ppt [互換モード]

Microsoft PowerPoint - prog04.ppt

PowerPoint Presentation

V850Jx3-U SPボード向けサンプルプログラム操作説明書

Microsoft PowerPoint - kougi8.ppt

02: 変数と標準入出力

※ ポイント ※

PowerPoint プレゼンテーション

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

memo

スライド タイトルなし

( ) 3 1 ( ), ( ).. 1

Microsoft PowerPoint - kougi6.ppt

PowerPoint プレゼンテーション

Microsoft Word - no15.docx

AquesTalk2 Win マニュアル

AquesTalk プログラミングガイド

AquesTalk2 Linux マニュアル

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

10-vm1.ppt

Microsoft PowerPoint - 計算機言語 第7回.ppt

PowerPoint プレゼンテーション

プログラミング及び演習 第1回 講義概容・実行制御

Microsoft Word - no204.docx

AquesTalk Win Manual

Microsoft PowerPoint - kougi9.ppt

Microsoft Word - appendix_b_srft.doc

02: 変数と標準入出力

Microsoft PowerPoint - 14th.ppt [互換モード]

第1回 プログラミング演習3 センサーアプリケーション

メモリ管理

Microsoft Word - Cプログラミング演習(12)

Microsoft PowerPoint pptx

Taro-ポインタ変数Ⅰ(公開版).j

Microsoft PowerPoint - dev1.ppt

格子点データの解析 1 月平均全球客観解析データの解析 客観解析データや衛星観測データのような格子点データは バイナリ形式のデータファイルに記録されていることが多いです バイナリ形式のデータファイルは テキスト形式の場合とは異なり 直接中身を見ることができません プログラムを書いてデータを読み出して

01-introduction.ppt

プログラミング演習3 - Cプログラミング -

TFTP serverの実装

1 C STL(1) C C C libc C C C++ STL(Standard Template Library ) libc libc C++ C STL libc STL iostream Algorithm libc STL string vector l

ファイル操作-バイナリファイル

Microsoft PowerPoint - prog06.ppt

ikuo/enshu/keisanki/ GUI(Graphica

memo

プログラミング実習I

文字列 2 前回の授業ではコンピュータ内部での文字の取り扱い 文字型の変数 文字型変数への代入方法などを学習した 今回は 前回に引き続き 文字処理を学習する 内容は 標準入出力 ( キーボード ディスプレイ ) での文字処理 文字のファイル処理 文字を取り扱うライブラリ関数である 標準入出力 Lin

プログラミングI第10回

Prog1_10th

プログラミング及び演習 第1回 講義概容・実行制御

04-process_thread_2.ppt

02: 変数と標準入出力

画像ファイルを扱う これまでに学んだ条件分岐, 繰り返し, 配列, ファイル入出力を使って, 画像を扱うプログラムにチャレンジしてみよう

プログラミング演習3 - Cプログラミング -

Microsoft PowerPoint - CproNt02.ppt [互換モード]

演算増幅器

Microsoft PowerPoint ppt

Microsoft PowerPoint - ca ppt [互換モード]

1. ファイルにアクセスするには ファイルにアクセスするには 1. ファイルを開く 2. アクセスする 3. ファイルを閉じるという手順を踏まなければなりません 1.1. ファイルを読み込む まずはファイルの内容を画面に表示させるプログラムを作りましょう 開始 FILE *fp char fname

Microsoft PowerPoint - kougi7.ppt

Microsoft PowerPoint - handout08.ppt

練習&演習問題

AquesTalk for WinCE プログラミングガイド

計算機概論

ERDAS IMAGINE における処理速度の向上 株式会社ベストシステムズ PASCO CORPORATION 2015

C プログラミング 1( 再 ) 第 5 回 講義では C プログラミングの基本を学び演習では やや実践的なプログラミングを通して学ぶ

ユーザーズマニュアル

データ構造

Transcription:

C 言語におけるファイル入出力の高速化 東京大学情報基盤センター 黒田久泰 不連続なメモリ上のデータをファイルに保存する場合 内部バッファサイズを大きくすると実行時間が短縮できます また メモリ上に連続して配置されている大規模なデータをファイルに保存する場合には できるだけ大きなデータサイズでファイル入出力を行うことで実行時間が短縮できます ここでは これらの方法や性能について紹介します 1. 内部バッファサイズの変更方法高水準入出力関数 fopen fread fwrite fclose では内部バッファにデータを貯めておき 内部バッファが空になるか一杯になるとまとめてファイル入出力を行います 通常 この内部バッファサイズはインクルードファイル /usr/include/stdio.h の BUFSIZ で定義されている値になります 例えば SR8000/MPP では 64KB SR11000/J1 では 4KB になっています ( サンプルプログラム main.c) #include <sys/time.h> #define SIZE 256*1024*1024 int a[size][2]; double getetime() struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double)tv.tv_usec*1e-6; int i; double st,en; FILE *fp; st=getetime(); fp=fopen("a.dat","w"); for(i=0;i<size;i++) fwrite(&a[i][0],sizeof(int),1,fp); fclose(fp); en=getetime(); printf("elapsed Time=%.6f\n",en-st); このプログラムは配列 a[size][2] の半分の要素 a[0][0], a[1][0], a[2][0],, a[size-1][0] だけを抜き出してファイルに出力するプログラムです ( 出力されるファイルサイズは 1GB) getetime 関数は gettimeofday システムコールの値を double 型の秒数に変換して返す関数で en-st はファイル出力にかかった経過時間 ( 秒 ) を表します

このプログラムを実行すると 下記のようになります (SR8000/MPP) % cc -64 -Os -noparallel +Op main.c %./a.out ( 実際はバッチジョブ上で実行 ) Elapsed Time=182.191025 (SR11000/J1) % cc -64 -Os -noparallel +Op main.c %./a.out ( 実際はバッチジョブ上で実行 ) Elapsed Time=237.864731 SR8000/MPP では約 182 秒 SR11000/J1 では約 238 秒かかりました このサンプルプログラムでは 内部バッファサイズを変更することで高速化させることが可能です バッファサイズを変更するには setvbuf 関数を使用します 書式 int setvbuf(file *fp, char *buffer, int mode, size_t size); fp で示されるファイルに対して 自動的に割り当てられる入出力バッファの代わりに buffer で指定した領域を入出力バッファとして利用することを指定する size には新しく割り当てる入出力バッファのサイズを指定する buffer の値が NULL の場合には malloc を使って自動的に size 分のメモリを確保する mode には次の 3 つの内のどれかを指定する _IOFBF 入出力を完全バッファリング ( バッファを埋め尽くすと出力を行う ) _IOLBF 入出力を行バッファリング ( バッファを埋め尽くしたときと改行コードが来たときに出力を行う ) _IONBF バッファリングなし (buffer と size の値は無視される ) 例えば入出力バッファサイズを 512KB にする場合には 下記のようにコードを追加します ( 内部バッファサイズの変更を行うコードの追加 ) fp=fopen("a.dat","w"); setvbuf(fp,null,_iofbf,512*1024); この 1 行を追加 for(i=0;i<size;i++) fwrite(&a[i][0],sizeof(int),1,fp); fclose(fp); fopen 関数でファイルをオープンした後に setvbuf 関数を呼び出すことに注意してください 内部バッファサイズを 4KB から 32MB まで変えたときの実行時間は図 1 のようになります

実行時間 ( 秒 ) 450 400 350 300 250 200 150 100 50 0 図 1 内部バッファサイズと実行時間 SR11000/J1 SR8000/MPP 4K 8K 16K 32K 64K 128K 256K 512K 1024K 2048K 4096K 8192K 16384K SR8000/MPP では入出力バッファサイズを 512KB にすると実行時間は約 156 秒になり標準の 64KB のと きと比べて約 1.17 倍の速度向上となります 一方 SR11000/J1 では標準の入出力バッファサイズが 4KB と小さいため 512KB にすると実行時間は約 28 秒になり約 8.4 倍の速度向上となります 2. 低水準入出力関数を用いたファイル入出力低水準入出力関数である open read write close を使ってファイル入出力を行う場合 内部バッファを使わずに直接ディスクに対してファイルの読み書きを行うことができます これらはシステムコールと呼ばれ 直接 オペレーティングシステム (OS) によって処理されます 書式 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags, mode_t mode); pathname にはファイルのパス名 flags にはファイル状態フラグ mode にはファイルのアクセス属性を指定してファイルをオープンする flags の値としてよく使われるものは次のものである ただし O_RDONLY O_WRONLY O_RDWR のどれか1つは入っていなければならない O_RDONLY 読み込み専用 O_WRONLY 書き込み専用 O_RDWR 読み書き両用 O_CREAT ファイルが存在しなかった場合作成する O_APPEND 追加モードでオープンする ( ファイル ポインタをファイルの最後に移動 ) O_TRUNC ファイルが既に存在する場合に書き込みモードでオープンされている場合 ファイルの長さを 0 に切り詰める mode には下記のシンボル定数を指定する ( 新しくファイルを作成するときのみ使用される ) S_IRUSR ファイル作成者に読み込みの許可がある S_IWUSR ファイル作成者に書き込みの許可がある S_IXUSR ファイル作成者に実行の許可があるファイル作成者と同一グループの者に許可を与える場合にはそれぞれ S_IRGRP S_IWGRP S_IXGRP を指定し 他人に許可を与える場合にはそれぞれ S_IROTH S_IWOTH S_IXOTH を指定する

書式 #include <unistd.h> ssize_t read(int filedes, void *buffer, size_t nbytes); ssize_t write(int filedes, void *buffer, size_t nbytes); read ではデータの読み込み write ではデータの書き込みを行う filedes にはファイルディスクリプタ buffer にはデータの先頭アドレス nbytes にはデータのバイト数を指定する 書式 #include <unistd.h> int close(int filedes); filedes で示されるファイルディスクリプタをクローズする 低水準入出力関数を利用すればいつでも速くなるわけではありません 具体的にその例を示します 次の 2 つのプログラムは 大きさ 100 万の配列 a の値を 1 要素 (=4 バイト ) ずつファイルに出力するプログラムです 左のプログラムは高水準入出力関数 fopen fwrite fclose で書かれており 右のプログラムでは低水準入出力関数 open write close で書かれています (fwrite を使った場合 ) #define SIZE 1000000 int a[size]; int i; FILE *fp; fp=fopen("a.dat","w"); for(i=0;i<size;i++) fwrite(&a[i],sizeof(int),1,fp); fclose(fp); (write を使った場合 ) #include <sys/types.h> #include <sys/mode.h> #include <fcntl.h> #define SIZE 1000000 int a[size]; int i; int file; file=open("a.dat",o_wronly O_CREAT,S_IREAD S_IWRITE); for(i=0;i<size;i++) write(file,&a[i],sizeof(int)); close(file); どちらも cc -64 Os noparallel +Op でコンパイルして実行したところ 下記のような実行時間 になりました fwrite を使った場合 write を使った場合 SR8000/MPP 1.21 秒 195.68 秒 SR11000/J1 0.29 秒 166.98 秒 このように write を使って小さいサイズの書き込みを何度も行うと 極端に遅くなってしまいます 低水準入出力関数を使う場合には できるだけ大きなサイズ単位でファイル入出力を行うように心がける必要があります

3. ファイルシステム para-io の利用 単一の大容量ファイルの入出力を行う場合には ファイルシステム para-io を利用すると実行時間が 短縮されます ここではファイルシステム para-io を利用して大きなサイズのファイルを出力したときの性能を紹介します 性能測定プログラムには下記のプログラムを利用しました 配列 a は double 型でデータサイズは 8GB になります この 8GB のデータを複数回に分けてファイル出力を行います ここでは低水準入出力関数を利用したプログラムを示します ( 性能測定プログラム ) #include <sys/time.h> #include <sys/types.h> #include <sys/mode.h> #include <fcntl.h> #include <unistd.h> #define SIZE 1024*1024*1024 double a[size]; double getetime() struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double)tv.tv_usec*1e-6; long long int i,bsize; double st,en; int file; 1 for(bsize=4096;bsize<=size;bsize*=2) unlink("/para-io/******/a.dat"); st=getetime(); file=open("/para-io/******/a.dat",o_wronly O_CREAT,S_IREAD S_IWRITE); 2 for(i=0;i<size/bsize;i++) write(file,&a[bsize*i],sizeof(double)*bsize); 3 close(file); en=getetime(); printf("size=%lld Elapsed Time=%.6f Rate=%.3fMB/s\n", bsize*8,en-st,(double)size*8/1024/1024/(en-st)); 4 ****** の部分にはユーザー ID を記述すること 高水準入出力関数を利用したプログラムに変更するには 1から4までをそれぞれ下記のように修正します 1 FILE *fp; 2 fp=fopen("/para-io/******/a.dat","w"); 3 fwrite(&a[bsize*i],sizeof(double),bsize,fp); 4 fclose(fp);

1 回に書き込むサイズを 32KB から 8GB まで増やしていったときのディスク書き込み速度のグラフを図 2 に示します MB/s 500 450 400 350 300 250 200 150 100 50 0 図 2 1 回に書き込むサイズとディスク書き込み速度 SR11000/J1 write SR11000/J1 fwrite SR8000/MPP write SR8000/MPP fwrite 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M 128M 256M 512M 1G 2G 4G 8G 低水準入出力関数 write を使ったプログラムと高水準入力関数 fwrite を使ったプログラムでは 実行時間にほとんど差がありませんでした これは 内部バッファサイズと同じサイズ以上のデータを fwrite で書き込もうとした場合に 内部バッファ経由ではなく 直接 ディスクに書き込む処理を行っているからだと考えられます そのため 低水準入出力関数を使用しなくても 高水準入出力関数を使えば十分な性能が得られることになります ファイルシステム para-io を使う場合 1 回に書き込むサイズを 8MB 以上になるようにすれば SR8000/MPP では約 170MB/s SR11000/J1 では約 420MB/s という転送速度になります 補足事項 1. SR11000/J1 では 仕様により fwrite で 2GB 以上のデータを一度に書き込もうとすると失敗します fwrite(a,sizeof(double),bsize,fp); のように書かれている部分を write(fileno(fp),a,sizeof(double)*bsize); のように write に書き換えると 2GB 以上のデータも書き込むことができるようになります fileno はファイルハンドルに対応するファイルディスクリプタを返すマクロ関数です 2. fwrite で内部バッファサイズを超えるデータをファイルに出力する場合 内部バッファサイズ単位毎にデータを内部バッファにコピーしてファイル出力を行うか あるいは 内部バッファを経由せずに直接データ全体を出力するかはシステムに依存します これらはシステムコール追跡コマンドで open システムコールの呼び出し部分を解析することで調べることができます システムコール追跡コマンドは SR11000/J1 では truss FreeBSD であれば ktrace Linux であれば strace というコマンド名になります