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 preamble_map pre_funcs;
58 std::vector<std::string> kernel_names;
60 std::unordered_map<std::string, texture1d_list> kernel_1dtextures;
62 std::unordered_map<std::string, texture2d_list> kernel_2dtextures;
63
65 using gpu_context_type = typename std::conditional<use_gpu<T> (),
66#ifdef USE_CUDA
68#elif defined(USE_METAL)
70#else
72#endif
74
76 gpu_context_type gpu_context;
77
78 public:
80 constexpr static size_t random_state_size = gpu_context_type::random_state_size;
81
82//------------------------------------------------------------------------------
87//------------------------------------------------------------------------------
88 static size_t max_random_state_size(const size_t size) {
89 return std::min(size, random_state_size);
90 }
91
92//------------------------------------------------------------------------------
96//------------------------------------------------------------------------------
97 static size_t max_concurrency() {
98 const size_t num = gpu_context_type::max_concurrency();
99 std::cout << "Located " << num << " "
100 << gpu_context_type::device_type() << " device"
101 << (num == 1 ? "." : "s.")
102 << std::endl;
103 return num;
104 }
105
106//------------------------------------------------------------------------------
110//------------------------------------------------------------------------------
111 context(const size_t index) : gpu_context(index) {
112 source_buffer << std::setprecision(max_digits10<T> ());
113 gpu_context.create_header(source_buffer);
114 }
115
116//------------------------------------------------------------------------------
129//------------------------------------------------------------------------------
130 void add_kernel(const std::string name,
136 const size_t size,
137 const size_t iterations=1) {
138 kernel_names.push_back(name);
139
140 std::vector<bool> is_constant(inputs.size(), true);
141 visiter_map visited;
142 register_usage usage;
143 kernel_1dtextures[name] = texture1d_list();
144 kernel_2dtextures[name] = texture2d_list();
145 for (auto &[out, in] : setters) {
146 auto found = std::distance(inputs.begin(),
147 std::find(inputs.begin(),
148 inputs.end(), in));
149 if (found < is_constant.size()) {
150 is_constant[found] = false;
151 }
152 out->compile_preamble(source_buffer, registers,
153 visited, usage,
154 kernel_1dtextures[name],
155 kernel_2dtextures[name],
156 pre_funcs,
157 gpu_context.remaining_const_memory);
158 }
159 for (auto &out : outputs) {
160 out->compile_preamble(source_buffer, registers,
161 visited, usage,
162 kernel_1dtextures[name],
163 kernel_2dtextures[name],
164 pre_funcs,
165 gpu_context.remaining_const_memory);
166 }
167
168 for (auto &in : inputs) {
169 if (usage.find(in.get()) == usage.end()) {
170 usage[in.get()] = 0;
171 }
172 }
173
174 argument_set thread_shared;
175 jit::register_map thread_mem;
176
177 gpu_context.create_kernel_prefix(source_buffer,
178 name, inputs, outputs,
179 atomics, state,
180 size, is_constant,
181 registers, usage,
182 kernel_1dtextures[name],
183 kernel_2dtextures[name],
184 thread_shared,
185 thread_mem,
186 iterations);
187
188 for (auto &[out, in] : setters) {
189 out->compile(source_buffer, registers, thread_mem, usage);
190 }
191 for (auto &out : outputs) {
192 out->compile(source_buffer, registers, thread_mem, usage);
193 }
194
195 gpu_context.create_kernel_postfix(source_buffer, outputs,
196 setters, state,
197 registers, usage,
198 thread_shared,
199 thread_mem,
200 iterations);
201
202// Delete the registers so that they can be used again in other kernels.
203 std::vector<void *> removed_elements;
204 for (auto &[key, value] : registers) {
205 if (value[0] == 'r' ||
206 value[0] == 'l' ||
207 value[0] == 'i') {
208 removed_elements.push_back(key);
209 }
210 }
211 for (auto &out : outputs) {
212 if (graph::atomic_accumulate_1D_cast(out).get()) {
213 removed_elements.push_back(out.get());
214 }
215 }
216
217 for (auto &key : removed_elements) {
218 registers.erase(key);
219 }
220 }
221
222//------------------------------------------------------------------------------
226//------------------------------------------------------------------------------
227 void add_max_reduction(const size_t size) {
228 gpu_context.create_reduction(source_buffer, size);
229 }
230
231//------------------------------------------------------------------------------
236//------------------------------------------------------------------------------
237 std::function<void(void)> create_zero_call(graph::input_nodes<T, SAFE_MATH> inputs) {
238 return gpu_context.create_zero_call(inputs);
239 }
240
241//------------------------------------------------------------------------------
246//------------------------------------------------------------------------------
247 std::function<void(void)> create_copy_call(graph::copy_nodes<T, SAFE_MATH> setters) {
248 return gpu_context.create_copy_call(setters);
249 }
250
251//------------------------------------------------------------------------------
253//------------------------------------------------------------------------------
255 std::cout << std::endl << source_buffer.str() << std::endl;
256 }
257
258//------------------------------------------------------------------------------
260//------------------------------------------------------------------------------
261 void save_source() {
262 std::string source = source_buffer.str();
263 std::ostringstream filename;
264 filename << std::hash<std::string> {} (source)
265 << std::hash<std::thread::id>{}(std::this_thread::get_id());
266 if constexpr (use_cuda()) {
267 filename << ".cu";
268 } else if constexpr (use_metal<T> ()) {
269 filename << ".metal";
270 } else {
271 filename << ".cpp";
272 }
273
274 std::ofstream outFile(filename.str());
275 outFile << source;
276 }
277
278//------------------------------------------------------------------------------
283//------------------------------------------------------------------------------
284 void compile(const bool add_reduction=false) {
285#ifdef SAVE_KERNEL_SOURCE
286 save_source();
287#endif
288 gpu_context.compile(source_buffer.str(),
289 kernel_names,
290 add_reduction);
291 }
292
293//------------------------------------------------------------------------------
303//------------------------------------------------------------------------------
304 std::function<void(void)> create_kernel_call(const std::string kernel_name,
309 const size_t num_rays) {
310 return gpu_context.create_kernel_call(kernel_name, inputs, outputs,
311 atomics, state, num_rays,
312 kernel_1dtextures[kernel_name],
313 kernel_2dtextures[kernel_name]);
314 }
315
316//------------------------------------------------------------------------------
322//------------------------------------------------------------------------------
323 std::function<T(void)> create_max_call(graph::shared_leaf<T, SAFE_MATH> &argument,
324 std::function<void(void)> run) {
325 return gpu_context.create_max_call(argument, run);
326 }
327
328//------------------------------------------------------------------------------
333//------------------------------------------------------------------------------
334 void print(const size_t index,
336 gpu_context.print_results(index, nodes);
337 }
338
339//------------------------------------------------------------------------------
345//------------------------------------------------------------------------------
346 T check_value(const size_t index,
348 return gpu_context.check_value(index, node);
349 }
350
351//------------------------------------------------------------------------------
353//------------------------------------------------------------------------------
354 void wait() {
355 gpu_context.wait();
356 }
357
358//------------------------------------------------------------------------------
362//------------------------------------------------------------------------------
363 std::function<void(void)> run_function(std::function<void(void)> callback) {
364 return gpu_context.run_function(callback);
365 }
366
367//------------------------------------------------------------------------------
372//------------------------------------------------------------------------------
374 T *source) {
375 gpu_context.copy_to_device(node, source);
376 }
377
378//------------------------------------------------------------------------------
383//------------------------------------------------------------------------------
385 T *destination) {
386 gpu_context.copy_to_host(node, destination);
387 }
388
389//------------------------------------------------------------------------------
393//------------------------------------------------------------------------------
395 return gpu_context.get_buffer(node);
396 }
397 };
398}
399
400#endif /* jit_h */
Class representing a cpu context.
Definition cpu_context.hpp:83
Class representing a cuda gpu context.
Definition cuda_context.hpp:74
Class representing a metal gpu context.
Definition metal_context.hpp:25
Class for JIT compile of the GPU kernels.
Definition jit.hpp:49
std::function< void(void)> create_copy_call(graph::copy_nodes< T, SAFE_MATH > setters)
Add copy.
Definition jit.hpp:247
void compile(const bool add_reduction=false)
Compile the kernel.
Definition jit.hpp:284
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:97
void wait()
Wait for kernel to finish.
Definition jit.hpp:354
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::input_nodes< T, SAFE_MATH > atomics, graph::shared_random_state< T, SAFE_MATH > state, const size_t num_rays)
Create a kernel calling function.
Definition jit.hpp:304
context(const size_t index)
Construct a jit context object.
Definition jit.hpp:111
static size_t max_random_state_size(const size_t size)
Get the number of random states needed.
Definition jit.hpp:88
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:323
std::function< void(void)> create_zero_call(graph::input_nodes< T, SAFE_MATH > inputs)
Add zero.
Definition jit.hpp:237
void add_max_reduction(const size_t size)
Add max reduction kernel.
Definition jit.hpp:227
void save_source()
Save the kernel source code.
Definition jit.hpp:261
void print(const size_t index, const graph::output_nodes< T, SAFE_MATH > &nodes)
Print output.
Definition jit.hpp:334
void copy_to_device(graph::shared_leaf< T, SAFE_MATH > &node, T *source)
Copy contexts of buffer to device.
Definition jit.hpp:373
T * get_buffer(graph::shared_leaf< T, SAFE_MATH > &node)
Get buffer from the gpu_context.
Definition jit.hpp:394
T check_value(const size_t index, const graph::shared_leaf< T, SAFE_MATH > &node)
Check the value.
Definition jit.hpp:346
std::function< void(void)> run_function(std::function< void(void)> callback)
Run a function.
Definition jit.hpp:363
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::input_nodes< T, SAFE_MATH > &atomics, graph::shared_random_state< T, SAFE_MATH > &state, const size_t size, const size_t iterations=1)
Add a kernel.
Definition jit.hpp:130
void print_source()
Print the kernel source.
Definition jit.hpp:254
void copy_to_host(graph::shared_leaf< T, SAFE_MATH > &node, T *destination)
Copy contexts of buffer to host.
Definition jit.hpp:384
Cpu context for cpus.
Cuda context for metal based gpus.
Metal context for metal based gpus.
shared_atomic_accumulate_1D< T, SAFE_MATH > atomic_accumulate_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a atomic accumulate 1D node.
Definition piecewise.hpp:2426
std::shared_ptr< random_state_node< T, SAFE_MATH > > shared_random_state
Convenience type alias for shared sqrt nodes.
Definition random.hpp:269
std::vector< shared_variable< T, SAFE_MATH > > input_nodes
Convenience type alias for a vector of inputs.
Definition node.hpp:2149
std::vector< std::pair< shared_variable< T, SAFE_MATH >, shared_variable< T, SAFE_MATH > > > copy_nodes
Convenience type alias for copying buffers.
Definition node.hpp:2157
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:691
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:2153
std::vector< shared_leaf< T, SAFE_MATH > > output_nodes
Convenience type alias for a vector of output nodes.
Definition node.hpp:706
Name space for JIT functions.
Definition jit.hpp:41
std::unordered_set< void * > visiter_map
Type alias for listing visited nodes.
Definition register.hpp:263
std::unordered_map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:261
std::unordered_set< std::string > preamble_map
Type alias for preamble defined functions.
Definition register.hpp:269
std::unordered_map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:259
constexpr bool use_cuda()
Test to use Cuda.
Definition register.hpp:68
std::unordered_map< void *, std::array< size_t, 2 > > texture2d_list
Type alias for indexing 2D textures.
Definition register.hpp:267
std::unordered_map< void *, size_t > texture1d_list
Type alias for indexing 1D textures.
Definition register.hpp:265
std::unordered_set< void * > argument_set
Type for tacking thread shared memory.
Definition register.hpp:271