2

allのstd::vectorインスタンスに基づいて計算されるパラメーターのリストに対して要素単位の計算を行うことに基づいてパラメーターを計算する小さな関数がありl,t,d,nます。これは私のプログラムの速度のピンチポイントです - 私はプロファイリングしました、そして私は確信しています。l,t,d,nstd::vector<double>

これは、演算子を使用する作業スニペットです[]。Core i7、8GB RAM、Windows 7 の Visual C++ 2008 Express で C++ の開発を行っています。リリース モードは/O2最適化されています。最終的に、これは SWIG を使用して Python 拡張機能にコンパイルされますが、先を急ぐのはやめましょう。

また、C 配列を使用してソリューションをコーディングしました (以下を参照)(以前は C で使用していたソリューションですが、(私のアプリケーションでは) std::vectorsの使用が必要な C++ のオブジェクト指向ソリューションに移行しました。メモリリークを避けるためです。)

3つのソリューションすべてを以下に示します。std::vectorイテレータ ソリューションが (常に??) 配列と同じくらい高速である必要があることについて、SO や他の場所で多くの話を聞いたことがありますが、私の結果は、100 万回の呼び出しに次の時間がかかることを示しています。

  • std::vector[]オペレータあり:2.53秒
  • std::vectorイテレータあり: 2.69 秒
  • Cアレイ:0.58秒

したがって、明らかに配列ソリューションの方がはるかに高速です。std::vector ソリューションのコーディングで明らかな何かが欠けていますか?

編集

したがって、私の問題の一部はプロファイリングにあったようです。最適化により、c-array コードのほとんどが最適化されました。これが、どの std::vector オプションよりもはるかに高速だった理由です。すべての exp() および pow() 呼び出しを実行するスループットによって、根本的に制限されていると思います。すべての推奨事項をお寄せいただきありがとうございます。私のアプリケーションでは、プロセッサの速度に直面しているだけだと思います。19*6 の pow 呼び出しの約 2 マイクロ秒は、実際にはそれほど悪くはないと思います。しかし、私にはまだ遅すぎます。 C'est la vie...

std::vector<double>[]演算子による索引付けの使用

double phir_power::base(double tau, double delta) throw()
{
    double summer=0;
    for (unsigned int i=iStart;i<=iEnd;i++)
    {
        if (l[i]>0)
            summer+=n[i]*pow(delta,d[i])*pow(tau,t[i])*exp(-pow(delta,l[i]));
        else
            summer+=n[i]*pow(delta,d[i])*pow(tau,t[i]);
    }
    return summer;
}

std::vector<double>イテレータで

std::vector<double>::const_iterator n_begin=n.begin(), n_end = n.end(), n_iter = n_begin;
std::vector<double>::const_iterator d_begin=d.begin(), d_end = d.end(), d_iter = d_begin;
std::vector<double>::const_iterator t_begin=t.begin(), t_end = t.end(), t_iter = t_begin;
std::vector<double>::const_iterator l_begin=l.begin(), l_end = l.end(), l_iter = l_begin;

for (unsigned int uuu=0;uuu<1e6;uuu+=1)
{
    double summer=0;
    //Bring the iterators back to the first element
    l_iter = l_begin;
    d_iter = d_begin;
    t_iter = t_begin;
    n_iter = n_begin;
    for (; l_iter != l_end; ++l_iter,++t_iter,++d_iter,++n_iter)
    {
        if ((*l_iter)>0)
            summer+=(*n_iter)*pow(delta,(*d_iter))*pow(tau,(*t_iter))*exp(-pow(delta,(*l_iter)));
        else
            summer+=(*n_iter)*pow(delta,(*d_iter))*pow(tau,(*t_iter));
    }
    rrrrrrrr += summer;
}
t2 = clock();
printf("Time for 1 million calls  %g [s] val %g \n",((double)(t2-t1))/CLOCKS_PER_SEC,rrrrrrrr);

Cアレイ

double r=0;
t0 = clock();
unsigned int qwe;
double ttte = 0;
double term_;
for (unsigned int j=1;j<19;j++)
{
    t1=clock();
    r=0;
    for (unsigned int i=0; i<1e6; i++)
    {
        term_ = n[j]*pow(delta,d[j])*pow(tau,t[j]);
        if (l[j]>0)
            term_ *= exp(-pow(delta,l[j]));
        r+=term_;
    }
    ttte+=r/1e6;
    t2=clock();
    printf("Index %d time %g [s] val %g\n",j,((double)(t2-t1))/CLOCKS_PER_SEC,r/1e6);
}
t3=clock();
printf("Time for 1 million calls %g [s] val is %g\n",((double)(t3-t0))/CLOCKS_PER_SEC,ttte);
4

3 に答える 3

1

イテレータに基づくコードの問題は、1 つの double を含む 4 つのベクトルがあるため、operator[] バージョンの 1 つのインデックス i に対して 4 つのイテレータが必要なことです。4 つの反復子を維持するのはコストがかかりすぎます。4 つの double を含む構造体を含む単一のベクトルを使用するイテレータを使用すると、パフォーマンスが向上します。実際には、operator[] バージョンの方が高速である可能性があります。これは、ポインターの計算が少なくなり、データの局所性が向上し、CPU のスループットが向上するためです。

于 2012-07-02T07:28:20.700 に答える
1

違いは、提供している C コードでは、何も変更されていない小さなループ内に大きなループがあり、何かを何百万回も実行していることです。イテレータを含むコードでは、大きなループの中に小さなループがあります。つまり、イテレータを常に変更する必要があります。これには余分な時間がかかる場合があります。これについてはよくわかりませんが、テストできる場合は、試してみてください!

于 2012-07-02T07:16:46.373 に答える
0

std::vectorメモリの 1 つの連続したブロックとして割り当てられることが保証されているため、使用し[]たくない場合はその演算子を使用する必要はありません。

double phir_power::base(double tau, double delta) throw()
{
    double summer=0;

    double *pl = &l[0];
    double *pn = &n[0];
    double *pd = &d[0];
    double *pt = &t[0];

    for (unsigned int i = iStart; i <= iEnd; i++)
    {
        if (pl[i] > 0)
            summer += pn[i] * pow(delta, pd[i]) * pow(tau, pt[i]) * exp(-pow(delta, pl[i]));
        else
            summer += pn[i] * pow(delta, pd[i]) * pow(tau, pt[i]);
    }
    return summer;
}
于 2012-07-02T02:48:23.427 に答える