2009-04-20 13 views
12

私はLinuxシステムで "cat"関数をシミュレートするシステムコール(オープン、読み込み、書き込み)を使ってCでこの関数を実行しました。実際のものよりも遅いです...なぜ私の "cat"関数はシステムコールでLinuxの "cat"に比べて遅いのですか?

私は同じものを使用していますバッファサイズを実際の "cat"とし、 "strace"を使って同じ量のシステムコールを作っていると思います。しかし、私の "猫"からの出力は、実際の "猫"より少し遅いです。

これは私が持っているコードです:

#define BUFSIZ 32768 

int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) { 
    ssize_t writtenBytes = 0; 

    while(writtenBytes < readBytes) { 
     writtenBytes += write(fdout, 
      buffer + writtenBytes, readBytes - writtenBytes); 
     if(writtenBytes == -1) { 
      return -1; 
     } 
    } 

    return 0; 
} 

int catPrint(int fdin, int fdout) { 
    char buffer[BUFSIZ]; 
    ssize_t readBytes; 

    do { 
     readBytes = read(fdin, buffer, BUFSIZ); 

     if(readBytes == -1) { 
      return -1; 
     } 

     if(sysWriteBuffer(fdout, buffer, readBytes) == -1) { 
      return -1; 
     } 
    } while(readBytes > 0); 

    return 0; 
} 

私は、ファイルから読んでいる)私はcatPrint(呼び出しよりも(私がメインに引数として渡すことを、私はコードがここで必要とされていないと思います)そのファイル記述子を持つ関数と出力記述子を表す1つの関数がstdoutに出力されるようにします。

私は同じファイルをテスト用に使用しているため、実際の "cat"と私の両方の場合、テキスト全体に対してread()とwrite()が1つしかないので、なぜスローですか分かりません。テキスト全体が画面に表示されるべきではありませんか?

P.S:宿題の一部ではありませんが、ここで私の質問は遅いのですが、これを宿題とタグ付けしました。私はシステムコールを使って "cat"型関数を作成する必要がありました。私はちょうど少し遅い私のコードに興味を持っています。私から愚かで解決

問題:
は、私はちょうど、同じファイル上でLinuxのオリジナル猫次々と数回呼び出すことを決めた、と私はちょうどそれがまた、時代のいくつかを遅らせたことに気づいIそれは私のものと同じくらい遅いです。私はすべてがうまくいくと思います...

この人のようなあなたの時間を無駄にして申し訳ありません。

+1

IMHOでは、「宿題」タグは誤解を招きます。あなたの質問は興味深い背景事実に関係しています。 「宿題」とは、面倒な初心者の仕事、または(規模の反対側の)クイズの質問のいずれかを意味します。 –

+0

2番目のwrite()でエラーが発生した場合、エラー(つまり、-1を返すwrite)処理が不正です。 – jpalecek

+0

あなたは宿題タグを削除することができます。もしそれが良いと思えば... jpalecekとはどういう意味ですか?私は補助機能しか持っていません(システムコールのように)書き込みは1つだけです。その補助関数内のwrite()が失敗した場合、catPrint()が呼び出された場所に-1を返す必要があります。 –

答えて

15

ああ、あなたの編集に基づいて、先読みバッファに噛まれていました。ファイルを一度実行することによって、ファイルを読み込む2つのプログラムをテストすることはできません。最初のファイルはディスク上にあるので常に遅くなります。ファイルがメモリに入ったら、2番目のファイルは高速に実行されます。それぞれに新しいデータを作成するか、1つを実行してから両方を実行して、両方ともreadaheadバッファの利点を得ます。

1

どれくらいですか?正規の猫は、いくつかの指示を保存するようなものです

char bufr[BUFSIZ]; 
ssize_t len; 

while((len=read(fdin, bufr, BUFSIZ)) >0) 
    write(fdout, bufr, len); 

+0

これは標準バージョンかもしれませんが、間違ったもの(例えば、あなたが()を書いている間に信号が来る場合) – jpalecek

+0

"何かのようなもの"のどの部分が欠けていましたか? –

+0

私が言ったように、元のcatと私のcatは、バッファサイズが32768のwrite()と同じバッファサイズと最後のread()をread()と呼びますそうでなければ終了する)。 –

3

最適化せずに(または最適化設定を高くしないで)コンパイルしたのでしょうか?

また、コードはsysWriteBufferを一度readBytesと呼んでいます。おそらく(部分的に)説明していますか?

sysWriteBufferを(コンパイラスイッチまたは手作業で)インライン展開することもできます。

"inlining"は、関数の呼び出しのオーバーヘッドをなくすために、関数の本体を呼び出しサイトにコピーすることを意味します。時々コンパイラがこれを自動的に行います(-O3はgccでこの最適化を可能にします)。 gccinlineキーワードを使用して、関数をインライン化するようにコンパイラに指示することもできます。あなたがこれを行う場合は、あなたの宣言は次のようになります。

static inline int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) { 
.... 
+0

catでstraceを使用すると、そこにも発生することがわかりますので、私はそれを残しました...そして、私は-O2フラグを使用しています。 –

+0

「-O3 -funroll_loops」を試して、それがどのように動作するかを確認することができます。より良いのは、猫が編集された正確な旗を決定することです。 –

+0

フラップは-funroll-loops(2番目のハイフンはアンダースコアではありません)です。とにかくこのケースでは大したことはないと思います。 – Anthony

1

あなたは、両方のstrace Sを比較しましたか? -ttパラメータを使用して、システムコールのタイミングを取得しようとする可能性があります。

+0

straceに関する知識があまりなく、-ttパラメータを試してみましたが、数字の束が現れましたが、その意味を理解できません。 –

+0

パーツの読み書きを探してみてください(出力は "time syscall(parameters)= return value"の形式である必要がありますのでread()またはwrite()を探して投稿してください) – jpalecek

3

研究mmap(2)。

あなたはftell/freadの細部を捨ててしまいますが、読み取りスループットが本当に重要な場合は、間接レイヤーをスキップします。

+0

ありがとう、私はmmapが必要です。 –

+0

私はこの練習に何か他のものを使用することはできません。 –

2

ソースコードを比較しないと、言うことはできません。あなたの猫とGNU catを比較する場合は、数時間/日のコードと20年以上進化したコードを比較していることに注意してください。

異なるデバイス(RAMディスクが良い)から複数の行に複数の入力サイズの両方のプログラムを実行し、より包括的なパフォーマンス分析を行うことができます。プログラムのどこが遅いかを判断する必要があります。

猫自体は本当に些細なので(あなたはすでにコンパイルを最適化しているとコメントしています)、私が観察しているパフォーマンスの影響は実際のアルゴリズムではなく、プログラムの読み込み時間にあると思います。システムのバイナリがprelinked(最近のほとんどのディストリビューションでは一般的です)の場合、コンパイルしたプログラムよりも速く読み込まれていることがわかります(プログラムをプレリンクするまで)。

関連する問題