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