global memoryからshared memoryへの大量の読み込み(補足)

昨日の説明は文章だけでわかりにくかったから、矩形領域をglobal memoryからshared memoryへ読み込むコードと結果の追加。
uint4で読むときには一列をhalf warp(16thread)の1回の読み込みで済ましている。(今回は横幅の最大を64要素に制限しているので)
intで読むときは1warp (32thread)が一列の読み込みを担当する。
この時に横幅が32要素以上あるときにはループが必要になる。

uint4の方が速い場合があるという自分の主張のためにintで読み込む関数は、殆どチューニングしていない。
"常にintが速い派"の人がint側をチューニングすると結果は変わるかもしれない。

#include 
#include 

#define TEST_TIMES (1024*64)
#define MAX_WIDTH  64
#define MAX_HEIGHT 48

__shared__ int buffer[MAX_WIDTH * MAX_HEIGHT];

/* uint4型で読み込む */
__global__ void load_uint4(int *in, int w, int h)
{
    int i, j;

    for (i=0; i> 4;
        int x = tid & 15;
        int h_ofs = blockDim.x >> 4;

        if (x * 4 < w){
            for (; line < h; line += h_ofs){
                int *a = in + w * line + 4 * x;
                int *b = buffer + w * line + 4 * x;
                *(uint4*)b = *(uint4*)a;
            }
        }
        __syncthreads();
    }
}

/* int型で読みこむ */
__global__ void loat_int(int *in, int w, int h)
{
    int i, j;

    for (i=0; i> 5;
        int x = tid & 31;
        int x_loop = (w+31) >> 5;
        int y_ofs = (blockDim.x >> 5);

        for (;line < h; line += y_ofs){
            int *a = in + w * line + x;
            int *b = buffer + w * line + x;

            for (j = 0; j < x_loop; j++){
                if (x + j * 32 < w){
                    int v;
                    v = a[j * 32];
                    b[j * 32] = v;
                }
            }
        }
        __syncthreads();
    }
}

int main()
{
    void *p;
    cudaEvent_t s, e;
    int wtbl = {32, 48, 64};
    int htbl = {4, 5, 8, 9, 16, 17, 32, 48};
    int i, j;

    cudaEventCreate(&s);
    cudaEventCreate(&e);

    cudaMalloc(&p, MAX_WIDTH*MAX_HEIGHT*sizeof(int));

    float v1, v2;
    for (i = 0;i < sizeof(htbl)/sizeof(int); i++){
        for (j = 0; j < sizeof(wtbl)/sizeof(int); j++){
            cudaEventRecord(s, 0);
            load_uint4<<<1,64>>>((int*)p, wtbl[j], htbl[i]);
            cudaEventRecord(e, 0);

            cudaEventSynchronize(e);
            cudaEventElapsedTime(&v1, s, e);

            cudaEventRecord(s, 0);
            load_int<<<1,64>>>((int*)p, wtbl[j], htbl[i]);
            cudaEventRecord(e, 0);

            cudaEventSynchronize(e);
            cudaEventElapsedTime(&v2, s, e);

            printf("[%2d x %2d] uint4=%f int=%f\n", wtbl[j], htbl[i], v1, v2);
        }
    }
}

上のコードを実行するとこうなる。
[]の中は読み込む領域の幅x高さ。
実行にかかった時間の単位はms

[32 x 4] uint4=66.250656 int=119.388702
[48 x 4] uint4=73.464035 int=192.734009
[64 x 4] uint4=78.324257 int=192.731491
[32 x 5] uint4=104.425728 int=171.324326
[48 x 5] uint4=112.621086 int=278.363129
[64 x 5] uint4=123.332573 int=279.045105
[32 x 8] uint4=108.605698 int=223.904190
[48 x 8] uint4=119.630241 int=365.088013
[64 x 8] uint4=132.729858 int=367.008209
[32 x 9] uint4=144.567932 int=272.575806
[48 x 9] uint4=157.935013 int=458.384735
[64 x 9] uint4=175.682175 int=455.767151
[32 x 16] uint4=188.546112 int=428.510803
[48 x 16] uint4=209.417053 int=725.599609
[64 x 16] uint4=232.570526 int=713.375244
[32 x 17] uint4=226.004807 int=484.262482
[48 x 17] uint4=247.822525 int=812.188965
[64 x 17] uint4=270.601349 int=806.044556
[32 x 32] uint4=349.365509 int=845.310425
[48 x 32] uint4=385.352203 int=1414.444824
[64 x 32] uint4=429.602112 int=1444.995605
[32 x 48] uint4=508.608246 int=1259.764771
[48 x 48] uint4=557.349609 int=2130.817871
[64 x 48] uint4=624.313965 int=2143.508789