3

obj モデルを OpenGL プロジェクトにインポートするために、wavefront Obj パーサー クラスを作成しました。クラスをデバッグ モードでテストしたところ、耐えられないほど遅いことがわかりました。

コードは機能し、かなり実用的であると同時に効率的であることを確認するために、明らかな微調整を行いました。

それでも、約 330,000 行のテキストを実行する 12 MB の obj ファイルであるテスト ファイルの読み込みには、解析に 1 分以上かかりました。

イライラして、私は Google を持っていましたが、案の定、この問題に遭遇したのは私が初めてではありませんでした

gamedev.net にクエリを投稿したこの男は、Visual Studio IDE と whammo の外部で、リリース モードでアルゴリズムを実行しただけで、許容できるパフォーマンスでした。これも私にとってはうまくいきました。私の〜70秒は〜3秒に短縮されました。

アルゴリズムのプロファイリングを行ったところ、ボトルネックは std::getline の呼び出しと次の場所にあります。

sstream >> sToken;

ここで、sstream は std::stringstream であり、sToken は std::string (スペースが事前に予約されています) です。

質問

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

最適化

ファイルを 2 回パスし、パス 1 では、トークンの種類を数えるだけです。スペースを予約できるようにするためです (頂点、法線、texcoords、面などを格納するベクトルを繰り返し成長させるのではなく)。

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 );

この最初のパスはほとんどコストがかからず (デバッグ モードで最大 8 秒、IDE 外のリリース モードで最大 0.3 秒)、大幅に節約できます (デバッグ モードでの解析時間が最大 180 秒から最大 60 秒に短縮されます)。

また、ファイル全体を文字列ストリームに読み込んで、ディスク アクセスを方程式から外します。

// 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::strings 用のスペースを事前に予約して、文字ごとにサイズが変更されないようにします。

sLineBuffer.reserve( 100 );
sToken.reserve(10);  // etc
4

2 に答える 2

1

この問題は、Visual Studio IDE の動作方法に関する誤解であることが判明しました。

F5 を押すと、デバッグ ビルドでもリリース ビルドでも、デバッグ モードで実行されます。

Ctrl+F5 がデバッガーを方程式から外すことを学びました (ただし、これを実行すると速度が向上するのは、リリース ビルドを実行している場合のみです)。

また、この場合、stdio がより良い解決策になる可能性があることも学びました。提案どおりに fscanf を使用するようにアルゴリズムを書き直さなければなりません。また、私の発見をここに報告する必要があります。

于 2012-05-05T01:10:51.903 に答える
0

STL は、コンパイラが多くの小さな関数を大量にインライン化することを期待するように書かれています。ただし、デバッガーを使用すると、抽象化のすべての素晴らしいレイヤーにステップインできます。デバッグ モードでは、何もインライン化できないため、かなりの費用がかかります。

通常、私は次のようなアドバイスはしませんが、OBJ ファイルを解析するという文脈では、STL を捨てて、古き良き時代のfscanfステートメントに頼ることをお勧めします。デバッグ中に大幅な改善が見られ、リリース モード中の速度が大幅に向上することさえあります。

于 2012-05-05T00:04:27.213 に答える