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