47 #define __CL_ENABLE_EXCEPTIONS
49 #undef __CL_ENABLE_EXCEPTIONS
51 #include <stooling/SourceCode.h>
53 #include <pvsutil/Assert.h>
54 #include <pvsutil/Logger.h>
56 #include "SkelCL/detail/Program.h"
58 #include "SkelCL/detail/Device.h"
59 #include "SkelCL/detail/DeviceList.h"
60 #include "SkelCL/detail/Util.h"
64 std::string binaryFilename(
const std::string& hash,
65 const std::shared_ptr<skelcl::detail::Device>&
68 std::stringstream filename;
70 std::string devName = devicePtr->name();
71 std::replace( devName.begin(), devName.end(),
' ',
'_');
72 filename <<
"." << hash
74 <<
"-" << devicePtr->id()
76 return filename.str();
85 Program::Program(
const std::string& source,
const std::string& hash)
90 LOG_DEBUG_INFO(
"Program instance created with source:\n", source,
94 Program::Program(Program&& rhs)
95 : _source(std::move(rhs._source)),
96 _hash(std::move(rhs._hash)),
97 _clPrograms(std::move(rhs._clPrograms))
101 Program& Program::operator=(Program&& rhs)
103 _source = std::move(rhs._source);
104 _hash = std::move(rhs._hash);
105 _clPrograms = std::move(rhs._clPrograms);
109 void Program::transferParameters(
const std::string& from,
111 const std::string& to)
113 _source.transferParameters(from, indexFrom, to);
114 _source.fixKernelParameter(to);
117 void Program::transferArguments(
const std::string& from,
119 const std::string& to)
121 _source.transferArguments(from, indexFrom, to);
124 void Program::renameFunction(
const std::string& from,
125 const std::string& to)
127 _source.renameFunction(from, to);
130 void Program::renameType(
const int i,
const std::string& typeName)
132 std::stringstream identifier;
133 identifier <<
"SCL_TYPE_" << i;
135 _source.redefineTypedef(identifier.str(), typeName);
138 bool Program::loadBinary()
141 ASSERT(!_hash.empty());
143 for (
auto& devicePtr : globalDeviceList) {
144 std::ifstream binaryFile(binaryFilename(_hash, devicePtr),
146 | std::ios_base::binary
147 | std::ios_base::ate);
148 if (binaryFile.fail()) {
154 std::ifstream::pos_type size = binaryFile.tellg();
156 std::unique_ptr<char[]> binary(
new char[size]);
158 binaryFile.seekg(0, std::ios::beg);
160 binaryFile.read(binary.get(), size);
164 cl::Program::Binaries binaries(1, std::make_pair(binary.get(), size));
165 std::vector<cl::Device> devices{ devicePtr->clDevice() };
166 _clPrograms.push_back( cl::Program( devicePtr->clContext(),
167 devices, binaries ) );
169 LOG_DEBUG_INFO(
"Load binary for device ", devicePtr->id(),
170 " from file ", binaryFilename(_hash, devicePtr));
172 ASSERT(_clPrograms.size() == globalDeviceList.size());
176 void Program::build()
178 bool createdProgramsFromSource =
false;
179 if (_clPrograms.empty()) {
180 createProgramsFromSource();
181 createdProgramsFromSource =
true;
187 for (
auto& devicePtr : globalDeviceList) {
188 _clPrograms[devicePtr->id()].build(
189 std::vector<cl::Device>(1, devicePtr->clDevice()) );
192 if (createdProgramsFromSource) {
196 }
catch (cl::Error& err) {
197 if (err.err() == CL_BUILD_PROGRAM_FAILURE) {
198 auto& devicePtr = globalDeviceList.front();
201 devicePtr->id()].getBuildInfo<CL_PROGRAM_BUILD_LOG>(
202 devicePtr->clDevice() );
203 LOG_ERROR(err,
"\nBuild log:\n", buildLog);
206 ABORT_WITH_ERROR(err);
211 cl::Kernel Program::kernel(
const Device&
device,
212 const std::string& name)
const
214 return cl::Kernel(_clPrograms[device.id()], name.c_str());
217 void Program::createProgramsFromSource()
220 std::transform( globalDeviceList.begin(), globalDeviceList.end(),
221 std::back_inserter(_clPrograms),
222 [
this](DeviceList::const_reference devicePtr) -> cl::Program {
223 std::stringstream ss;
224 ss <<
"#define skelcl_get_device_id() " << devicePtr->id() <<
"\n";
226 std::string s(ss.str());
227 s.append(_source.code());
229 LOG_DEBUG_INFO(
"Create cl::Program for device ", devicePtr->id(),
230 " with source:\n", s,
"\n");
232 return cl::Program(devicePtr->clContext(),
233 cl::Program::Sources(1, std::make_pair(s.c_str(),
240 void Program::saveBinary()
242 if (_hash.empty())
return;
244 if (util::envVarValue(
"SKELCL_SAVE_BINARY") !=
"YES")
return;
246 for (
auto& devicePtr : globalDeviceList) {
248 auto size = _clPrograms[
249 devicePtr->id()].getInfo<CL_PROGRAM_BINARY_SIZES>();
250 ASSERT(size.size() == 1);
252 std::unique_ptr<char[]> charPtr(
new char[size.front()]);
254 std::vector<char *> binary{ charPtr.get() };
256 _clPrograms[devicePtr->id()].getInfo(CL_PROGRAM_BINARIES, &binary);
258 std::ofstream outfile(binaryFilename(_hash, devicePtr),
260 | std::ios_base::trunc
261 | std::ios_base::binary);
262 outfile.write(binary.front(),
static_cast<long>(size.front()));
263 LOG_DEBUG_INFO(
"Saved binary for device ", devicePtr->id(),
264 " to file ", binaryFilename(_hash, devicePtr));
265 }
catch (cl::Error err) {
266 ABORT_WITH_ERROR(err);
Out< ContainerType< T > > out(ContainerType< T > &c)
Helper function to create a Out wrapper object.
SKELCL_DLL detail::DeviceID device(size_t dID)
Creates an OpenCL device ID to be used as parameter of the init(detail::PlatformID, detail::DeviceID) function.