在某个阈值后,Std :: vector填充时间从0ms到16ms?

时间:2010-07-11 19:47:46

标签: c++ vector performance

这就是我正在做的事情。我的应用程序在拖动时从用户获取点并实时显示填充的多边形。

它基本上在MouseMove上添加鼠标位置。这一点是一个USERPOINT并且具有更好的句柄,因为最终我会做得更好,这就是我必须将它们转换为向量的原因。

所以基本上是MousePos - &gt; USERPOINT。 USERPOINT被添加到std::vector<USERPOINT>。然后在我的UpdateShape()函数中,我这样做:

DrawingPoints的定义如下:

std::vector<std::vector<GLdouble>> DrawingPoints;


Contour[i].DrawingPoints.clear();



 for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x)
         SetCubicBezier(
             Contour[i].UserPoints[x],
             Contour[i].UserPoints[x + 1],
             i);

SetCubicBezier()目前看起来像这样:

void OGLSHAPE::SetCubicBezier(USERFPOINT &a,USERFPOINT &b, int &currentcontour )
{
std::vector<GLdouble> temp(2);

    if(a.RightHandle.x == a.UserPoint.x && a.RightHandle.y == a.UserPoint.y 
        && b.LeftHandle.x == b.UserPoint.x && b.LeftHandle.y == b.UserPoint.y )
    {

        temp[0] = (GLdouble)a.UserPoint.x;
        temp[1] = (GLdouble)a.UserPoint.y;

        Contour[currentcontour].DrawingPoints.push_back(temp);

        temp[0] = (GLdouble)b.UserPoint.x;
        temp[1] = (GLdouble)b.UserPoint.y;


        Contour[currentcontour].DrawingPoints.push_back(temp);

    }
    else
    {
         //do cubic bezier calculation
        }

因此,对于cubic bezier的原因,我需要将USERPOINTS设置为GlDouble [2](因为GLUTesselator接受一个double的静态数组。

所以我做了一些分析。在~100点,代码:

 for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x)
         SetCubicBezier(
             Contour[i].UserPoints[x],
             Contour[i].UserPoints[x + 1],
             i);

执行0 ms。然后大约120,它跳到16毫秒,永远不会回头。我很肯定这是由于std :: vector。我该怎么做才能让它保持0ms。我不介意在生成形状时使用大量内存,然后在形状完成时删除多余的东西,或类似的东西。

4 个答案:

答案 0 :(得分:12)

0ms没有时间......没有时间执行任何事情。这应该是您可能想要在时序结果上检查时序方法的第一个指标。

即,定时器通常没有良好的分辨率。您的16ms之前的结果可能实际上只有1ms - 在0ms时错误地报告了15ms。无论如何,如果我们能告诉你如何将它保持在0毫秒,那么我们就会变得富有而且很有名。

相反,找出循环的哪些部分花费的时间最长,然后优化它们。不要朝着任意时间的方向努力。我建议找一个好的剖析器来获得准确的结果。然后你不需要猜测什么是慢的(循环中的东西),但实际上可以看到哪个部分很慢。

答案 1 :(得分:1)

您可以使用vector::reserve()来避免DrawingPoints中不必要的重新分配:

Contour[i].DrawingPoints.reserve(Contour[i].size());    
for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x) {
   ...
}

答案 2 :(得分:1)

如果您实际上只计算了第二个代码片段(如您在帖子中所述),那么您可能只是从向量中读取。这意味着,原因不能是向量的重新分配成本。在这种情况下,它可能是由于CPU的缓存问题(即小数据集可以从cpu缓存中以闪电般的速度读取,但只要数据集大于缓存[或者当交替从不同的内存位置读取]时,cpu必须访问ram,它明显比缓存访问慢。)

如果您分析的代码部分将数据附加到向量,则在填充之前使用具有适当容量的std :: vector :: reserve()(向量中的预期条目数)。

但是,关于分析/基准测试的两个一般规则:

1)使用高分辨率精度的时间测量方法(正如其他人所说,计时器的分辨率太低)

2)在任何情况下,运行代码片段不止一次(例如100次),获取所有运行的总时间并将其除以运行次数。这将为您提供一些实数。

答案 3 :(得分:0)

这里有很多猜测。我想,这是一个很好的猜测,但猜测不过。当你试图测量功能所用的时间时,这并没有告诉你他们如何接受它。你可以看看你是否尝试过时间会改变的不同事物,从中可以得到一些关于时间花费的建议,但你无法确定。

如果你真的想知道花时间的是什么,你需要在花费时间时抓住它,并确定它正在做什么。一种方法是通过该代码在指令级单步执行,但我怀疑这是不可能的。下一个最好的方法是获取堆栈样本。您可以找到基于堆栈样本的分析器。就个人而言,我依靠手工技术for the reasons given here

请注意,这并不是关于测量时间。这是为了找出为什么花费额外的时间,这是一个非常不同的问题。