Cuda 随机访问时共享内存中的预期银行冲突数
让Cuda 随机访问时共享内存中的预期银行冲突数,cuda,Cuda,让A成为共享内存中正确对齐的32位整数数组 如果单个warp尝试随机获取a的元素,预计的组冲突数是多少 换言之: __shared__ int A[N]; //N is some big constant integer ... int v = A[ random(0..N-1) ]; // <-- expected number of bank conflicts here? \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
A
成为共享内存中正确对齐的32位整数数组
如果单个warp尝试随机获取a
的元素,预计的组冲突数是多少
换言之:
__shared__ int A[N]; //N is some big constant integer
...
int v = A[ random(0..N-1) ]; // <-- expected number of bank conflicts here?
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu//N是一个大的常量整数
...
int v=A[random(0..N-1)];// 我假设费米32库共享内存,其中每个4个后续字节存储在后续库中。使用以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NBANK 32
#define N 7823
#define WARPSIZE 32
#define NSAMPLE 10000
int main(){
srand ( time(NULL) );
int i=0,j=0;
int *conflictCheck=NULL;
int *randomNumber=NULL;
int *statisticCheck=NULL;
conflictCheck=(int*)malloc(sizeof(int)*NBANK);
randomNumber=(int*)malloc(sizeof(int)*WARPSIZE);
statisticCheck=(int*)malloc(sizeof(int)*(NBANK+1));
while(i<NSAMPLE){
// generate a sample warp shared memory access
for(j=0; j<WARPSIZE; j++){
randomNumber[j]=rand()%NBANK;
}
// check the bank conflict
memset(conflictCheck, 0, sizeof(int)*NBANK);
int max_bank_conflict=0;
for(j=0; j<WARPSIZE; j++){
conflictCheck[randomNumber[j]]++;
max_bank_conflict = max_bank_conflict<conflictCheck[randomNumber[j]]? conflictCheck[randomNumber[j]]: max_bank_conflict;
}
// store statistic
statisticCheck[max_bank_conflict]++;
// next iter
i++;
}
// report statistic
printf("Over %d random shared memory access, there found following precentages of bank conflicts\n");
for(i=0; i<NBANK+1; i++){
//
printf("%d -> %6.4f\n",i,statisticCheck[i]/(float)NSAMPLE);
}
return 0;
}
我们可以得出结论,随机访问最有可能出现3到4路冲突。您可以使用不同的N
(数组中的元素数)、NBANK
(共享内存中的银行数)、WARPSIZE
(机器的扭曲大小)和NSAMPLE
(为评估模型而生成的随机共享内存访问数)来调整运行,虽然我还没有完全正确
您基本上想知道,如果将一个扭曲中的随机32位字索引放入对齐的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
如果我认为问题类似于哈希,那么它涉及到将散列到单个位置的预期最大项目数,并将n个项目散列到n个桶中。(这个数学问题很复杂!)
对于n=32,计算结果约为2.788(使用自然对数)。这很好,但我在这里修改了ahmad的程序,以经验计算预期的最大值(还简化了代码和修改了名称等,以便于澄清,并修复了一些bug)
#包括
#包括
#包括
#包括
#定义NBANK 32
#定义尺寸32
#定义NSAMPLE 100000
int main(){
int i=0,j=0;
int*银行=(int*)马洛克银行(sizeof(int)*NBANK);
int*randomNumber=(int*)malloc(sizeof(int)*WARPSIZE);
int*maxCount=(int*)malloc(sizeof(int)*(NBANK+1));
memset(maxCount,0,sizeof(int)*(NBANK+1));
对于(int i=0;i在数学中,这被认为是一个“桶中的球”问题-32个球被随机放入32个桶中。你可以列举可能的模式并计算它们的概率来确定分布。简单的方法是行不通的,因为模式的数量是巨大的:(63!)/(32!)(31!)“几乎”是五分之一
但是,如果您以递归方式构建解决方案并使用条件概率,就有可能解决这个问题
查找Charles J.Corrado的一篇论文,名为“多项式/狄里克莱和多元超几何频率的最大值、最小值和范围的精确分布”
下面,我们从最左边的桶开始,计算可能落入桶中的每个球数的概率。然后,我们向右移动一个,并根据已经使用的球数和桶数确定桶中可能存在的每个球数的条件概率
对于VBA代码,我深表歉意,但当我主动回答时,VBA是我仅有的一切:)
对于32个球和桶,我预计桶中的最大球数约为3.532941
要与ahmad进行比较的输出:
1 0.000000
2 0.029273
3 0.516311
4 0.361736
5 0.079307
6 0.011800
7 0.001417
8 0.000143
9 0.000012
10 0.000001
11 0.000000
12 0.000000
13 0.000000
14 0.000000
15 0.000000
16 0.000000
17 0.000000
18 0.000000
19 0.000000
20 0.000000
21 0.000000
22 0.000000
23 0.000000
24 0.000000
25 0.000000
26 0.000000
27 0.000000
28 0.000000
29 0.000000
30 0.000000
31 0.000000
32 0.000000
哈!在数学失败的地方,一个实验是有效的:)我仍然希望看到解决方案的一些数学公式,但如果我找不到任何东西,我就接受这种方法。rand()是一个非常糟糕的随机数生成器,windows上只有16位,Linux上只有32位…@harrism:我已经报告了Linux上的数字。我认为rand()
足够好,因为我们需要rand()%32
。这个分析对我来说似乎非常明智和有用。作为一个次要的观察,我认为在费米的情况下,它不能解释如果2(或更多)线程访问数组中完全相同的位置,这不是银行冲突,它是通过广播机制进行排序的。但从统计上看,我认为这不会对结果产生太大或根本没有影响。而且数组越大,发生这种情况的可能性越小。由于似乎很难得到数学公式,我只接受t他是答案。但是如果有人有更好的答案,请分享!好问题,+1。(我们需要在cuda标签上投票更多好问题!)我忘了提到,但应该插入一个很棒的博客,通过harrism的帖子在这里。回答很棒,谢谢。顺便说一句,提到的博客是John D Cook的,最近碰巧有一篇关于这个问题的帖子。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define NBANK 32
#define WARPSIZE 32
#define NSAMPLE 100000
int main(){
int i=0,j=0;
int *bank=(int*)malloc(sizeof(int)*NBANK);
int *randomNumber=(int*)malloc(sizeof(int)*WARPSIZE);
int *maxCount=(int*)malloc(sizeof(int)*(NBANK+1));
memset(maxCount, 0, sizeof(int)*(NBANK+1));
for (int i=0; i<NSAMPLE; ++i) {
// generate a sample warp shared memory access
for(j=0; j<WARPSIZE; j++){
randomNumber[j]=rand()%NBANK;
}
// check the bank conflict
memset(bank, 0, sizeof(int)*NBANK);
int max_bank_conflict=0;
for(j=0; j<WARPSIZE; j++){
bank[randomNumber[j]]++;
}
for(j=0; j<WARPSIZE; j++)
max_bank_conflict = std::max<int>(max_bank_conflict, bank[j]);
// store statistic
maxCount[max_bank_conflict]++;
}
// report statistic
printf("Max conflict degree %% (%d random samples)\n", NSAMPLE);
float expected = 0;
for(i=1; i<NBANK+1; i++) {
float prob = maxCount[i]/(float)NSAMPLE;
printf("%02d -> %6.4f\n", i, prob);
expected += prob * i;
}
printf("Expected maximum bank conflict degree = %6.4f\n", expected);
return 0;
}
Function nCr#(ByVal n#, ByVal r#)
Static combin#()
Static size#
Dim i#, j#
If n = r Then
nCr = 1
Exit Function
End If
If n > size Then
ReDim combin(0 To n, 0 To n)
combin(0, 0) = 1
For i = 1 To n
combin(i, 0) = 1
For j = 1 To i
combin(i, j) = combin(i - 1, j - 1) + combin(i - 1, j)
Next
Next
size = n
End If
nCr = combin(n, r)
End Function
Function p_binom#(n#, r#, p#)
p_binom = nCr(n, r) * p ^ r * (1 - p) ^ (n - r)
End Function
Function p_next_bucket_balls#(balls#, balls_used#, total_balls#, _
bucket#, total_buckets#, bucket_capacity#)
If balls > bucket_capacity Then
p_next_bucket_balls = 0
Else
p_next_bucket_balls = p_binom(total_balls - balls_used, balls, 1 / (total_buckets - bucket + 1))
End If
End Function
Function p_capped_buckets#(n#, cap#)
Dim p_prior, p_update
Dim bucket#, balls#, prior_balls#
ReDim p_prior(0 To n)
ReDim p_update(0 To n)
p_prior(0) = 1
For bucket = 1 To n
For balls = 0 To n
p_update(balls) = 0
For prior_balls = 0 To balls
p_update(balls) = p_update(balls) + p_prior(prior_balls) * _
p_next_bucket_balls(balls - prior_balls, prior_balls, n, bucket, n, cap)
Next
Next
p_prior = p_update
Next
p_capped_buckets = p_update(n)
End Function
Function expected_max_buckets#(n#)
Dim cap#
For cap = 0 To n
expected_max_buckets = expected_max_buckets + (1 - p_capped_buckets(n, cap))
Next
End Function
Sub test32()
Dim p_cumm#(0 To 32)
Dim cap#
For cap# = 0 To 32
p_cumm(cap) = p_capped_buckets(32, cap)
Next
For cap = 1 To 32
Debug.Print " ", cap, Format(p_cumm(cap) - p_cumm(cap - 1), "0.000000")
Next
End Sub
1 0.000000
2 0.029273
3 0.516311
4 0.361736
5 0.079307
6 0.011800
7 0.001417
8 0.000143
9 0.000012
10 0.000001
11 0.000000
12 0.000000
13 0.000000
14 0.000000
15 0.000000
16 0.000000
17 0.000000
18 0.000000
19 0.000000
20 0.000000
21 0.000000
22 0.000000
23 0.000000
24 0.000000
25 0.000000
26 0.000000
27 0.000000
28 0.000000
29 0.000000
30 0.000000
31 0.000000
32 0.000000