让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?
请假设特斯拉或费米建筑。我不想详述Kepler的32位与64位存储区配置。另外,为简单起见,我们假设所有随机数都不同(因此没有广播机制)。
我的直觉表明数字在4到6之间,但我想找一些数学评估。
我相信这个问题可以从CUDA中抽象出来,并作为数学问题出现。我搜索它作为生日悖论的延伸,但我在那里发现了非常可怕的公式,并没有找到最终的公式。我希望有一种更简单的方法......
答案 0 :(得分:6)
在数学方面,这被认为是“垃圾箱中的球”问题 - 32个球随机掉入32个垃圾箱。您可以枚举可能的模式并计算其概率以确定分布。虽然模式的数量很大,但天真的方法是行不通的:(63!)/(32!)(31!)几乎是一个五分之一。
如果您以递归方式构建解决方案并使用条件概率,则可以解决这个问题。
查找Charles J. Corrado撰写的一篇名为“Multinomial / Dirichlet和多变量超几何频率的最大值,最小值和范围的精确分布”的论文。
在下文中,我们从最左边的水桶开始,计算可能落入其中的每个球数的概率。然后我们向右移动一个,并根据已经使用的球和桶的数量确定可能在该桶中的每个球数的条件概率。
为VBA代码道歉,但是当我有动力回答时,VBA就是我所能提供的:)。
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
对于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
答案 1 :(得分:4)
我会尝试一个数学答案,虽然我还没有完全正确。
你基本上想知道,在一个warp中随机的32位字索引到一个对齐的__shared__
数组中,“映射到的warp中最大地址数的expected value是多少?一家银行?“
如果我认为问题类似于散列,则它与散列到单个位置的预期最大项目数有关,而{n}与散列n个项目的散列有关this document shows an upper bound on that number of O(log n / log log n)。 (数学非常多毛!)。
对于n = 32,可以达到约2.788(使用自然对数)。这没关系,但在这里我修改了ahmad的程序,以经验计算预期的最大值(也简化了代码和修改后的名称等,以便清晰并修复了一些错误)。
#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;
}
使用程序中找到的百分比作为概率,预期的最大值是产品sum(i * probability(i))
的总和,i
从1到32.我计算预期值为3.529(匹配ahmad的数据)。这不是很远,但2.788应该是一个上限。由于上限是用大O表示法给出的,我想有一个常数因素被遗漏了。但就目前而言,这已经达到了目前的水平。
开放式问题:这个常数因素是否足以解释它?是否可以计算n = 32的常数因子?协调这些,和/或找到一个封闭的形式解决方案,以获得32个银行和32个并行线程的预期最大银行冲突程度将是有趣的。
这是一个非常有用的主题,因为当共享内存寻址实际上是随机的时,它可以帮助建模和预测性能。
答案 2 :(得分:3)
我假设fermi 32-bank共享内存,其中每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;
}
我得到了以下输出:
Over 0 random shared memory access, there found following precentages of bank conflicts
0 -> 0.0000
1 -> 0.0000
2 -> 0.0281
3 -> 0.5205
4 -> 0.3605
5 -> 0.0780
6 -> 0.0106
7 -> 0.0022
8 -> 0.0001
9 -> 0.0000
10 -> 0.0000
11 -> 0.0000
12 -> 0.0000
13 -> 0.0000
14 -> 0.0000
15 -> 0.0000
16 -> 0.0000
17 -> 0.0000
18 -> 0.0000
19 -> 0.0000
20 -> 0.0000
21 -> 0.0000
22 -> 0.0000
23 -> 0.0000
24 -> 0.0000
25 -> 0.0000
26 -> 0.0000
27 -> 0.0000
28 -> 0.0000
29 -> 0.0000
30 -> 0.0000
31 -> 0.0000
32 -> 0.0000
我们可以得出结论,随机访问最有可能发生3到4路冲突。您可以使用不同的N
(数组中的元素数),NBANK
(共享内存中的库数),WARPSIZE
(机器的warp大小)和{{1来调整运行(为评估模型而生成的随机共享内存访问次数)。