2012-07-10 68 views
0

我已经编写了一个例程,它使用的是相当多的std::vector<double>。它的运行速度相当缓慢,AQTime似乎暗示我正在构建山脉的矢量,但我不知道为什么我会。对于某些上下文,我的示例运行迭代10次。每次迭代将〜400个点的3个c数组复制到矢量中,并为输出创建3个新的相同大小的矢量。每个输出点可能是从2个输入向量中总计20个点的结果,这可以计算出最差的10 * 400 * 3 * 2 * 20 = 480,000个解除引用。令人难以置信的是,profiler指出一些std ::方法被称为4600万次。我怀疑我做错了什么!std ::需要进行矢量优化

一些代码:

vector<double>gdbChannel::GetVector() { 
    if (fHaveDoubleData & (fLength > 0)) { 
     double * pD = getDoublePointer(); 
     vector<double>v(pD, pD + fLength); 

     return v; 
    } else { 
     throw(Exception("attempt to retrieve vector on empty line")); ; 
    } 
} 

void gdbChannel::SaveVector(GX_HANDLE _hLine, const vector<double> & V) { 
    if (hLine != _hLine) { 
     GetLine(_hLine, V.size(), true); 
    } 
    GX_DOUBLE * pData = getDoublePointer(); 
    memcpy(pData, &V[0], V.size()*sizeof(V[0])); 
    ReplaceData(); 
} 

///This routine gets called 10 times 
bool SpecRatio::DoWork(GX_HANDLE_PTR pLine) { 
    if (!(hKin.GetLine(*pLine, true) && hUin.GetLine(*pLine, true) && hTHin.GetLine(*pLine, true))) { 
     return true; 
    } 
    vector<double>vK = hKin.GetVector(); 
    vector<double>vU = hUin.GetVector(); 
    vector<double>vTh = hTHin.GetVector(); 

    if ((vK.size() == 0) || (vU.size() == 0) || (vTh.size() == 0)) { 
     return true; 
    } 
    ///TODO: confirm all vectors the same lenghth 
    len = vK.size(); 
    vUK.clear(); // these 3 vectors are declared as private class members 
    vUTh.clear(); 
    vThK.clear(); 
    vUK.reserve(len); 
    vUTh.reserve(len); 
    vThK.reserve(len); 

    // TODO: ensure everything is same fidincr, fidstart and length 

    for (int i = 0; i < len; i++) { 
     if (vK.at(i) < MinK) { 
     vUK.push_back(rDUMMY); 
     vUTh.push_back(rDUMMY); 
     vThK.push_back(rDUMMY); 
     } else { 
     vUK.push_back(RatioPoint(vU, vK, i, UMin, KMin)); 
     vUTh.push_back(RatioPoint(vU, vTh, i, UMin, ThMin)); 
     vThK.push_back(RatioPoint(vTh, vK, i, ThMin, KMin)); 
     } 

    } 
    hUKout.setFidParams(hKin); 
    hUKout.SaveVector(*pLine, vUK); 
    hUTHout.setFidParams(hKin); 
    hUTHout.SaveVector(*pLine, vUTh); 
    hTHKout.setFidParams(hKin); 
    hTHKout.SaveVector(*pLine, vThK); 
    return TestError(); 
} 

double SpecRatio::VValue(vector<double>V, int Index) { 
    double result; 
    if ((Index < 0) || (Index >= len)) { 
     result = 0; 

    } else { 
     try { 
     result = V.at(Index); 
     if (OasisUtils::isDummy(result)) { 
      result = 0; 
     } 
     } 
     catch (out_of_range) { 
     result = 0; 
     } 
    } 
    return result; 
} 

double SpecRatio::RatioPoint(vector<double>Num, vector<double>Denom, int Index, double NumMin, double DenomMin) { 
    double num = VValue(Num, Index); 
    double denom = VValue(Denom, Index); 
    int s = 0; 
    // Search equalled 10 in this case 
    while (((num < NumMin) || (denom < DenomMin)) && (s < Search)) { 
     num += VValue(Num, Index - s) + VValue(Num, Index + s); 
     denom += VValue(Denom, Index - s) + VValue(Denom, Index + s); 
     s++; 
    } 
    if ((num < NumMin) || (denom < DenomMin)) { 
     return rDUMMY; 
    } else { 
     return num/denom; 
    } 

} 

顶部AQTime违者:

的std :: _ Uninit_copy>,双*,性病::分配器> 3.65秒 和115731点击

std :: _ Construct 1.69秒和46450637 Hits

std :: _ Vector_const_iterator> ::运营商 != 1.66秒和46566395个点击数等...

std::allocator<double>::construct
operator new
std::_Vector_const_iterator<double, std::allocator<double> >::operator ++std::_Vector_const_iterator<double, std::allocator<double> >::operator * std::_Vector_const_iterator<double, std::allocator<double> >::operator ==

每个被调用超过46万次。

我很明显是做错了,导致所有这些对象被创建。任何人都可以看到我的错误(S)?

回答

2

这是因为你正在通过值传递你的函数参数。每当一个std::vector按值传递时,必须完成一个向量的完整副本。

更改这些:

double SpecRatio::VValue(vector<double>V, int Index) { 

double SpecRatio::RatioPoint(vector<double>Num, vector<double>Denom... 

要:

double SpecRatio::VValue(const vector<double> &V, int Index) 

double SpecRatio::RatioPoint(const vector<double> &Num, const vector<double> &Denom... 

因为你使用,你从来没有真正需要作出这些载体的单独副本。

+0

当然,谢谢你。 – marcp 2012-07-10 06:00:19

+0

您还应该考虑更改'gdbChannel :: GetVector()'将输出向量传递给引用参数,而不是按值返回向量。这可以避免另一个副本,特别是如果编译器不实现[RVO](http://en.wikipedia.org/wiki/Return_value_optimization)。 – 2012-07-18 23:27:10

1

由于您传递它们并返回它们的方式(“按值”),您在几个地方复制矢量的效率很低(“深”)。例如,您的VValue()方法正在制作其矢量参数的副本,就像您的RatioPoint()方法一样,其中两个矢量参数都被完全复制(不必要地)。相反,您可能希望将向量参数作为const vector<double>&(即“通过引用”传递,就像在SaveVector()中那样)。

此外,您的GetVector()方法可能会返回矢量的副本,尽管如果编译器优化它可能会避免(如walrii在回复我的原始错误帖子时指出的那样)。如果你使用的是C++ - 11,你可以返回一个可移动的(正如walrii也指出的那样)。如果没有这些,解决方法有点棘手 - 你可以考虑在堆上分配矢量,并返回一个共享或自动指针。

+1

你的第二段是有点关闭。NVRO将处理它,如果你有C++ 11,那么会移动语义。使用堆对象会因分配而降低速度。 – walrii 2012-07-10 03:30:11

+0

@walrii好点。我将编辑它来修复它。 – Turix 2012-07-10 03:43:03