summaryrefslogtreecommitdiffstats
path: root/tools/cuda-ab/p2/src/p2_mixed.cu
diff options
context:
space:
mode:
Diffstat (limited to 'tools/cuda-ab/p2/src/p2_mixed.cu')
-rw-r--r--tools/cuda-ab/p2/src/p2_mixed.cu273
1 files changed, 273 insertions, 0 deletions
diff --git a/tools/cuda-ab/p2/src/p2_mixed.cu b/tools/cuda-ab/p2/src/p2_mixed.cu
new file mode 100644
index 0000000..56f993d
--- /dev/null
+++ b/tools/cuda-ab/p2/src/p2_mixed.cu
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * p2_mixed - mail + vadd + int reduction + 2D grid + 2 streams in one
+ * process, freeing each phase before the next so the peak live device
+ * footprint stays at the vadd phase (3 x 32 KB = 24 pages).
+ *
+ * phase 1: device-authored mail via a parameter-buffer kernel
+ * phase 2: vectorAdd n=8192 (element-exact fp32)
+ * phase 3: 4096 -> 1 int reduction (shared memory + atomicAdd)
+ * phase 4: 2D grid hash kernel (40x20, block 16x16, partial tiles)
+ * phase 5: 2 streams, addv + scale per stream (exact fp32)
+ */
+#include "common.h"
+
+#define MIX_MAIL "the little gpu man says p2 mixed"
+#define VN 8192
+#define RD_N 4096
+#define G2_NX 40
+#define G2_NY 20
+#define ST_N 1024
+#define ST_NS 2
+
+__global__ void mail_kernel(char *out, const char *msg, int len)
+{
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+
+ if (i < len)
+ out[i] = msg[i];
+}
+
+__global__ void vadd(const float *a, const float *b, float *c, int n)
+{
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+
+ if (i < n)
+ c[i] = a[i] + b[i];
+}
+
+__global__ void reduce_sum(const int *in, int *out, int n)
+{
+ __shared__ int sdata[256];
+ int tid = threadIdx.x;
+ int i = blockIdx.x * blockDim.x + tid;
+
+ sdata[tid] = (i < n) ? in[i] : 0;
+ __syncthreads();
+ for (int s = blockDim.x >> 1; s > 0; s >>= 1) {
+ if (tid < s)
+ sdata[tid] += sdata[tid + s];
+ __syncthreads();
+ }
+ if (tid == 0)
+ atomicAdd(out, sdata[0]);
+}
+
+__global__ void grid2d(int *out, int nx, int ny)
+{
+ int ix = blockIdx.x * blockDim.x + threadIdx.x;
+ int iy = blockIdx.y * blockDim.y + threadIdx.y;
+
+ if (ix < nx && iy < ny) {
+ int idx = iy * nx + ix;
+
+ out[idx] = 1000000 + idx;
+ }
+}
+
+__global__ void addv(float *x, float v, int n)
+{
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+
+ if (i < n)
+ x[i] = x[i] + v;
+}
+
+__global__ void scale(float *x, float s, int n)
+{
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+
+ if (i < n)
+ x[i] = x[i] * s;
+}
+
+static int phase_mail(void)
+{
+ char h[128];
+ char *d_out = NULL, *d_msg = NULL;
+ int len = (int)strlen(MIX_MAIL);
+ int bad = 0;
+
+ if (cudaMalloc(&d_out, len) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&d_msg, len) != cudaSuccess) {
+ cudaFree(d_out);
+ return 1;
+ }
+ cudaMemcpy(d_msg, MIX_MAIL, len, cudaMemcpyHostToDevice);
+ mail_kernel<<<1, 64>>>(d_out, d_msg, len);
+ cudaGetLastError();
+ cudaDeviceSynchronize();
+ cudaMemcpy(h, d_out, len, cudaMemcpyDeviceToHost);
+ bad = (memcmp(h, MIX_MAIL, len) != 0) ? 1 : 0;
+ if (bad == 0)
+ printf("MAIL %s\n", h);
+ cudaFree(d_out);
+ cudaFree(d_msg);
+ printf("RESULT mixed mail bad=%d\n", bad);
+ return bad;
+}
+
+static int phase_vadd(void)
+{
+ float *h_a = (float *)malloc(sizeof(float) * VN);
+ float *h_b = (float *)malloc(sizeof(float) * VN);
+ float *h_c = (float *)malloc(sizeof(float) * VN);
+ float *d_a = NULL, *d_b = NULL, *d_c = NULL;
+ int bad = 0;
+
+ if (!h_a || !h_b || !h_c)
+ return 1;
+ for (int i = 0; i < VN; i++) {
+ h_a[i] = (float)(i % 1000) * 0.5f;
+ h_b[i] = (float)(i % 997) * 0.25f;
+ }
+ if (cudaMalloc(&d_a, sizeof(float) * VN) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&d_b, sizeof(float) * VN) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&d_c, sizeof(float) * VN) != cudaSuccess)
+ return 1;
+ cudaMemcpy(d_a, h_a, sizeof(float) * VN, cudaMemcpyHostToDevice);
+ cudaMemcpy(d_b, h_b, sizeof(float) * VN, cudaMemcpyHostToDevice);
+ vadd<<<(VN + 255) / 256, 256>>>(d_a, d_b, d_c, VN);
+ cudaGetLastError();
+ cudaDeviceSynchronize();
+ cudaMemcpy(h_c, d_c, sizeof(float) * VN, cudaMemcpyDeviceToHost);
+ for (int i = 0; i < VN; i++)
+ if (h_c[i] != h_a[i] + h_b[i])
+ bad++;
+ cudaFree(d_a);
+ cudaFree(d_b);
+ cudaFree(d_c);
+ free(h_a);
+ free(h_b);
+ free(h_c);
+ printf("RESULT mixed vadd n=%d bad=%d\n", VN, bad);
+ return bad;
+}
+
+static int phase_reduce(void)
+{
+ int *h_in = (int *)malloc(sizeof(int) * RD_N);
+ int *d_in = NULL, *d_out = NULL;
+ int got = 0, exp = 0, bad = 0;
+
+ if (!h_in)
+ return 1;
+ for (int i = 0; i < RD_N; i++) {
+ h_in[i] = i;
+ exp += i;
+ }
+ if (cudaMalloc(&d_in, sizeof(int) * RD_N) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&d_out, sizeof(int)) != cudaSuccess)
+ return 1;
+ cudaMemcpy(d_in, h_in, sizeof(int) * RD_N, cudaMemcpyHostToDevice);
+ cudaMemset(d_out, 0, sizeof(int));
+ reduce_sum<<<(RD_N + 255) / 256, 256>>>(d_in, d_out, RD_N);
+ cudaGetLastError();
+ cudaDeviceSynchronize();
+ cudaMemcpy(&got, d_out, sizeof(int), cudaMemcpyDeviceToHost);
+ bad = (got != exp) ? 1 : 0;
+ cudaFree(d_in);
+ cudaFree(d_out);
+ free(h_in);
+ printf("RESULT mixed red n=%d sum=%d bad=%d\n", RD_N, got, bad);
+ return bad;
+}
+
+static int phase_grid2d(void)
+{
+ int n = G2_NX * G2_NY;
+ int *d_out = NULL, *got = (int *)malloc(sizeof(int) * n);
+ int bad = 0;
+
+ if (!got)
+ return 1;
+ if (cudaMalloc(&d_out, sizeof(int) * n) != cudaSuccess) {
+ free(got);
+ return 1;
+ }
+ grid2d<<<dim3(5, 2), dim3(16, 16)>>>(d_out, G2_NX, G2_NY);
+ cudaGetLastError();
+ cudaDeviceSynchronize();
+ cudaMemcpy(got, d_out, sizeof(int) * n, cudaMemcpyDeviceToHost);
+ for (int i = 0; i < n; i++)
+ if (got[i] != 1000000 + i)
+ bad++;
+ cudaFree(d_out);
+ free(got);
+ printf("RESULT mixed grid2d nx=%d ny=%d bad=%d\n", G2_NX, G2_NY,
+ bad);
+ return bad;
+}
+
+static int phase_streams(void)
+{
+ float *h = (float *)malloc(sizeof(float) * ST_N);
+ float *got = (float *)malloc(sizeof(float) * ST_N);
+ cudaStream_t st[ST_NS];
+ float *d_x[ST_NS];
+ int bad = 0;
+
+ if (!h || !got)
+ return 1;
+ for (int i = 0; i < ST_N; i++)
+ h[i] = (float)(i % 100);
+ for (int k = 0; k < ST_NS; k++) {
+ if (cudaStreamCreate(&st[k]) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&d_x[k], sizeof(float) * ST_N) != cudaSuccess)
+ return 1;
+ cudaMemcpyAsync(d_x[k], h, sizeof(float) * ST_N,
+ cudaMemcpyHostToDevice, st[k]);
+ addv<<<(ST_N + 255) / 256, 256, 0, st[k]>>>(d_x[k], 7.0f, ST_N);
+ scale<<<(ST_N + 255) / 256, 256, 0, st[k]>>>(d_x[k], 3.0f, ST_N);
+ cudaGetLastError();
+ }
+ for (int k = 0; k < ST_NS; k++) {
+ cudaStreamSynchronize(st[k]);
+ cudaMemcpy(got, d_x[k], sizeof(float) * ST_N,
+ cudaMemcpyDeviceToHost);
+ for (int i = 0; i < ST_N; i++)
+ if (got[i] != ((float)(i % 100) + 7.0f) * 3.0f)
+ bad++;
+ cudaStreamDestroy(st[k]);
+ cudaFree(d_x[k]);
+ }
+ free(h);
+ free(got);
+ printf("RESULT mixed stream nstreams=%d n=%d bad=%d\n", ST_NS, ST_N,
+ bad);
+ return bad;
+}
+
+int main(int argc, char **argv)
+{
+ if (p2_emit_mode(argc, argv)) {
+ printf("MAIL %s\n", MIX_MAIL);
+ printf("RESULT mixed mail bad=0\n");
+ printf("RESULT mixed vadd n=%d bad=0\n", VN);
+ printf("RESULT mixed red n=%d sum=%d bad=0\n", RD_N,
+ RD_N * (RD_N - 1) / 2);
+ printf("RESULT mixed grid2d nx=%d ny=%d bad=0\n", G2_NX, G2_NY);
+ printf("RESULT mixed stream nstreams=%d n=%d bad=0\n", ST_NS,
+ ST_N);
+ printf("RESULT mixed total bad=0\n");
+ return p2_status(0);
+ }
+
+ p2_device_info();
+
+ int bad = 0;
+
+ bad += phase_mail();
+ bad += phase_vadd();
+ bad += phase_reduce();
+ bad += phase_grid2d();
+ bad += phase_streams();
+
+ printf("RESULT mixed total bad=%d\n", bad);
+ return p2_status(bad);
+}