2012-05-04 17 views
3

objモデルをOpenGLプロジェクトにインポートするために、Wavefront Objパーサークラスを作成しました。私はクラスをデバッグモードでテストしたところ、それは耐え難いほど遅いことがわかった。ストリーム解析アルゴリズムの速度問題

コードは機能していて、合理的に効率的だったことを確認するために、わかりやすく調整しました。

まだ、私のテストファイルをロードすると、およそ330,000行のテキストに実行される12MBのobjファイルが解析に1分以上かかりました。

私はGoogleを持っていましたが、確かに、I wasn't the first person to run into this problemでした。

彼の質問をgamedev.netに投稿したこの男は、単にリリースモードで、Visual Studio IDEの外で許容可能なパフォーマンスを発揮したアルゴリズムを実行しました。これも私のために働いた、私の〜70秒は〜3秒に縮小されました。

私は、アルゴリズムのいくつかのプロファイリングをした、とボトルネックは::はstdへの呼び出しでのgetlineあり、中に以下:

sstream提供ははstd ::にstringstreamで、STOKENがSTDである
sstream >> sToken; 

::文字列(スペースがあらかじめ予約されている)

質問

なぜIDEが(でも、リリースモードで)私の構文解析アルゴリズムを実行している時とても信じられないほど遅いです - と私はIDEによって、コードを実行するときに、これをスピードアップするために何かできること(F5があります - プロジェクトを実行する)?これはデバッギングを非常に遅くしています。 IDEからIDEを実行するための実行可能コードにコード/フックを挿入しているのですか、これをキャッシュミスなどに置くことができますか?

最適化

私は、ファイルを2回通過を行うには、パス1に、私はちょうどトークンの種類を数える - 私はスペースを確保することができるように(というよりも、繰り返しの頂点を保存するベクトルを成長させ、法線、texcoords 、この最初のパスコストはほとんど(〜8デバッグモードで秒、または〜IDE外でリリースモードで0.3秒)と効率の節約は巨大であるが、(

sLineBuffer.reserve(100); 
sToken.reserve(10); 

while(sstream.good()) 
{ 
    sstream >> sToken; 
    getline(sstream, sLineBuffer); 

    if(sToken.compare("f") == 0) 
     nFaces ++; 

    else if(sToken.compare("v") == 0) 
     nVertices ++; 

    else if(sToken.compare("vn") == 0) 
     nNormals ++; 

    else if(sToken.compare("vt") == 0) 
     nTextures ++; 

    else if(sToken.compare("g") == 0) 
     nGroups ++; 
} 

m_Vertices.reserve(nVertices); 
m_Normals.reserve(nNormals); 
m_TexCoords.reserve(nTextures); 
m_Faces.reserve(nFaces); 
m_Groups.reserve(nGroups); 

)などに直面していることは〜180秒から解析時間を短縮しますデバッグモードで約60秒まで)。

式のうち、ディスクアクセスを取るように私はまた、にstringstreamにファイル全体をお読みください。

// Read entire file from disk into memory 
fstream stream; 
stringstream sstream; 
stream.open(m_sFilename.c_str(), std::ios::in); 
sstream << stream.rdbuf(); 
stream.close(); 

をまた、可能な場合、アルゴリズムを通じて、私はSTDのためのスペースを確保しようとする::前もって文字列、彼らはキャラクターごとにリサイズされていないよう:

sLineBuffer.reserve(100); 
sToken.reserve(10); // etc 
+0

おそらくファイルをmmappingすると役立つ可能性があります。 – mfontanini

+1

「IDEで実行する」とは、デバッガの下にあるのでしょうか、Ctrl-F5で起動するのと同じ問題がありますか?また、IDEの外で実行する場合、同じバイナリを使用していますか、どちらが「リリース」ビルドであってもコンパイラオプションに多少の違いが生じる可能性があります。 –

+1

これはおそらくあなたが報告している減速とは関係ありませんが、while(sstream.good())というコードは良い考えではありません。そのように '.good()'や '.eof()'をテストするI/Oループは[悪い習慣]です(http://stackoverflow.com/questions/4324441)。 – Blastfurnace

答えて

0

多くの小さな機能の重いインライン化を行うためのコンパイラを期待するようにSTLは、このような方法で書かれています。しかし、デバッガを使用すると、素晴らしい抽象レイヤーに入ることができます。デバッグモードでは、インラインではできないため、抽象度の高いレイヤーを作成することができます。

通常、私は以下のアドバイスはしませんが、OBJファイルの解析の文脈では、STLを投げ捨て、良い古い形式のfscanfステートメントに依存することをお勧めします。デバッグ時には大きなメリットがあり、リリースモードではスピードが大幅に向上します。

+0

stdioライブラリを使って書き直す必要がありましたが、STLのヒントは面白いです! ベクトルサイズを予約するためにトークンを数えると、大幅にスピードアップします。成長するにつれてサイズを変更する必要がないことを意味します。結果は自分自身のために話す、そこにあなたに同意しなければならない。最初のパスを削除した場合、2回目のパスには3倍の時間がかかります。 –

+0

最初のパスを削除すると、リリースビルド中に3回かかるか?あなたはデバッグビルド中に3倍の時間がかかりました。 – cdiggins

+0

はい、リリースビルドにはまだまだ時間がかかります。 –

1

この問題は、Visual Studio IDEの動作に誤解されていました。

DebugまたはReleaseビルドに関係なく、F5キーを押すと、デバッグモードが実行されます。

Ctrl + F5がデバッガを式から外していることを知りました(ただし、リリースビルドを実行している場合に限り、速度を上げることができます)。

また、この例ではstdioが優れた解決策である可能性があることもわかりました。提案したfscanfを使用するようにアルゴリズムを書き直す必要があります。私の考えはここに戻ってきますが、私はその考えにうんざりしています。