Graph Framework
Loading...
Searching...
No Matches
jit.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
6//------------------------------------------------------------------------------
7
8#ifndef jit_h
9#define jit_h
10
11#include <algorithm>
12#include <iterator>
13#include <thread>
14
15#ifdef USE_METAL
16#include "metal_context.hpp"
17#elif defined(USE_CUDA)
18#include "cuda_context.hpp"
19#endif
20#include "cpu_context.hpp"
21
22//------------------------------------------------------------------------------
26//------------------------------------------------------------------------------
27//------------------------------------------------------------------------------
31//------------------------------------------------------------------------------
32#ifdef USE_METAL
33#define START_GPU @autoreleasepool {
34#define END_GPU }
35#else
36#define START_GPU
37#define END_GPU
38#endif
39
41namespace jit {
42//------------------------------------------------------------------------------
47//------------------------------------------------------------------------------
48 template<float_scalar T, bool SAFE_MATH=false>
49 class context {
50 private:
52 std::ostringstream source_buffer;
54 register_map registers;
56 std::vector<std::string> kernel_names;
58 std::map<std::string, texture1d_list> kernel_1dtextures;
60 std::map<std::string, texture2d_list> kernel_2dtextures;
61
63 using gpu_context_type = typename std::conditional<use_gpu<T> (),
64#ifdef USE_CUDA
66#elif defined(USE_METAL)
68#else
70#endif
72
74 gpu_context_type gpu_context;
76 bool used_random;
77
78 public:
80 constexpr static size_t random_state_size = gpu_context_type::random_state_size;
81
82//------------------------------------------------------------------------------
86//------------------------------------------------------------------------------
87 static size_t max_concurrency() {
88 const size_t num = gpu_context_type::max_concurrency();
89 std::cout << "Located " << num << " "
90 << gpu_context_type::device_type() << " device"
91 << (num == 1 ? "." : "s.")
92 << std::endl;
93 return num;
94 }
95
96//------------------------------------------------------------------------------
100//------------------------------------------------------------------------------
101 context(const size_t index) : gpu_context(index), used_random(false) {
102 source_buffer << std::setprecision(max_digits10<T> ());
103 gpu_context.create_header(source_buffer);
104 }
105
106//------------------------------------------------------------------------------
117//------------------------------------------------------------------------------
118 void add_kernel(const std::string name,
123 const size_t size) {
124 kernel_names.push_back(name);
125
126 if (state.get() && !used_random) {
127 used_random = true;
130 }
131
132 std::vector<bool> is_constant(inputs.size(), true);
133 visiter_map visited;
134 register_usage usage;
135 kernel_1dtextures[name] = texture1d_list();
136 kernel_2dtextures[name] = texture2d_list();
137 for (auto &[out, in] : setters) {
138 auto found = std::distance(inputs.begin(),
139 std::find(inputs.begin(),
140 inputs.end(), in));
141 if (found < is_constant.size()) {
142 is_constant[found] = false;
143 }
144 out->compile_preamble(source_buffer, registers,
145 visited, usage,
146 kernel_1dtextures[name],
147 kernel_2dtextures[name],
148 gpu_context.remaining_const_memory);
149 }
150 for (auto &out : outputs) {
151 out->compile_preamble(source_buffer, registers,
152 visited, usage,
153 kernel_1dtextures[name],
154 kernel_2dtextures[name],
155 gpu_context.remaining_const_memory);
156 }
157
158 for (auto &in : inputs) {
159 if (usage.find(in.get()) == usage.end()) {
160 usage[in.get()] = 0;
161 }
162 }
163
164 gpu_context.create_kernel_prefix(source_buffer,
165 name, inputs, outputs, state,
166 size, is_constant,
167 registers, usage,
168 kernel_1dtextures[name],
169 kernel_2dtextures[name]);
170
171 register_map indices;
172 for (auto &[out, in] : setters) {
173 out->compile(source_buffer, registers, indices, usage);
174 }
175 for (auto &out : outputs) {
176 out->compile(source_buffer, registers, indices, usage);
177 }
178
179 gpu_context.create_kernel_postfix(source_buffer, outputs,
180 setters, state,
181 registers, indices, usage);
182
183// Delete the registers so that they can be used again in other kernels.
184 std::vector<void *> removed_elements;
185 for (auto &[key, value] : registers) {
186 if (value[0] == 'r') {
187 removed_elements.push_back(key);
188 }
189 }
190
191 for (auto &key : removed_elements) {
192 registers.erase(key);
193 }
194 }
195
196//------------------------------------------------------------------------------
200//------------------------------------------------------------------------------
201 void add_max_reduction(const size_t size) {
202 gpu_context.create_reduction(source_buffer, size);
203 }
204
205//------------------------------------------------------------------------------
207//------------------------------------------------------------------------------
209 std::cout << std::endl << source_buffer.str() << std::endl;
210 }
211
212//------------------------------------------------------------------------------
214//------------------------------------------------------------------------------
215 void save_source() {
216 std::string source = source_buffer.str();
217 std::ostringstream filename;
218 filename << std::hash<std::string> {} (source)
219 << std::hash<std::thread::id>{}(std::this_thread::get_id());
220 if constexpr (use_cuda()) {
221 filename << ".cu";
222 } else if constexpr (use_metal<T> ()) {
223 filename << ".metal";
224 } else {
225 filename << ".cpp";
226 }
227
228 std::ofstream outFile(filename.str());
229 outFile << source;
230 }
231
232//------------------------------------------------------------------------------
237//------------------------------------------------------------------------------
238 void compile(const bool add_reduction=false) {
239#ifdef SAVE_KERNEL_SOURCE
240 save_source();
241#endif
242 gpu_context.compile(source_buffer.str(),
243 kernel_names,
244 add_reduction);
245 }
246
247//------------------------------------------------------------------------------
256//------------------------------------------------------------------------------
257 std::function<void(void)> create_kernel_call(const std::string kernel_name,
261 const size_t num_rays) {
262 return gpu_context.create_kernel_call(kernel_name, inputs, outputs, state, num_rays,
263 kernel_1dtextures[kernel_name],
264 kernel_2dtextures[kernel_name]);
265 }
266
267//------------------------------------------------------------------------------
273//------------------------------------------------------------------------------
274 std::function<T(void)> create_max_call(graph::shared_leaf<T, SAFE_MATH> &argument,
275 std::function<void(void)> run) {
276 return gpu_context.create_max_call(argument, run);
277 }
278
279//------------------------------------------------------------------------------
284//------------------------------------------------------------------------------
285 void print(const size_t index,
287 gpu_context.print_results(index, nodes);
288 }
289
290//------------------------------------------------------------------------------
296//------------------------------------------------------------------------------
297 T check_value(const size_t index,
299 return gpu_context.check_value(index, node);
300 }
301
302//------------------------------------------------------------------------------
304//------------------------------------------------------------------------------
305 void wait() {
306 gpu_context.wait();
307 }
308
309//------------------------------------------------------------------------------
314//------------------------------------------------------------------------------
316 T *source) {
317 gpu_context.copy_to_device(node, source);
318 }
319
320//------------------------------------------------------------------------------
325//------------------------------------------------------------------------------
327 T *destination) {
328 gpu_context.copy_to_host(node, destination);
329 }
330
331//------------------------------------------------------------------------------
335//------------------------------------------------------------------------------
337 return gpu_context.get_buffer(node);
338 }
339 };
340}
341
342#endif /* jit_h */
Class representing a cpu context.
Definition cpu_context.hpp:82
Class representing a cuda gpu context.
Definition cuda_context.hpp:73
Class representing a metal gpu context.
Definition metal_context.hpp:25
static void compile_random(std::ostringstream &stream)
Write the preamble for the random function.
Definition random.hpp:314
static void compile_random_state(std::ostringstream &stream)
Write the preamble for the random state struct.
Definition random.hpp:31
Class for JIT compile of the GPU kernels.
Definition jit.hpp:49
void compile(const bool add_reduction=false)
Compile the kernel.
Definition jit.hpp:238
static constexpr size_t random_state_size
Size of random state needed.
Definition jit.hpp:80
static size_t max_concurrency()
Get the maximum number of concurrent instances.
Definition jit.hpp:87
void wait()
Wait for kernel to finish.
Definition jit.hpp:305
context(const size_t index)
Construct a jit context object.
Definition jit.hpp:101
std::function< T(void)> create_max_call(graph::shared_leaf< T, SAFE_MATH > &argument, std::function< void(void)> run)
Create a max compute kernel calling function.
Definition jit.hpp:274
void add_max_reduction(const size_t size)
Add max reduction kernel.
Definition jit.hpp:201
void save_source()
Save the kernel source code.
Definition jit.hpp:215
std::function< void(void)> create_kernel_call(const std::string kernel_name, graph::input_nodes< T, SAFE_MATH > inputs, graph::output_nodes< T, SAFE_MATH > outputs, graph::shared_random_state< T, SAFE_MATH > state, const size_t num_rays)
Create a kernel calling function.
Definition jit.hpp:257
void print(const size_t index, const graph::output_nodes< T, SAFE_MATH > &nodes)
Print output.
Definition jit.hpp:285
void copy_to_device(graph::shared_leaf< T, SAFE_MATH > &node, T *source)
Copy contexts of buffer to device.
Definition jit.hpp:315
T * get_buffer(graph::shared_leaf< T, SAFE_MATH > &node)
Get buffer from the gpu_context.
Definition jit.hpp:336
T check_value(const size_t index, const graph::shared_leaf< T, SAFE_MATH > &node)
Check the value.
Definition jit.hpp:297
void add_kernel(const std::string name, graph::input_nodes< T, SAFE_MATH > inputs, graph::output_nodes< T, SAFE_MATH > outputs, graph::map_nodes< T, SAFE_MATH > setters, graph::shared_random_state< T, SAFE_MATH > state, const size_t size)
Add a kernel.
Definition jit.hpp:118
void print_source()
Print the kernel source.
Definition jit.hpp:208
void copy_to_host(graph::shared_leaf< T, SAFE_MATH > &node, T *destination)
Copy contexts of buffer to host.
Definition jit.hpp:326
Cpu context for cpus.
Cuda context for metal based gpus.
Metal context for metal based gpus.
std::shared_ptr< random_state_node< T, SAFE_MATH > > shared_random_state
Convenience type alias for shared sqrt nodes.
Definition random.hpp:270
std::vector< shared_variable< T, SAFE_MATH > > input_nodes
Convenience type alias for a vector of inputs.
Definition node.hpp:1711
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:676
std::vector< std::pair< shared_leaf< T, SAFE_MATH >, shared_variable< T, SAFE_MATH > > > map_nodes
Convenience type alias for mapping end codes back to inputs.
Definition node.hpp:1715
std::vector< shared_leaf< T, SAFE_MATH > > output_nodes
Convenience type alias for a vector of output nodes.
Definition node.hpp:691
Name space for JIT functions.
Definition jit.hpp:41
std::map< void *, size_t > texture1d_list
Type alias for indexing 1D textures.
Definition register.hpp:263
std::map< void *, std::array< size_t, 2 > > texture2d_list
Type alias for indexing 2D textures.
Definition register.hpp:265
std::map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:259
std::map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:257
constexpr bool use_cuda()
Test to use Cuda.
Definition register.hpp:67
std::set< void * > visiter_map
Type alias for listing visited nodes.
Definition register.hpp:261