summaryrefslogtreecommitdiffstats
path: root/tools/cuda-ab/memset_probe.cu
blob: a6a12e0a4144359644ae43b5d6ab5ed3cb689c65 (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
// SPDX-License-Identifier: BSD-3-Clause
/*
 * memset_probe.cu - isolate the memcpy_roundtrip memset-phase failure.
 *
 * cudaMemset(8 MB, 0x5A) -> D2H -> byte verify, with a run-length report:
 * the first bad offset, and a coverage map at 4 KB granularity (correct /
 * wrong / untouched-malloc-prefill) so "fill under-delivered" is
 * distinguishable from "readback delivered wrong pages".
 *
 * Build: nvcc -O2 --cudart=static -o memset_probe memset_probe.cu
 */

#include <cstdio>
#include <cstdlib>
#include <cuda_runtime.h>

#define CHECK(x)                                                         \
	do {                                                             \
		cudaError_t e_ = (x);                                    \
		if (e_ != cudaSuccess) {                                 \
			printf("CUDA_ERROR %s at line %d\n",             \
			       cudaGetErrorString(e_), __LINE__);        \
			printf("STATUS FAIL\n");                         \
			return 1;                                        \
		}                                                        \
	} while (0)

#define PAGE 4096
#define MemsetByte 0x5A

int main(void)
{
	const size_t bytes = 8u << 20;
	unsigned char *h;
	unsigned char *d;
	size_t i;
	int bad = 0;
	size_t first_bad = (size_t)-1;
	size_t n_pages, p;

	setvbuf(stdout, NULL, _IONBF, 0);
	h = (unsigned char *)malloc(bytes);
	if (!h)
		return 1;
	memset(h, 0xEE, bytes);

	CHECK(cudaMalloc(&d, bytes));
	printf("DPTR d=%p bytes=%zu\n", (void *)d, bytes);

	CHECK(cudaMemset(d, MemsetByte, bytes));
	CHECK(cudaDeviceSynchronize());
	CHECK(cudaMemcpy(h, d, bytes, cudaMemcpyDeviceToHost));

	for (i = 0; i < bytes; i++) {
		if (h[i] != (unsigned char)MemsetByte) {
			if (first_bad == (size_t)-1)
				first_bad = i;
			bad++;
		}
	}
	printf("FIRST_BAD off=%zu (0x%zx) bad=%d total=%zu\n",
	       first_bad, first_bad, bad, bytes);
	n_pages = bytes / PAGE;
	for (p = 0; p < n_pages; p++) {
		int good = 1, prefill = 1;

		for (i = 0; i < PAGE; i++) {
			if (h[p * PAGE + i] != (unsigned char)MemsetByte)
				good = 0;
			if (h[p * PAGE + i] != 0xEE)
				prefill = 0;
			if (!good && !prefill)
				break;
		}
		if (!good) {
			printf("PAGE %zu %s b0=%02x b1=%02x b2=%02x b3=%02x b4095=%02x\n",
			       p, prefill ? "PREFILL" : "OTHER",
			       h[p * PAGE], h[p * PAGE + 1],
			       h[p * PAGE + 2], h[p * PAGE + 3],
			       h[p * PAGE + 4095]);
			if (p > 24)
				break;
		}
	}
	printf("STATUS %s\n", bad == 0 ? "OK" : "FAIL");
	return 0;
}