-1

配列aをbに設定することを含む、最適化しようとしているCコードがあります。私は現在これを達成するために memcpy を使用していますが、動作しますが、十分に高速ではありません。いえ

double a[4] = {1.0, 2.0, 3.0, 4.0};
double b[4];
memcpy(b, a, sizeof(a));

これは基本的な例です。私のプログラムは似ていますが、最大 9000 個の double を使用します。ポインターを使用すると時間を大幅に節約できることはわかっていますが、その方法がわかりません。大変お世話になりました。

編集:破棄できる配列を保持する必要はありません。a から b に転送するだけです。

4

2 に答える 2

8

memcpy()うまくいかない場合は、行き詰まっています。memcpy()大きなオペランドの場合、この関数はメモリにバインドされているため、 *それを打ち負かすことはできません。唯一のオプションは、配列をコピーする必要がないようにプログラムを再設計することです。

(「メモリバウンド」とmemcpy()は、RAMまたはメモリコントローラーの速度によって制限されることを意味します。機能は、CPUバウンド、メモリバウンド、IOバウンドなどです。)

ほとんどのプラットフォームでmemcpy()は、手作業で調整されたアセンブリ言語で記述されており、さまざまなプロセッサ機能 (SSE など) を利用できるように大幅に最適化されています。複数のコアを使用しようとしてもうまくいきません。より多くのコアに作業を分散させたとしても、より多くの RAM やメモリ コントローラーに作業を分散させることにはならないからです。

脚注

*一部のプラットフォームまたはツールチェーンでは、最適化が不十分なmemcpy().

于 2013-05-21T08:30:04.130 に答える
3

b の値を使用して、a の新しい値を決定します。データの収束を確認する while ループを通過します。

その場合、次のように配列を前後に切り替えると、コピーを回避できる場合があります(これは、あなたが書いたものとは逆です。必要に応じて調整してください)。

double array1[SIZE], array2[SIZE];
double* a = array1, double* b = array2;
generate_initial_values(array1);

for (;;)
{
    // do either 
    memcpy(b, a, sizeof array1); // sizeof either array will do; *don't* use sizeof a or b, which is only the size of the pointer, not of the array
    update_values_in_b(b);

    // or, better:
    produce_modified_values_in_b_from_a(a, b);

    if (converged(a, b)) break;
    // switch arrays
    double* temp_ptr = a;
    a = b;
    b = temp_ptr;
}

それがうまくいく場合は、2番目の方法で行う方が高速です。memcpy が必要な場合は、非常に高速な memcpy for image processing?の内容を試すことができます。ですが、おそらく memcpy を使用して、コンパイラの最適化レベルをできるだけ高く設定するのが最善の方法です。#include <string.h>memcpy への size 引数がコンパイル時の定数 (上記) であることを確認し、生成されたアセンブリ コードを調べて、コンパイラがコピーをインライン化していることを確認します。

編集:待ってください、配列を切り替える必要さえない別の考えがあります:

double a[SIZE], b[SIZE];
generate_initial_values(a);

for (;;)
{
    produce_modified_values_in_second_array_from_first(a, b);
    if (converged(a, b)) break;
    produce_modified_values_in_second_array_from_first(b, a);
    if (converged(b, a)) break;
}

ループを終了すると、どの配列に最新の値があるかわかりませんが、それらが収束した場合はおそらく気にしません。その場合は、最新の値へのポインターを設定するか、関数を使用できます。

void calling_function(void)
{
    ...
    double a[SIZE], b[SIZE];
    generate_initial_values(a);
    double* great_values = get_great_values(a, b); // returns either a or b
    ...
}

double* get_great_values(double* a1, double* a2)
{
    for (;;)
    {
        produce_modified_values_in_second_array_from_first(a1, a2);
        if (converged(a1, a2)) return a2;
        produce_modified_values_in_second_array_from_first(a2, a1);
        if (converged(a2, a1)) return a1;
    }
}
于 2013-05-21T08:47:52.093 に答える