編集
最初の投稿のコード スニペット (以下を参照) では、 を に適切に送信していませんでしstruct
たdevice
。これは修正されましたが、結果は同じです。私の完全なコードでは、この間違いはありませんでした。(私の最初の投稿では、そのコマンドに 2 つの間違いがありました。1 つは、構造が からコピーされていましHostToDevice
たが、実際には反転されており、コピーのサイズも間違っていました。お詫びします。両方のエラーは修正されましたが、再コンパイルされたコードはまだ残っています。私の完全なコードと同様に、以下に説明するゼロ現象を表示します。)
EDIT 2
コードの非独占化の書き直しを急いで、私はいくつかのエラーを作成しましたが、dalekchefが親切に指摘してくれました(struct
デバイスへのコピーは、書き直されたコードとデバイスで、デバイスへの割り当ての前に実行されましたcudaMalloc
呼び出しにsizeof(...)
配列要素の型が乗算されませんでした.これらの修正を追加し、再コンパイルして再テストしましたが、問題は解決しませんでした.また、元のコードを再確認しましたが、これらの間違いはありませんでした.錯乱。
大規模なシミュレーション プログラムから統計をダンプしようとしています。同様の簡素化されたコードを以下に示します。どちらのコードも同じ問題を示します。平均値を出力する必要があるときにゼロを出力します。
#include "stdio.h"
struct __align__(8) DynamicVals
{
double a;
double b;
int n1;
int n2;
int perDump;
};
__device__ int *dev_arrN1, *dev_arrN2;
__device__ double *dev_arrA, *dev_arrB;
__device__ DynamicVals *dev_myVals;
__device__ int stepsA, stepsB;
__device__ double sumA, sumB;
__device__ int stepsN1, stepsN2;
__device__ int sumN1, sumN2;
__global__ void TEST
(int step, double dev_arrA[], double dev_arrB[],
int dev_arrN1[], int dev_arrN2[],DynamicVals *dev_myVals)
{
if (step % dev_myVals->perDump)
{
dev_arrN1[step/dev_myVals->perDump] = 0;
dev_arrN2[step/dev_myVals->perDump] = 0;
dev_arrA[step/dev_myVals->perDump] = 0.0;
dev_arrB[step/dev_myVals->perDump] = 0.0;
stepsA = 0;
stepsB = 0;
stepsN1 = 0;
stepsN2 = 0;
sumA = 0.0;
sumB = 0.0;
sumN1 = 0;
sumN2 = 0;
}
sumA += dev_myVals->a;
sumB += dev_myVals->b;
sumN1 += dev_myVals->n1;
sumN2 += dev_myVals->n2;
stepsA++;
stepsB++;
stepsN1++;
stepsN2++;
if ( sumA > 100000000 )
{
dev_arrA[step/dev_myVals->perDump] +=
sumA / stepsA;
sumA = 0.0;
stepsA = 0;
}
if ( sumB > 100000000 )
{
dev_arrB[step/dev_myVals->perDump] +=
sumB / stepsB;
sumB = 0.0;
stepsB = 0;
}
if ( sumN1 > 1000000 )
{
dev_arrN1[step/dev_myVals->perDump] +=
sumN1 / stepsN1;
sumN1 = 0;
stepsN1 = 0;
}
if ( sumN2 > 1000000 )
{
dev_arrN2[step/dev_myVals->perDump] +=
sumN2 / stepsN2;
sumN2 = 0;
stepsN2 = 0;
}
if ((step+1) % dev_myVals->perDump)
{
dev_arrA[step/dev_myVals->perDump] +=
sumA / stepsA;
dev_arrB[step/dev_myVals->perDump] +=
sumB / stepsB;
dev_arrN1[step/dev_myVals->perDump] +=
sumN1 / stepsN1;
dev_arrN2[step/dev_myVals->perDump] +=
sumN2 / stepsN2;
}
}
int main()
{
const int TOTAL_STEPS = 10000000;
DynamicVals vals;
int *arrN1, *arrN2;
double *arrA, *arrB;
int statCnt;
vals.perDump = TOTAL_STEPS/10;
statCnt = TOTAL_STEPS/vals.perDump+1;
vals.a = 30000.0;
vals.b = 60000.0;
vals.n1 = 10000;
vals.n2 = 20000;
cudaMalloc( (void**)&dev_arrA, statCnt*sizeof(double) );
cudaMalloc( (void**)&dev_arrB, statCnt*sizeof(double) );
cudaMalloc( (void**)&dev_arrN1, statCnt*sizeof(int) );
cudaMalloc( (void**)&dev_arrN2, statCnt*sizeof(int) );
cudaMalloc( (void**)&dev_myVals, sizeof(DynamicVals));
cudaMemcpy(dev_myVals, &vals, sizeof(DynamicVals),
cudaMemcpyHostToDevice);
arrA = (double *)malloc(statCnt * sizeof(double));
arrB = (double *)malloc(statCnt * sizeof(double));
arrN1 = (int *)malloc(statCnt * sizeof(int));
arrN2 = (int *)malloc(statCnt * sizeof(int));
for (int i=0; i< TOTAL_STEPS; i++)
TEST<<<1,1>>>(i, dev_arrA,dev_arrB,dev_arrN1,dev_arrN2,dev_myVals);
cudaMemcpy(arrA,dev_arrA,statCnt * sizeof(double),cudaMemcpyDeviceToHost);
cudaMemcpy(arrB,dev_arrB,statCnt * sizeof(double),cudaMemcpyDeviceToHost);
cudaMemcpy(arrN1,dev_arrN1,statCnt * sizeof(int),cudaMemcpyDeviceToHost);
cudaMemcpy(arrN2,dev_arrN2,statCnt * sizeof(int),cudaMemcpyDeviceToHost);
for (int i=0; i< statCnt; i++)
{
printf("Step: %d ; A=%g B=%g N1=%d N2=%d\n",
i*vals.perDump,
arrA[i], arrB[i], arrN1[i], arrN2[i]);
}
}
出力:
Step: 0 ; A=0 B=0 N1=0 N2=0
Step: 1000000 ; A=0 B=0 N1=0 N2=0
Step: 2000000 ; A=0 B=0 N1=0 N2=0
Step: 3000000 ; A=0 B=0 N1=0 N2=0
Step: 4000000 ; A=0 B=0 N1=0 N2=0
Step: 5000000 ; A=0 B=0 N1=0 N2=0
Step: 6000000 ; A=0 B=0 N1=0 N2=0
Step: 7000000 ; A=0 B=0 N1=0 N2=0
Step: 8000000 ; A=0 B=0 N1=0 N2=0
Step: 9000000 ; A=0 B=0 N1=0 N2=0
Step: 10000000 ; A=0 B=0 N1=0 N2=0
ここで、ダンプに短い期間を使用した場合、または # が小さかった場合は、直接だけで済む可能性があります
- 追加
- 期間と期末で割る
...アルゴリズムですが、そうしないint
とオーバーフローするため、一時的な合計を使用します(オーバーフローしdouble
ませんが、精度が失われることが心配でした)。
小さい値に対して上記の直接アルゴリズムを使用すると、ゼロ以外の正しい値が得られますが、2 番目に中間値 ( 、 など) を使用するとstepsA
、sumA
値がゼロになります。私はここでばかげたことをしていることを知っています...何が欠けていますか?
注:
A.) はい、上記の形式のこのコードは並列ではなく、それ自体では並列化が保証されないことを知っています。これは、はるかに長いコードの小さな統計収集部分の一部です。そのコードでは、スレッド インデックス固有の条件付きロジックに入れられて衝突を防ぎ (並列化)、シミュレーション プログラムへのデータ収集として機能します (並列化を保証します)。うまくいけば、上記のコードの出所を理解し、スレッド セーフの欠如についての卑劣なコメントを避けることができます。(この免責事項は、私がそれほど明確でない用語で書いているにもかかわらず、完全なコードではなく抜粋を投稿していることを理解していない人々から非生産的なコメントを受け取った過去の経験から追加されています。)
B.) はい、変数の名前があいまいであることは知っています。そこが肝心だ。私が取り組んでいるコードはプロプライエタリですが、最終的にはオープン ソースになります。過去に同様の匿名化されたコードを投稿し、命名規則について失礼なコメントを受け取ったので、これを書くだけです.
C.) はい、CUDA のマニュアルを何度か読みましたが、間違いを犯したり、理解できない機能がいくつかあることは認めます。ここでは共有メモリを使用していませんが、完全なコードでは共有メモリ (もちろん) を使用しています。
D.) はい、上記のコードは、動作していないコードのデータ ダンプ部分とまったく同じ機能を表しており、この特定の問題に関連しないロジックが削除され、スレッド セーフ条件が適用されています。変数名は変更されていますが、アルゴリズム的には変更されていないはずであり、これはまったく同じ非動作出力 (ゼロ) によって検証されます。
E.) 上記のスニペットの「動的」struct
には非動的な値があることに気付きました。完全なコードでは、これstruct
にはシミュレーション データが含まれており、動的であるため、この構造体に名前を付けました。簡素化されたコードの静的な性質により、統計収集コードが失敗することはありません。これは、各ダンプの平均が一定 (およびゼロ以外) であることを意味するだけです。