2012-07-10 49 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