2012-02-11 15 views
2

可能な限り最速のランタイムを実現するためにC++プログラムを最適化するのに問題があります。IOをC++で最適化

コードの要件は、ファイルにプログラムに入力された2つの長整数の差の絶対値を出力することです。すなわち:

./myprogram < unkownfilenamefullofdata 

ファイル名が不明で、スペースで区切っ行につき2つの数字を持っています。未知の量のテストデータがあります。私はテストデータの2つのファイルを作成しました。 1つは極端な場合があり、5ランである。もう一つは、Javaプログラムを使って200万の乱数を生成し、それをtimedrunファイルに出力しました。

大量のファイルは3.4秒で実行されます。私は1.1秒にそれを打破する必要があります。

これは私のコードです:

int main() { 
long int a, b; 
while (scanf("%li %li",&a,&b)>-1){ 
    if(b>=a) 
    printf("%li/n",(b-a)); 
    else 
    printf("%li/n",(a-b)); 
    } //endwhile 
return 0; 
}//end main 

私は私のプログラム上のValgrindを走り、それがホールドアップの多くは、読み取りと書き込みの部分であることを示しました。私が数字だけを受け取ることを知っているなら、print/scanをC++の最も未加工の形式に書き換えるにはどうしたらよいですか?数字を2進数でスキャンし、論理演算でデータを操作してその差を計算する方法はありますか?私もバッファを書くことを検討するように言われましたが、Webを検索してコードを試してから約6時間後、私は失敗でした。

ご協力いただければ幸いです。

+0

最適化してコンパイルしましたか? – Dave

+0

出力も同様にリダイレクトします。 –

+1

プログラムはファイルを読み取っていません。リダイレクトを使用してファイルの内容をプログラムに送ります。ファイルをアプリケーションに直接ロードし、メモリに完全にロードし、scanfよりも低いレベルのルーチンを解析して解析します。 –

答えて

2

何をする必要があるのか​​は、文字列全体をメモリにロードしてから、繰り返しI/O呼び出しを行うのではなく、そこから数値を抽出することです。しかし、あなたがよく知っていることは、ハードドライブから18MBをロードするだけの時間がかかることです。

+2

現代的なハードドライブは、80-120 MB/sの読み取りが可能です。これは、取られた時間を説明するものではありません。 –

+0

@BenVoigt:彼は合理的に現代的なハードドライブを持っていると誰が言う? – Puppy

+0

あなたはそうです。彼がパフォーマンスを気にするなら、おそらくSATA-II SSD(200 MB/s)またはSATA-III SSD(500 MB/s)を持っているだろう。またはホットファイルシステムキャッシュ(複数GB /秒)。 –

1

ファイルの形式を保証することができるので、scanfを大幅に向上させることができます。形式が何であるかを正確に知っているので、多くのエラーチェックは必要ありません。また、printfは新しい行をあなたのプラットフォームの適切な改行に変換します。

私は、この整数にあるのと同様のコードを使用しています(nosyのポストページの半分を参照してください)。読み込み整数領域でかなり大きなスピードアップが得られました。負の数を扱うには、それを変更する必要があります。うまくいけば、より速いprintf関数を書く方法についていくつかのアイデアを得ることができればうれしいですが、私はscanfを置き換えることから始まり、それがどれくらい遠くにあるのかを見ていきます。

+0

整数= 'itoa' +' puts'の方が速い 'printf'です。最適化された 'itoa' [here](http://stackoverflow.com/questions/4351371/c-performance-challenge-integer-to-stdstring-conversion)。 –

1

問題が示唆しているように、これらの数字をすべて読み込み、テキストからバイナリに変換することです。

最高の改善点は、プログラムをバイナリとして生成するすべてのプログラムから数値を書き出すことです。これにより、ディスクから読み取らなければならないデータの量を大幅に削減し、テキストからバイナリへの変換に必要な時間をわずかに短縮します。

あなたは、2,000,000の数字が1つの数字あたり18MB = 9バイトを占めているとします。これには空白と行末マーカーが含まれているので、妥当と思われます。

数値を4バイトの整数として格納すると、ディスクから読み取らなければならないデータ量の半分になります。フォーマット変換の節約に加えて、パフォーマンスの倍増を期待するのは合理的です。

さらに多くのものが必要なので、さらに過激なものが必要です。データファイルを別々のファイルに分割し、それぞれを独自のディスクに分割し、各ファイルを独自のプロセスで処理することを検討する必要があります。4つのコアがあり、処理を4つの別々のプロセスに分割し、4つの高性能ディスクを接続できる場合は、パフォーマンスを2倍にすることを望むかもしれません。ボトルネックは現在OSディスク管理であり、OSが4つのディスクをどれだけうまく並列管理するかを推測することは不可能です。

これは、処理が非常に単純化されたモデルであると仮定します。あなたの記述がそこにあるならば、本当の解決策は、テストファイルを書くプログラムの減算をすることでしょう!

+0

"最高の改善[...]は数字[...]をバイナリとして書いています。 <---これ。 (まあ、これとメモリはパイプを介してすべてをプッシュするのではなくファイルをマップします)。 – Damon

0

あなたのプログラムでファイルを開き、すべてを一度に読むよりも、それをメモリマッピングする方がよいでしょう。あなたのプログラムで利用可能な〜2GBのアドレス空間には〜18MBは問題ありません。

次に、strtodを使用して番号を読み取り、ポインタを前進させます。

入力リダイレクションと比較して5〜10倍のスピードアップを期待しています。scanfです。