summaryrefslogtreecommitdiffstats
path: root/tools/cuda-ab/p2/src/p2_shapes.cu
blob: 93ae0e944d98905953e58fc0051602e411d77ae7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// SPDX-License-Identifier: BSD-3-Clause
/*
 * p2_shapes - grid/block shape variation with a bound-checked index-hash
 * kernel:
 *   case 1: 1x1x1 grid, 1x1x1 block (minimum launch)
 *   case 2: odd sizes        (n=1013, block 33, 31 blocks)
 *   case 3: non-multiple n   (n=1000, block 64, partial last block)
 *   case 4: 2D grid          (40x20, block 16x16, partial tiles)
 *   case 5: 3D grid          (24x8x8, block 8x4x2)
 *
 * Device memory: one 8 KB int buffer reused across cases (2 pages).
 */
#include "common.h"

#define MAXN 2048

struct shape {
	int nx, ny, nz;   /* logical extent    */
	int bx, by, bz;   /* block dims        */
	int gx, gy, gz;   /* grid dims         */
	int tag;
};

static const struct shape cases[] = {
	{   1,  1,  1,   1,  1,  1,   1,  1,  1, 1 },
	{1013,  1,  1,  33,  1,  1,  31,  1,  1, 2 },
	{1000,  1,  1,  64,  1,  1,  16,  1,  1, 3 },
	{  40, 20,  1,  16, 16,  1,   5,  2,  1, 4 },
	{  24,  8,  8,   8,  4,  2,   3,  2,  4, 5 },
};

#define NCASES ((int)(sizeof(cases) / sizeof(cases[0])))

__global__ void shape_kernel(int *out, int nx, int ny, int nz, int tag)
{
	int ix = blockIdx.x * blockDim.x + threadIdx.x;
	int iy = blockIdx.y * blockDim.y + threadIdx.y;
	int iz = blockIdx.z * blockDim.z + threadIdx.z;

	if (ix < nx && iy < ny && iz < nz) {
		int idx = (iz * ny + iy) * nx + ix;

		out[idx] = tag * 1000000 + idx;
	}
}

static void shape_expected(int *exp, const struct shape *s)
{
	for (int iz = 0; iz < s->nz; iz++)
		for (int iy = 0; iy < s->ny; iy++)
			for (int ix = 0; ix < s->nx; ix++) {
				int idx = (iz * s->ny + iy) * s->nx + ix;

				exp[idx] = s->tag * 1000000 + idx;
			}
}

int main(int argc, char **argv)
{
	int bad = 0;

	if (p2_emit_mode(argc, argv)) {
		int *exp = (int *)malloc(sizeof(int) * MAXN);

		for (int c = 0; c < NCASES; c++) {
			int n = cases[c].nx * cases[c].ny * cases[c].nz;

			shape_expected(exp, &cases[c]);
			printf("RESULT shapes case=%d n=%d bad=0\n",
			       cases[c].tag, n);
		}
		printf("RESULT shapes cases=%d bad=0\n", NCASES);
		free(exp);
		return p2_status(0);
	}

	p2_device_info();

	int *d_out = NULL, *h_got = (int *)malloc(sizeof(int) * MAXN);
	int *h_exp = (int *)malloc(sizeof(int) * MAXN);

	if (!h_got || !h_exp)
		return 1;
	P2_CHECK(cudaMalloc(&d_out, sizeof(int) * MAXN));

	for (int c = 0; c < NCASES; c++) {
		const struct shape *s = &cases[c];
		int n = s->nx * s->ny * s->nz;
		dim3 grid(s->gx, s->gy, s->gz), block(s->bx, s->by, s->bz);
		int sbad = 0;

		shape_kernel<<<grid, block>>>(d_out, s->nx, s->ny, s->nz,
					      s->tag);
		P2_CHECK(cudaGetLastError());
		P2_CHECK(cudaDeviceSynchronize());
		P2_CHECK(cudaMemcpy(h_got, d_out, sizeof(int) * n,
				    cudaMemcpyDeviceToHost));
		memset(h_exp, 0, sizeof(int) * n);
		shape_expected(h_exp, s);
		for (int i = 0; i < n; i++)
			if (h_got[i] != h_exp[i])
				sbad++;
		printf("RESULT shapes case=%d n=%d bad=%d\n", s->tag, n, sbad);
		bad += sbad;
	}
	printf("RESULT shapes cases=%d bad=%d\n", NCASES, bad);

	cudaFree(d_out);
	free(h_got); free(h_exp);
	return p2_status(bad);
}