forked from plaidml/plaidml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ocl.h
217 lines (174 loc) · 5.42 KB
/
ocl.h
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright 2017-2018 Intel Corporation.
#pragma once
#include <string>
#include "base/shim/opencl/opencl.h"
#include "base/util/logging.h"
namespace vertexai {
namespace tile {
namespace hal {
namespace opencl {
namespace ocl = vertexai::shim::opencl;
// A little wrapper class to simplify handling OpenCL errors.
class Err final {
public:
// A simple Check wrapper, for common error handling situations (i.e. fixed
// string description). This will throw an exception with a useful message
// iff the supplied Err value wraps something other than CL_SUCCESS.
static void Check(Err err, const std::string& msg) {
if (err) {
std::rethrow_exception(err.ToException(msg));
}
}
Err() : code_(CL_SUCCESS) {}
// clang-format off
//cppcheck-suppress noExplicitConstructor // NOLINT
Err(cl_int code); // NOLINT
// clang-format on
// Errors are "true" if there is an error. So the idiom is:
// Err err = /* something */
// if (err) {
// /* throw something */
// }
operator bool() const { return code_ != CL_SUCCESS; }
cl_int* ptr() { return &code_; }
const char* str() const;
cl_int code() const { return code_; }
std::exception_ptr ToException(const std::string& msg) const {
if (code_ == CL_SUCCESS) {
return std::exception_ptr();
}
std::string err_msg = msg + ": " + str();
LOG(ERROR) << err_msg;
return std::make_exception_ptr(std::runtime_error(err_msg));
}
private:
cl_int code_;
};
inline std::ostream& operator<<(std::ostream& o, const Err& err) { return o << err.str(); }
// Retain/Release overloads for OpenCL objects.
inline void Retain(cl_event e) {
Err err = ocl::RetainEvent(e);
LOG_IF(err, ERROR) << "clRetainEvent: " << err.str();
}
inline void Release(cl_event e) {
Err err = ocl::ReleaseEvent(e);
LOG_IF(err, ERROR) << "clReleaseEvent: " << err.str();
}
inline void Retain(cl_mem m) {
Err err = ocl::RetainMemObject(m);
LOG_IF(err, ERROR) << "clRetainMemObject: " << err.str();
}
inline void Release(cl_mem m) {
Err err = ocl::ReleaseMemObject(m);
LOG_IF(err, ERROR) << "clReleaseMemObject: " << err.str();
}
inline void Retain(cl_kernel k) {
Err err = ocl::RetainKernel(k);
LOG_IF(err, ERROR) << "clRetainKernel: " << err.str();
}
inline void Release(cl_kernel k) {
Err err = ocl::ReleaseKernel(k);
LOG_IF(err, ERROR) << "clReleaseKernel: " << err.str();
}
inline void Retain(cl_context c) {
Err err = ocl::RetainContext(c);
LOG_IF(err, ERROR) << "clRetainContext: " << err.str();
}
inline void Release(cl_context c) {
Err err = ocl::ReleaseContext(c);
LOG_IF(err, ERROR) << "clReleaseContext: " << err.str();
}
inline void Retain(cl_program p) {
Err err = ocl::RetainProgram(p);
LOG_IF(err, ERROR) << "clRetainProgram: " << err.str();
}
inline void Release(cl_program p) {
Err err = ocl::ReleaseProgram(p);
LOG_IF(err, ERROR) << "clReleaseProgram: " << err.str();
}
inline void Retain(cl_command_queue c) {
Err err = ocl::RetainCommandQueue(c);
LOG_IF(err, ERROR) << "clRetainCommandQueue: " << err.str();
}
inline void Release(cl_command_queue c) {
Err err = ocl::ReleaseCommandQueue(c);
LOG_IF(err, ERROR) << "clReleaseCommandQueue: " << err.str();
}
// A simple wrapper for OpenCL objects, providing RAII support. If a wrapper
// holds an object, the wrapper retains a refcount on that object. If the
// wrapper is assigned a bare OpenCL object, the wrapper assumes the object's
// refcount; this allows the wrapper to be used as an lvalue accepting objects
// returned by OpenCL library calls.
template <typename O>
class CLObj final {
public:
CLObj() {}
// clang-format off
//cppcheck-suppress noExplicitConstructor // NOLINT
CLObj(O obj) : obj_{obj} {} // NOLINT
// clang-format on
CLObj(const CLObj<O>& other) : obj_{other.obj_} {
if (obj_) {
Retain(obj_);
}
}
CLObj(CLObj<O>&& other) : obj_{other.obj_} { other.obj_ = nullptr; }
CLObj& operator=(const CLObj<O>& other) {
if (other.obj_) {
Retain(other.obj_);
}
if (obj_) {
Release(obj_);
}
obj_ = other.obj_;
return *this;
}
CLObj& operator=(CLObj<O>&& other) {
if (obj_) {
Release(obj_);
}
obj_ = other.obj_;
other.obj_ = nullptr;
return *this;
}
~CLObj() {
if (obj_) {
Release(obj_);
}
}
void reset() {
if (obj_) {
Release(obj_);
obj_ = nullptr;
}
}
// Returns the object held by this wrapper, without retaining it or releasing
// it. Do not create a new wrapper from the result without explicitly
// retaining it.
O get() const { return obj_; }
operator bool() const { return obj_ != nullptr; }
bool operator==(const CLObj<O>& other) const { return obj_ == other.obj_; }
bool operator==(O other) const { return obj_ == other; }
bool operator!=(const CLObj<O>& other) const { return obj_ != other.obj_; }
bool operator!=(O other) const { return obj_ != other; }
// Releases the object held by the wrapper (if any), and returns a pointer
// to the newly zero object within the wrapper. This is intended for use
// with OpenCL calls that use output parameters to return objects.
O* LvaluePtr() {
if (obj_) {
Release(obj_);
}
obj_ = nullptr;
return &obj_;
}
private:
O obj_ = nullptr;
};
template <typename O>
inline bool operator<(const CLObj<O>& lhs, const CLObj<O>& rhs) {
return lhs.get() < rhs.get();
}
} // namespace opencl
} // namespace hal
} // namespace tile
} // namespace vertexai