forked from bhamon/gpuPlotGenerator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGenerationDevice.cpp
199 lines (160 loc) · 7.32 KB
/
GenerationDevice.cpp
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
GPU plot generator for Burst coin.
Author: Cryo
Bitcoin: 138gMBhCrNkbaiTCmUhP9HLU9xwn5QKZgD
Burst: BURST-YA29-QCEW-QXC3-BKXDL
Based on the code of the official miner and dcct's plotgen.
*/
#include <stdexcept>
#include <sstream>
#include <fstream>
#include <streambuf>
#include "OpenclError.h"
#include "GenerationDevice.h"
namespace cryo {
namespace gpuPlotGenerator {
GenerationDevice::GenerationDevice(const std::shared_ptr<DeviceConfig>& p_config, const std::shared_ptr<OpenclDevice>& p_device) throw (std::exception)
: m_config(p_config), m_device(p_device), m_context(0), m_commandQueue(0), m_bufferDevice(0), m_program(0), m_kernels{0, 0, 0}, m_available(true) {
m_bufferCpu = new unsigned char[getMemorySize()];
cl_int error;
m_context = clCreateContext(0, 1, &m_device->getHandle(), NULL, NULL, &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL context");
}
m_commandQueue = clCreateCommandQueue(m_context, m_device->getHandle(), 0, &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL command queue");
}
m_bufferDevice = clCreateBuffer(m_context, CL_MEM_READ_WRITE, sizeof(unsigned char) * m_config->getGlobalWorkSize() * GEN_SIZE, 0, &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL GPU buffer");
}
std::string source(loadSource(KERNEL_PATH + "/nonce.cl"));
const char* sources[] = {source.c_str()};
std::size_t sourcesLength[] = {source.length()};
m_program = clCreateProgramWithSource(m_context, 1, sources, sourcesLength, &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL program");
}
std::string includePath("-I " + KERNEL_PATH);
error = clBuildProgram(m_program, 1, &m_device->getHandle(), includePath.c_str(), 0, 0);
if(error != CL_SUCCESS) {
std::size_t logSize;
cl_int subError = clGetProgramBuildInfo(m_program, m_device->getHandle(), CL_PROGRAM_BUILD_LOG, 0, 0, &logSize);
if(subError != CL_SUCCESS) {
throw OpenclError(subError, "Unable to retrieve the OpenCL build info size");
}
std::unique_ptr<char[]> log(new char[logSize]);
subError = clGetProgramBuildInfo(m_program, m_device->getHandle(), CL_PROGRAM_BUILD_LOG, logSize, (void*)log.get(), 0);
if(subError != CL_SUCCESS) {
throw OpenclError(subError, "Unable to retrieve the OpenCL build info");
}
std::ostringstream message;
message << "Unable to build the OpenCL program" << std::endl;
message << log.get();
throw OpenclError(error, message.str());
}
m_kernels[0] = clCreateKernel(m_program, "nonce_step1", &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL step1 kernel");
}
error = clSetKernelArg(m_kernels[0], 0, sizeof(cl_mem), (void*)&m_bufferDevice);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step1 kernel arguments");
}
m_kernels[1] = clCreateKernel(m_program, "nonce_step2", &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL step2 kernel");
}
error = clSetKernelArg(m_kernels[1], 0, sizeof(cl_mem), (void*)&m_bufferDevice);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step2 kernel arguments");
}
m_kernels[2] = clCreateKernel(m_program, "nonce_step3", &error);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to create the OpenCL step3 kernel");
}
error = clSetKernelArg(m_kernels[2], 0, sizeof(cl_mem), (void*)&m_bufferDevice);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step3 kernel arguments");
}
}
GenerationDevice::~GenerationDevice() throw () {
if(m_kernels[2]) { clReleaseKernel(m_kernels[2]); }
if(m_kernels[1]) { clReleaseKernel(m_kernels[1]); }
if(m_kernels[0]) { clReleaseKernel(m_kernels[0]); }
if(m_program) { clReleaseProgram(m_program); }
if(m_bufferDevice) { clReleaseMemObject(m_bufferDevice); }
if(m_commandQueue) { clReleaseCommandQueue(m_commandQueue); }
if(m_context) { clReleaseContext(m_context); }
delete[] m_bufferCpu;
}
void GenerationDevice::computePlots(unsigned long long p_address, unsigned long long p_startNonce, unsigned int p_workSize) throw (std::exception) {
if(p_workSize > m_config->getGlobalWorkSize()) {
throw std::runtime_error("Global work size too low for the requested work size");
}
cl_int error;
std::size_t globalWorkSize = m_config->getGlobalWorkSize();
std::size_t localWorkSize = m_config->getLocalWorkSize();
error = clSetKernelArg(m_kernels[0], 1, sizeof(unsigned int), (void*)&p_workSize);
error |= clSetKernelArg(m_kernels[0], 2, sizeof(unsigned long long), (void*)&p_address);
error |= clSetKernelArg(m_kernels[0], 3, sizeof(unsigned long long), (void*)&p_startNonce);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step1 kernel arguments");
}
error = clEnqueueNDRangeKernel(m_commandQueue, m_kernels[0], 1, 0, &globalWorkSize, &localWorkSize, 0, 0, 0);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Error in step1 kernel launch");
}
unsigned int hashesNumber = m_config->getHashesNumber();
unsigned int hashesSize = hashesNumber * HASH_SIZE;
for(unsigned int i = 0 ; i < PLOT_SIZE ; i += hashesSize) {
unsigned int hashesOffset = PLOT_SIZE - i;
error = clSetKernelArg(m_kernels[1], 1, sizeof(unsigned int), (void*)&p_workSize);
error |= clSetKernelArg(m_kernels[1], 2, sizeof(unsigned long long), (void*)&p_startNonce);
error |= clSetKernelArg(m_kernels[1], 3, sizeof(unsigned int), (void*)&hashesOffset);
error |= clSetKernelArg(m_kernels[1], 4, sizeof(unsigned int), (void*)&hashesNumber);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step2 kernel arguments");
}
error = clEnqueueNDRangeKernel(m_commandQueue, m_kernels[1], 1, 0, &globalWorkSize, &localWorkSize, 0, 0, 0);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Error in step2 kernel launch");
}
error = clFinish(m_commandQueue);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Error in step2 kernel finish");
}
}
error = clSetKernelArg(m_kernels[2], 1, sizeof(unsigned int), (void*)&p_workSize);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Unable to set the OpenCL step3 kernel arguments");
}
error = clEnqueueNDRangeKernel(m_commandQueue, m_kernels[2], 1, 0, &globalWorkSize, &localWorkSize, 0, 0, 0);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Error in step3 kernel launch");
}
}
void GenerationDevice::bufferPlots() throw (std::exception) {
std::size_t offsetGpu = 0;
std::size_t offsetCpu = 0;
for(unsigned int i = 0, end = m_config->getGlobalWorkSize() ; i < end ; ++i, offsetGpu += GEN_SIZE, offsetCpu += PLOT_SIZE) {
int error = clEnqueueReadBuffer(m_commandQueue, m_bufferDevice, CL_TRUE, sizeof(unsigned char) * offsetGpu, sizeof(unsigned char) * PLOT_SIZE, m_bufferCpu + offsetCpu, 0, 0, 0);
if(error != CL_SUCCESS) {
throw OpenclError(error, "Error in synchronous read");
}
}
}
std::string GenerationDevice::loadSource(const std::string& p_file) const throw (std::exception) {
std::ifstream stream(p_file, std::ios::in);
if(!stream) {
throw std::runtime_error("Unable to open the source file");
}
std::string str;
stream.seekg(0, std::ios::end);
str.reserve(stream.tellg());
stream.seekg(0, std::ios::beg);
str.assign(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
return str;
}
}}