3

我编写了一个波前 Obj 解析器类,将 obj 模型导入到我的 OpenGL 项目中。我在调试模式下测试了这个类,发现它慢得让人难以忍受。

代码有效,我进行了明显的调整,以确保它在合理实用的范围内尽可能高效。

尽管如此,加载我的测试文件,一个 12mb 的 obj 文件,运行大约 330,000 行文本,需要一分钟才能解析。

沮丧,我有一个谷歌,果然,我不是第一个遇到这个问题的人

这个在 gamedev.net 上发布查询的人只是在发布模式下运行他的算法,在 Visual Studio IDE 和 whammo 之外运行,性能可以接受。这也对我有用,我的 ~70 秒减少到 ~3 秒。

我对算法进行了一些分析,瓶颈在于对 std::getline 的调用,如下所示:

sstream >> sToken;

其中 sstream 是 std::stringstream 而 sToken 是 std::string (预先保留空间)。

问题

为什么 IDE 在运行我的解析算法时速度如此之慢(即使在发布模式下) - 在通过 IDE 运行代码时我能做些什么来加快速度(F5 - 运行项目)?这使得调试变得非常缓慢。IDE 是否将代码/挂钩注入到可执行文件中以通过 IDE 运行,或者这是否可以归结为缓存未命中或其他原因?

优化

我对文件进行两次传递,在传递一次时,我只计算令牌类型 - 这样我就可以保留空间(而不是迭代地增长存储顶点、法线、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 回答