-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbitonic_sort.cu
More file actions
88 lines (70 loc) · 2.4 KB
/
Copy pathbitonic_sort.cu
File metadata and controls
88 lines (70 loc) · 2.4 KB
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
#include <cuda_runtime.h>
#include <iostream>
#define BLOCK_SIZE 1024
#define CUDA_CHECK(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
exit(code);
}
}
__global__ void bitonicSortShared(int* arr) {
__shared__ int s_data[BLOCK_SIZE];
int tid = threadIdx.x;
int gid = blockIdx.x * BLOCK_SIZE + tid;
s_data[tid] = arr[gid];
__syncthreads();
for (int k = 2; k <= BLOCK_SIZE; k <<= 1) {
for (int j = k >> 1; j > 0; j >>= 1) {
int ixj = tid ^ j;
if (ixj > tid) {
bool ascending = (tid & k) == 0;
int val_i = s_data[tid];
int val_j = s_data[ixj];
if ((ascending && val_i > val_j) || (!ascending && val_i < val_j)) {
s_data[tid] = val_j;
s_data[ixj] = val_i;
}
}
__syncthreads();
}
}
arr[gid] = s_data[tid];
}
__global__ void bitonicMergeKernel(int* arr, int j, int k, int n) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i >= n) return;
int ixj = i ^ j;
if (ixj > i && ixj < n) {
bool ascending = (i & k) == 0;
int val_i = arr[i];
int val_j = arr[ixj];
if ((ascending && val_i > val_j) || (!ascending && val_i < val_j)) {
arr[i] = val_j;
arr[ixj] = val_i;
}
}
}
// Utility function to run the full sort
void bitonicSort(int* h_arr, int n) {
int* d_arr;
size_t bytes = n * sizeof(int);
CUDA_CHECK(cudaMalloc(&d_arr, bytes));
CUDA_CHECK(cudaMemcpy(d_arr, h_arr, bytes, cudaMemcpyHostToDevice));
// Step 1: Shared memory block-wise sort
int numBlocks = (n + BLOCK_SIZE - 1) / BLOCK_SIZE;
bitonicSortShared<<<numBlocks, BLOCK_SIZE>>>(d_arr);
CUDA_CHECK(cudaGetLastError());
CUDA_CHECK(cudaDeviceSynchronize());
// Step 2: Global merge steps
for (int k = 2; k <= n; k <<= 1) { // k = 2, 4, 8, ...
for (int j = k >> 1; j > 0; j >>= 1) { // j = k/2, k/4, ..., 1
bitonicMergeKernel<<<numBlocks, BLOCK_SIZE>>>(d_arr, j, k, n);
cudaDeviceSynchronize();
}
}
cudaMemcpy(h_arr, d_arr, bytes, cudaMemcpyDeviceToHost);
cudaFree(d_arr);
}