-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCLPathFinder.cpp
More file actions
165 lines (120 loc) · 5.83 KB
/
Copy pathCLPathFinder.cpp
File metadata and controls
165 lines (120 loc) · 5.83 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "CLPathFinder.h"
#define CHECK_OPENCL_STATUS(ret, string) \
do { \
cl_int clRet = ret; \
if (clRet != CL_SUCCESS) { \
std::cerr << string << " with error code" << "(" << ret << ")" << std::endl; \
return 1; \
} \
} while(false)
int CLPathFinder::init(std::string path, cl_device_id device, int kernel_version)
{
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create context");
std::string kernel_source;
if (get_kernel_source(path, kernel_source)) {
return 1;
}
const size_t code_size = kernel_source.size();
const char* code_string = kernel_source.data();
program = clCreateProgramWithSource(context, 1, &code_string, &code_size, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create program with given source");
clStatus = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
CHECK_OPENCL_STATUS(clStatus, "Error during source compiling");
iterKernel = clCreateKernel(program, "bellmanFordIter", &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create bellmanFordIter kernel");
initKernel = clCreateKernel(program, "bellmanFordInit", &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create bellmanFordInit kernel");
queue = clCreateCommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create command queue");
this->kernel_version = kernel_version;
this->device = device;
return 0;
}
int CLPathFinder::set_args(Graph& g, int start)
{
edgesBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY, 2 * sizeof(int) * g.edges.size(), nullptr, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create edges buffer");
clStatus = clEnqueueWriteBuffer(queue, edgesBuffer, CL_FALSE, 0, 2 * sizeof(int) * g.edges.size(), g.edges.data(), 0, nullptr, nullptr);
CHECK_OPENCL_STATUS(clStatus, "Cannot write graph into edges buffer");
weightsBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(double) * g.weight.size(), nullptr, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create buffer for edges weights");
clStatus = clEnqueueWriteBuffer(queue, weightsBuffer, CL_FALSE, 0, sizeof(double) * g.weight.size(), g.weight.data(), 0, nullptr, nullptr);
CHECK_OPENCL_STATUS(clStatus, "Cannot write to weight buffer");
distancesBuffer = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(double) * g.vertices_amount, nullptr, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create distances buffer");
distances.resize(g.vertices_amount);
clStatus = clEnqueueWriteBuffer(queue, distancesBuffer, CL_FALSE, 0, sizeof(double) * distances.size(), distances.data(), 0, nullptr, nullptr);
CHECK_OPENCL_STATUS(clStatus, "Cannot write into distances buffer");
changed = 0;
changedBuffer = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(changed), &changed, &clStatus);
CHECK_OPENCL_STATUS(clStatus, "Cannot create changing check buffer");
int arg = 0;
clSetKernelArg(initKernel, arg++, sizeof(cl_mem), &distancesBuffer);
clSetKernelArg(initKernel, arg++, sizeof(cl_uint), &g.vertices_amount);
clSetKernelArg(initKernel, arg++, sizeof(cl_uint), &start);
arg = 0;
edges_amount = g.edges.size();
clSetKernelArg(iterKernel, arg++, sizeof(cl_uint), &edges_amount);
clSetKernelArg(iterKernel, arg++, sizeof(cl_mem), &edgesBuffer);
clSetKernelArg(iterKernel, arg++, sizeof(cl_mem), &weightsBuffer);
clSetKernelArg(iterKernel, arg++, sizeof(cl_mem), &distancesBuffer);
clSetKernelArg(iterKernel, arg++, sizeof(cl_mem), &changedBuffer);
size_t localSizes[3] = { 0 };
clStatus = clGetKernelWorkGroupInfo(iterKernel, device, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, sizeof(localSizes), localSizes, nullptr);
CHECK_OPENCL_STATUS(clStatus, "Cannot get workgroup information from given kernel");
localSize = localSizes[0];
globalSizeInit = global_align(g.vertices_amount, localSize);
globalSizeIter = global_align(g.edges.size(), localSize);
if (kernel_version == 2) {
globalSizeIter = global_align(globalSizeIter / localSize, localSize);
}
return 0;
}
int CLPathFinder::run()
{
int count_iterations = 0;
clEnqueueNDRangeKernel(queue, initKernel, 1, 0, &globalSizeInit, &localSize, 0, nullptr, nullptr);
do {
changed = 0;
clEnqueueWriteBuffer(queue, changedBuffer, CL_FALSE, 0, sizeof(cl_uint), &changed, 0, nullptr, nullptr);
clEnqueueNDRangeKernel(queue, iterKernel, 1, 0, &globalSizeIter, &localSize, 0, nullptr, nullptr);
clEnqueueReadBuffer(queue, changedBuffer, CL_TRUE, 0, sizeof(cl_uint), &changed, 0, nullptr, nullptr);
count_iterations++;
} while (changed);
clFinish(queue);
clEnqueueReadBuffer(queue, distancesBuffer, CL_TRUE, 0, sizeof(double) * distances.size(), distances.data(), 0, nullptr, nullptr);
std::cout << "OpenCL FordBellman(ver" << kernel_version << ") works with " << count_iterations << " iterations." << std::endl;
return 0;
}
void CLPathFinder::releaseResources()
{
if (edgesBuffer) {
clReleaseMemObject(edgesBuffer);
}
if (weightsBuffer) {
clReleaseMemObject(weightsBuffer);
}
if (distancesBuffer) {
clReleaseMemObject(distancesBuffer);
}
if (program) {
clReleaseProgram(program);
}
if (initKernel) {
clReleaseKernel(initKernel);
}
if (iterKernel) {
clReleaseKernel(iterKernel);
}
if (queue) {
clReleaseCommandQueue(queue);
}
if (context) {
clReleaseContext(context);
}
}
std::vector<double> CLPathFinder::get_distances()
{
return distances;
}