【问题标题】:Why is this code running over 100 times slower in Debug mode than Release?为什么这段代码在 Debug 模式下的运行速度比 Release 慢 100 倍以上?
【发布时间】:2016-04-09 08:53:18
【问题描述】:

转帖原因:

原来我只有一个回复,只是指出标题被夸大了。因此再试一次,也许这次会有更多人看到这个问题,因为我真的不知道该去哪里找……我会确保删除原来的问题以避免重复,并保留这个新问题。我不是想向论坛发送垃圾邮件。

在编辑时请随意删除上面的文字,我只是想解释为什么我要重新发布 - 但这并不是问题的一部分。

所以,原来的问题是:

我的程序中有一些函数在调试模式下运行非常慢,在 Visual Studio Community, 2015 中。它们是用于“索引”3D 模型顶点的函数。

通常情况下,我准备让调试模式慢一点,可能慢 2 -3 倍。但是……

Release模式下,程序在大约2-3秒内启动并索引模型。完美。

然而,在 Debug 模式下,我的程序需要 7 分钟 才能真正响应、开始渲染和接受输入。索引一个模型超过七分钟。在此期间,程序完全冻结。

相同的模型在“发布”模式下加载和索引不到 3 。 Debug 怎么可能花这么长的时间?

调试和发布模式都是开箱即用的标准模式。我不记得更改其中任何一个中的任何设置。

这是在调试模式下减慢程序速度的代码:

// Main Indexer Function
void indexVBO_TBN(
std::vector<glm::vec3> &in_vertices,
std::vector<glm::vec2> &in_uvs,
std::vector<glm::vec3> &in_normals,
std::vector<glm::vec3> &in_tangents,
std::vector<glm::vec3> &in_bitangents,

std::vector<unsigned short> & out_indices,
std::vector<glm::vec3> &out_vertices,
std::vector<glm::vec2> &out_uvs,
std::vector<glm::vec3> &out_normals,
std::vector<glm::vec3> &out_tangents,
std::vector<glm::vec3> &out_bitangents){

int count = 0;

// For each input vertex
for (unsigned int i = 0; i < in_vertices.size(); i++) {

    // Try to find a similar vertex in out_vertices, out_uvs, out_normals, out_tangents & out_bitangents
    unsigned int index;
    bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i], out_vertices, out_uvs, out_normals, index);

    if (found) {
        // A similar vertex is already in the VBO, use it instead !
        out_indices.push_back(unsigned short(index));

        // Average the tangents and the bitangents
        out_tangents[index] += in_tangents[i];
        out_bitangents[index] += in_bitangents[i];
    } else {
        // If not, it needs to be added in the output data.
        out_vertices.push_back(in_vertices[i]);
        out_uvs.push_back(in_uvs[i]);
        out_normals.push_back(in_normals[i]);
        out_tangents.push_back(in_tangents[i]);
        out_bitangents.push_back(in_bitangents[i]);
        out_indices.push_back((unsigned short)out_vertices.size() - 1);
    }
    count++;
}
}

然后是它使用的 2 个小“助手”函数(isNear()getSimilarVertexIndex()):

// Returns true if v1 can be considered equal to v2
bool is_near(float v1, float v2){
return fabs( v1-v2 ) < 0.01f;
}


bool getSimilarVertexIndex( glm::vec3 &in_vertex, glm::vec2 &in_uv, glm::vec3 &in_normal,
                        std::vector<glm::vec3> &out_vertices, std::vector<glm::vec2> &out_uvs, std::vector<glm::vec3> &out_normals,
                        unsigned int &result){
// Lame linear search
for (unsigned int i = 0; i < out_vertices.size(); i++) {

    if (is_near(in_vertex.x, out_vertices[i].x) &&
        is_near(in_vertex.y, out_vertices[i].y) &&
        is_near(in_vertex.z, out_vertices[i].z) &&
        is_near(in_uv.x, out_uvs[i].x) &&
        is_near(in_uv.y, out_uvs[i].y) &&
        is_near(in_normal.x, out_normals[i].x) &&
        is_near(in_normal.y, out_normals[i].y) &&
        is_near(in_normal.z, out_normals[i].z)
        ) {
        result = i;
        return true;
    }
}
return false;
}

上述功能的所有功劳归于: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/

这可能是:

  1. Visual Studio 社区 2015 年问题?
  2. VSC15 调试模式问题?
  3. 代码慢? (但它只是在 Debug 中很慢?!)

【问题讨论】:

  • 这很慢,因为调试模式会关闭优化器并启用大量昂贵的运行时检查,例如越界数组索引和内存溢出检测。
  • 核心问题是您对代码应该在调试构建中的速度有非常不切实际的期望。优化器对于获得高性能的 STL 集合代码至关重要,它已关闭。非常好的迭代器调试功能也大大减慢了代码速度。您可以使用 _HAS_ITERATOR_DEBUGGING 轻松关闭它,但是,这有什么意义。只需使用较小的数据集来调试您的代码。
  • 没有。我在问为什么特定的一小段代码明显(!!!)慢(而不是程序的其余部分)。一旦程序通过了上述代码,它一点也不慢。只是一段代码在调试模式下运行缓慢。在执行“索引”功能之前和之后,我运行的所有其他代码都运行良好。
  • 致所有其他回复(Roger、Hans 和 Ice),尤其是 Ice,谢谢各位,我今天下午会调查!
  • 我同意这很奇怪:100 倍的减速是不寻常的,绝对值得研究。多少次迭代(围绕主循环多少次)?如果在调试模式下启用优化会怎样?

标签: c++ performance debugging visual-studio-2015


【解决方案1】:

有很多东西会/可能会被优化:

  1. 使用索引[] 迭代向量比使用迭代器要慢;在调试中,这当然没有优化,但在发布时可能会
  2. 此外,由于处于调试模式时的运行时检查和调试功能,通过[] 访问向量很慢;当您转到operator[] 的实现时,可以很容易地看到这一点
  3. push_backsize 可能还有一些额外的检查,而不是在使用释放模式时退出

所以,我的主要猜测是你使用[] 太多了。当您通过使用真正的迭代器更改迭代时,它可能会更快发布。所以,而不是:

for (unsigned int i = 0; i < in_vertices.size(); i++) {

使用:

for(auto& vertex : in_vertices)

这间接使用了迭代器。你也可以明确地写:

   for(auto vertexIt = in_vertices.begin(); vertexIt != in_vertices.end(); ++vertexIt)
   {
      auto& vertex = *vertexIt;

显然,这是更长的代码,看起来不太可读并且没有实际优势,除非您需要迭代器来执行某些其他功能。

【讨论】:

  • 非常感谢Ice的帮助和广泛的解释,今天下午将进行调查! :)
猜你喜欢
  • 2016-08-08
  • 2012-09-19
  • 2022-06-20
  • 1970-01-01
  • 2011-05-02
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多