Graph Framework
Loading...
Searching...
No Matches
cpu_context.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
6//------------------------------------------------------------------------------
7
8#ifndef cpu_context_h
9#define cpu_context_h
10
11#include <fstream>
12#include <cstdlib>
13#include <cstring>
14#include <thread>
15
16// Clang headers will define IBAction and IBOutlet these so undefined them
17// here.
18#undef IBAction
19#undef IBOutlet
20#include "llvm/Support/VirtualFileSystem.h"
21#include "clang/Frontend/TextDiagnosticPrinter.h"
22#include "clang/Frontend/CompilerInvocation.h"
23#include "clang/Frontend/CompilerInstance.h"
24#include "clang/Basic/TargetInfo.h"
25#include "clang/CodeGen/CodeGenAction.h"
26#include "clang/Lex/PreprocessorOptions.h"
27#include "llvm/Support/TargetSelect.h"
28#include "llvm/ExecutionEngine/Orc/LLJIT.h"
29#ifndef NDEBUG
30#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
31#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
32#endif
33#include "llvm/Support/raw_ostream.h"
34#include "llvm/ADT/IntrusiveRefCntPtr.h"
35#include "llvm/ADT/SmallVector.h"
36#include "llvm/TargetParser/Host.h"
37#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
38
39#include "random.hpp"
40#include "piecewise.hpp"
41#include "timing.hpp"
42
43#ifndef NDEBUG
44//------------------------------------------------------------------------------
46//------------------------------------------------------------------------------
47LLVM_ATTRIBUTE_USED void linkComponents() {
48 llvm::errs() << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
49}
50#endif
51
52namespace gpu {
53//------------------------------------------------------------------------------
62//------------------------------------------------------------------------------
63 llvm::SmallVector<const char *, 8> split_string(char *string) {
64 llvm::SmallVector<const char *, 8> args = {string};
65
66 while (*(++string) != '\0') {
67 if (*string == ' ') {
68 *string = '\0';
69 args.push_back(++string);
70 }
71 }
72
73 return args;
74 }
75
76//------------------------------------------------------------------------------
81//------------------------------------------------------------------------------
82 template<jit::float_scalar T, bool SAFE_MATH=false>
84 private:
86 std::unique_ptr<llvm::orc::LLJIT> jit;
88 std::unordered_map<graph::leaf_node<T, SAFE_MATH> *, std::vector<T>> kernel_arguments;
90 std::unordered_map<graph::leaf_node<T, SAFE_MATH> *, std::vector<T>> host_buffers;
92 std::unordered_map<graph::leaf_node<T, SAFE_MATH> *, size_t> arg_index;
93
94 public:
96 constexpr static size_t random_state_size = 1;
97
100
101//------------------------------------------------------------------------------
105//------------------------------------------------------------------------------
106 static size_t max_concurrency() {
107 return std::thread::hardware_concurrency();
108 }
109
110//------------------------------------------------------------------------------
112//------------------------------------------------------------------------------
113 static std::string device_type() {
114 return "CPU";
115 }
116
117//------------------------------------------------------------------------------
121//------------------------------------------------------------------------------
122 cpu_context(const size_t index) {
123 llvm::InitializeNativeTarget();
124 llvm::InitializeNativeTargetAsmPrinter();
125 }
126
127//------------------------------------------------------------------------------
133//------------------------------------------------------------------------------
134 void compile(const std::string kernel_source,
135 std::vector<std::string> names,
136 const bool add_reduction=false) {
137 std::ostringstream temp_stream;
138 temp_stream << reinterpret_cast<size_t> (this);
139 const std::string thread_id = temp_stream.str();
140
141 temp_stream.str(std::string());
142 temp_stream.clear();
143
144 temp_stream << "temp_" << thread_id << ".cpp";
145
146 const std::string filename = temp_stream.str();
147
148 if (jit::verbose) {
149 std::cout << "CPU info." << std::endl;
150 std::cout << " Command Line : " << std::endl;
151 }
152
153 char arg_string[] = CXX_ARGS;
154 llvm::SmallVector<const char *, 8> args = split_string(arg_string);
155 args.push_back(filename.c_str());
156#ifdef NDEBUG
157 args.push_back("-ffast-math");
158 args.push_back("-O3");
159#else
160 args.push_back("-debug-info-kind=standalone");
161#endif
162 if (jit::verbose) {
163 for (auto &arg : args) {
164 std::cout << " " << arg << std::endl;
165 }
166 }
167
168 clang::DiagnosticOptions diagnostic_options;
169 auto diagnostic_printer = std::make_unique<clang::TextDiagnosticPrinter> (llvm::errs(),
170 diagnostic_options);
171
172 auto diagnostic_ids = llvm::makeIntrusiveRefCnt<clang::DiagnosticIDs> ();
173 clang::DiagnosticsEngine diagnostic_engine(diagnostic_ids,
174 diagnostic_options,
175 diagnostic_printer.release());
176
177 auto invocation = std::make_shared<clang::CompilerInvocation> ();
178 clang::CompilerInvocation::CreateFromArgs(*(invocation.get()), args,
179 diagnostic_engine);
180
181 llvm::StringRef source_code_data(kernel_source);
182 auto buffer = llvm::MemoryBuffer::getMemBuffer(source_code_data);
183 invocation->getPreprocessorOpts().addRemappedFile(filename.c_str(),
184 buffer.release());
185
186 clang::CompilerInstance clang(invocation);
187 clang.createDiagnostics();
188
189 clang::TargetOptions target_options;
190 target_options.Triple = llvm::sys::getProcessTriple();
191 auto *target_info = clang::TargetInfo::CreateTargetInfo(diagnostic_engine,
192 target_options);
193 clang.setTarget(target_info);
194
195 clang::EmitLLVMOnlyAction action;
196 clang.ExecuteAction(action);
197
198 auto ir_module = action.takeModule();
199 auto context = std::unique_ptr<llvm::LLVMContext> (action.takeLLVMContext());
200
201 auto jit_try = llvm::orc::LLJITBuilder()
202#ifndef NDEBUG
203 .setPrePlatformSetup([](llvm::orc::LLJIT &J) {
204 return llvm::orc::enableDebuggerSupport(J);
205 })
206#endif
207 .create();
208 if (auto jiterror = jit_try.takeError()) {
209 std::cerr << "Failed to build JIT : " << toString(std::move(jiterror)) << std::endl;
210 exit(-1);
211 }
212 jit = std::move(jit_try.get());
213
214 auto error = jit->addIRModule(llvm::orc::ThreadSafeModule(std::move(ir_module),
215 llvm::orc::ThreadSafeContext(std::move(context))));
216
217#ifdef MACOS_LIB_RT
218 error = jit->linkStaticLibraryInto(jit->getMainJITDylib(), MACOS_LIB_RT);
219#endif
220 }
221
222//------------------------------------------------------------------------------
234//------------------------------------------------------------------------------
235 std::function<void(void)> create_kernel_call(const std::string kernel_name,
240 const size_t num_rays,
241 const jit::texture1d_list &tex1d_list,
242 const jit::texture2d_list &tex2d_list) {
243 auto entry = std::move(jit->lookup(kernel_name)).get();
244
245 std::unordered_map<size_t, T *> buffers;
246
247 for (auto &input : inputs) {
248 if (!kernel_arguments.contains(input.get())) {
249 std::vector<T> arg(input->size());
250 memcpy(arg.data(), input->data(), input->size()*sizeof(T));
251 kernel_arguments[input.get()] = arg;
252 }
253 buffers[reinterpret_cast<size_t> (input.get())] = kernel_arguments[input.get()].data();
254 }
255 for (auto &output : outputs) {
257 if (!kernel_arguments.contains(output.get())) {
258 std::vector<T> arg(num_rays);
259 kernel_arguments[output.get()] = arg;
260 }
261 buffers[reinterpret_cast<size_t> (output.get())] = kernel_arguments[output.get()].data();
262 }
263 }
264 for (auto &atomic : atomics) {
265 if (!kernel_arguments.contains(atomic.get())) {
266 std::vector<T> arg(atomic->size());
267 memcpy(arg.data(), atomic->data(), atomic->size()*sizeof(T));
268 kernel_arguments[atomic.get()] = arg;
269 }
270 buffers[reinterpret_cast<size_t> (atomic.get())] = kernel_arguments[atomic.get()].data();
271 }
272
273 if (state.get()) {
274 auto kernel = entry.toPtr<void(*)(std::unordered_map<size_t, T *> &, typename graph::random_state_node<T, SAFE_MATH>::mt_state *)> ();
275
276 if (!kernel) {
277 std::cerr << "Failed to load function. " << kernel_name
278 << std::endl;
279 exit(-1);
280 }
281
282 if (jit::verbose) {
283 std::cout << " Function pointer: "
284 << reinterpret_cast<size_t> (kernel)
285 << std::endl;
286 }
287
288 return [kernel, buffers, state
289#ifdef PROFILE_KERNELS
290 , kernel_name
291#endif
292 ] () mutable {
293#ifdef PROFILE_KERNELS
294 timing::measure_diagnostic timer(kernel_name);
295#endif
296 kernel(buffers, state->data());
297#ifdef PROFILE_KERNELS
298 timer.print();
299#endif
300 };
301 } else {
302 auto kernel = entry.toPtr<void(*)(std::unordered_map<size_t, T *> &)> ();
303
304 if (!kernel) {
305 std::cerr << "Failed to load function. " << kernel_name
306 << std::endl;
307 exit(-1);
308 }
309
310 if (jit::verbose) {
311 std::cout << " Function pointer: "
312 << reinterpret_cast<size_t> (kernel)
313 << std::endl;
314 }
315
316 return [kernel, buffers
317#ifdef PROFILE_KERNELS
318 , kernel_name
319#endif
320 ] () mutable {
321#ifdef PROFILE_KERNELS
322 timing::measure_diagnostic timer(kernel_name);
323#endif
324 kernel(buffers);
325#ifdef PROFILE_KERNELS
326 timer.print();
327#endif
328 };
329 }
330 }
331
332//------------------------------------------------------------------------------
338//------------------------------------------------------------------------------
339 std::function<T(void)> create_max_call(graph::shared_leaf<T, SAFE_MATH> &argument,
340 std::function<void(void)> run) {
341 auto begin = kernel_arguments[argument.get()].cbegin();
342 auto end = kernel_arguments[argument.get()].cend();
343
344 return [run, begin, end] () mutable {
345 run();
346 if constexpr (jit::complex_scalar<T>) {
347 return *std::max_element(begin, end,
348 [] (const T a, const T b) {
349 return std::abs(a) < std::abs(b);
350 });
351 } else {
352 return *std::max_element(begin, end);
353 }
354 };
355 }
356
357//------------------------------------------------------------------------------
362//------------------------------------------------------------------------------
363 std::function<void(void)> create_zero_call(graph::input_nodes<T, SAFE_MATH> &inputs) {
364 std::vector<T *> buffers;
365 std::vector<size_t> sizes;
366
367 for (auto &input : inputs) {
368 if (!kernel_arguments.contains(input.get())) {
369 std::vector<T> arg(input->size());
370 memcpy(arg.data(), input->data(), input->size()*sizeof(T));
371 kernel_arguments[input.get()] = arg;
372 }
373 buffers.push_back(kernel_arguments[input.get()].data());
374 sizes.push_back(input->size()*sizeof(T));
375 }
376
377 return [buffers, sizes] () mutable {
378#ifdef PROFILE_KERNELS
379 timing::measure_diagnostic timer("zero buffer");
380#endif
381 for (size_t i = 0, ie = buffers.size(); i < ie; i++) {
382 std::memset(buffers[i], 0, sizes[i]);
383 }
384#ifdef PROFILE_KERNELS
385 timer.print();
386#endif
387 };
388 }
389
390//------------------------------------------------------------------------------
395//------------------------------------------------------------------------------
396 std::function<void(void)> create_copy_call(graph::copy_nodes<T, SAFE_MATH> &setters) {
397 std::vector<T *> sources;
398 std::vector<T *> destinations;
399 std::vector<size_t> sizes;
400
401 for (auto &[out, in] : setters) {
402 if (!kernel_arguments.contains(in.get())) {
403 std::vector<T> arg(in->size());
404 memcpy(arg.data(), in->data(), in->size()*sizeof(T));
405 kernel_arguments[in.get()] = arg;
406 }
407 destinations.push_back(kernel_arguments[in.get()].data());
408 sizes.push_back(in->size()*sizeof(T));
409
410 if (!kernel_arguments.contains(out.get())) {
411 std::vector<T> arg(out->size());
412 memcpy(arg.data(), out->data(), out->size()*sizeof(T));
413 kernel_arguments[out.get()] = arg;
414 }
415 sources.push_back(kernel_arguments[out.get()].data());
416 }
417
418 return [sources, destinations, sizes] () mutable {
419#ifdef PROFILE_KERNELS
420 timing::measure_diagnostic timer("copy buffer");
421#endif
422 for (size_t i = 0, ie = sources.size(); i < ie; i++) {
423 std::memcpy(destinations[i], sources[i], sizes[i]);
424 }
425#ifdef PROFILE_KERNELS
426 timer.print();
427#endif
428 };
429 }
430
431//------------------------------------------------------------------------------
436//------------------------------------------------------------------------------
437 void wait() {
438 for (auto &item : host_buffers) {
439 memcpy(item.second.data(),
440 kernel_arguments[item.first].data(),
441 sizeof(T)*kernel_arguments[item.first].size());
442 }
443 }
444
445//------------------------------------------------------------------------------
450//------------------------------------------------------------------------------
451 std::function<void(void)> run_function(std::function<void(void)> callback) {
452#ifdef PROFILE_KERNELS
453 return [callback]() {
454 timing::measure_diagnostic timer("callback");
455 callback();
456 timer.print();
457 };
458#else
459 return callback;
460#endif
461 }
462
463//------------------------------------------------------------------------------
468//------------------------------------------------------------------------------
469 void print_results(const size_t index,
471 for (auto &out : nodes) {
472 const T temp = kernel_arguments[out.get()][index];
473 if constexpr (jit::complex_scalar<T>) {
474 std::cout << std::real(temp) << " " << std::imag(temp) << " ";
475 } else {
476 std::cout << temp << " ";
477 }
478 }
479 std::cout << std::endl;
480 }
481
482//------------------------------------------------------------------------------
488//------------------------------------------------------------------------------
489 T check_value(const size_t index,
491 return kernel_arguments[node.get()][index];
492 }
493
494//------------------------------------------------------------------------------
499//------------------------------------------------------------------------------
501 T *source) {
502 memcpy(kernel_arguments[node.get()].data(),
503 source,
504 sizeof(T)*kernel_arguments[node.get()].size());
505 }
506
507//------------------------------------------------------------------------------
512//------------------------------------------------------------------------------
514 T *destination) {
515 memcpy(destination,
516 kernel_arguments[node.get()].data(),
517 sizeof(T)*kernel_arguments[node.get()].size());
518 }
519
520//------------------------------------------------------------------------------
524//------------------------------------------------------------------------------
525 void create_header(std::ostringstream &source_buffer) {
526 source_buffer << "#include <unordered_map>" << std::endl
527 << "#include <array>" << std::endl
528 << "#include <cstdint>" << std::endl
529 << "#include <bit>" << std::endl;
531 source_buffer << "#include <complex>" << std::endl;
532 source_buffer << "#include <special_functions.hpp>" << std::endl;
533 } else {
534 source_buffer << "#include <cmath>" << std::endl;
535 }
536 source_buffer << "#include <atomic>" << std::endl
537 << "using namespace std;" << std::endl;
538 }
539
540//------------------------------------------------------------------------------
558//------------------------------------------------------------------------------
559 void create_kernel_prefix(std::ostringstream &source_buffer,
560 const std::string name,
565 const size_t size,
566 const std::vector<bool> &is_constant,
567 jit::register_map &registers,
568 const jit::register_usage &usage,
569 jit::texture1d_list &textures1d,
570 jit::texture2d_list &textures2d,
571 jit::argument_set &thread_shared,
572 jit::register_map &thread_mem,
573 const size_t iterations=1) {
574 source_buffer << std::endl;
575 source_buffer << "extern \"C\" void " << name << "(" << std::endl;
576
577 source_buffer << " unordered_map<size_t, ";
578 jit::add_type<T> (source_buffer);
579 source_buffer << " *> &args";
580 if (state.get()) {
581 source_buffer << "," << std::endl
582 << " mt_state *" << jit::to_string('s', state.get());
583 }
584 source_buffer << ") {" << std::endl;
585
586 jit::argument_set used_args;
587 for (size_t i = 0, ie = inputs.size(); i < ie; i++) {
588 if (!used_args.contains(inputs[i].get())) {
589 source_buffer << " ";
590 if (is_constant[i]) {
591 source_buffer << "const ";
592 }
593 jit::add_type<T> (source_buffer);
594 source_buffer << " *" << jit::to_string('v', inputs[i].get())
595 << " = args["
596 << reinterpret_cast<size_t> (inputs[i].get())
597 << "];" << std::endl;
598 used_args.insert(inputs[i].get());
599 }
600 }
601 for (auto &output : outputs) {
602 if (!used_args.contains(output.get()) &&
604 source_buffer << " ";
605 jit::add_type<T> (source_buffer);
606 source_buffer << " *" << jit::to_string('o', output.get())
607 << " = args["
608 << reinterpret_cast<size_t> (output.get())
609 << "];" << std::endl;
610 used_args.insert(output.get());
611 }
612 }
613 for (size_t i = 0, ie = atomics.size(); i < ie; i++) {
614 if (!used_args.contains(atomics[i].get())) {
615 source_buffer << " ";
616 jit::add_type<T> (source_buffer);
617 source_buffer << " *"
618 << jit::to_string('v', atomics[i].get())
619 << " = args["
620 << reinterpret_cast<size_t> (atomics[i].get())
621 << "];"
622 << std::endl;
623 used_args.insert(atomics[i].get());
624 }
625 }
626 if (state.get()) {
627 registers[state.get()] = jit::to_string('r', state.get());
628 source_buffer << " mt_state &"
629 << registers[state.get()] << " = "
630 << jit::to_string('s', state.get()) << "[0]";
631 state->endline(source_buffer, usage);
632 }
633 source_buffer << " for (size_t i = 0; i < " << size << "; i++) {" << std::endl;
634 if (iterations > 1) {
635 source_buffer << " for (size_t j = 0; j < " << iterations << "; j++) {" << std::endl;
636 }
637
638 for (auto &input : inputs) {
639 registers[input.get()] = jit::to_string('r', input.get());
640 source_buffer << " const ";
641 jit::add_type<T> (source_buffer);
642 source_buffer << " " << registers[input.get()]
643 << " = " << jit::to_string('v', input.get())
644 << "[i]";
645 input->endline(source_buffer, usage);
646 }
647 }
648
649//------------------------------------------------------------------------------
661//------------------------------------------------------------------------------
662 void create_kernel_postfix(std::ostringstream &source_buffer,
666 jit::register_map &registers,
667 const jit::register_usage &usage,
668 const jit::argument_set &thread_shared,
669 jit::register_map &thread_mem,
670 const size_t iterations=1) {
671 jit::argument_set out_registers;
672 for (auto &[out, in] : setters) {
673 if (!out->is_match(in)) {
674 auto a = out->compile(source_buffer, registers,
675 thread_mem, usage);
676 source_buffer << " " << jit::to_string('v', in.get());
677 source_buffer << "[i] = ";
678 if constexpr (SAFE_MATH) {
679 if constexpr (jit::complex_scalar<T>) {
680 jit::add_type<T> (source_buffer);
681 source_buffer << " (";
682 if (!graph::random_cast(a).get()) {
683 source_buffer << "isnan(real("
684 << registers[a.get()]
685 << ")) ? 0.0 : real("
686 << registers[a.get()]
687 << "), isnan(imag("
688 << registers[a.get()]
689 << ")) ? 0.0 : imag("
690 << registers[a.get()]
691 << ")";
692 } else {
693 source_buffer << registers[a.get()];
694 }
695 source_buffer << ");" << std::endl;
696 } else {
697 if (!graph::random_cast(a).get()) {
698 source_buffer << "isnan(" << registers[a.get()]
699 << ") ? 0.0 : ";
700 }
701 source_buffer << registers[a.get()]
702 << ";" << std::endl;
703 }
704 } else {
705 source_buffer << registers[a.get()] << ";" << std::endl;
706 }
707 out_registers.insert(out.get());
708 }
709 }
710 for (auto &out : outputs) {
711 if (!graph::variable_cast(out).get() &&
713 !out_registers.contains(out.get())) {
714 auto a = out->compile(source_buffer, registers,
715 thread_mem, usage);
716 source_buffer << " " << jit::to_string('o', out.get());
717 source_buffer << "[i] = ";
718 if constexpr (SAFE_MATH) {
719 if constexpr (jit::complex_scalar<T>) {
720 jit::add_type<T> (source_buffer);
721 source_buffer << " (";
722 if (!graph::random_cast(a).get()) {
723 source_buffer << "isnan(real("
724 << registers[a.get()]
725 << ")) ? 0.0 : real("
726 << registers[a.get()]
727 << "), isnan(imag("
728 << registers[a.get()]
729 << ")) ? 0.0 : imag("
730 << registers[a.get()]
731 << ")";
732 } else {
733 source_buffer << registers[a.get()];
734 }
735 source_buffer << ");" << std::endl;
736 } else {
737 if (!graph::random_cast(a).get()) {
738 source_buffer << "isnan(" << registers[a.get()]
739 << ") ? 0.0 : ";
740 }
741 source_buffer << registers[a.get()]
742 << ";" << std::endl;
743 }
744 } else {
745 source_buffer << registers[a.get()] << ";" << std::endl;
746 }
747 out_registers.insert(out.get());
748 }
749 }
750
751 if (iterations > 1) {
752 source_buffer << " }" << std::endl;
753 }
754 source_buffer << " }" << std::endl << "}" << std::endl;
755 }
756
757//------------------------------------------------------------------------------
762//------------------------------------------------------------------------------
763 void create_reduction(std::ostringstream &source_buffer,
764 const size_t size) {}
765
766//------------------------------------------------------------------------------
775//------------------------------------------------------------------------------
777 if (!host_buffers.contains(node.get())) {
778 host_buffers[node.get()] = kernel_arguments[node.get()];
779 }
780 return host_buffers[node.get()].data();
781 }
782 };
783}
784
785#endif /* cpu_context_h */
Class representing a cpu context.
Definition cpu_context.hpp:83
void print_results(const size_t index, const graph::output_nodes< T, SAFE_MATH > &nodes)
Print out the results.
Definition cpu_context.hpp:469
std::function< void(void)> create_copy_call(graph::copy_nodes< T, SAFE_MATH > &setters)
Create kernel call that will to copy one buffer to another.
Definition cpu_context.hpp:396
std::function< void(void)> run_function(std::function< void(void)> callback)
Run a callback function in the queue.
Definition cpu_context.hpp:451
void create_kernel_postfix(std::ostringstream &source_buffer, graph::output_nodes< T, SAFE_MATH > &outputs, graph::map_nodes< T, SAFE_MATH > &setters, graph::shared_random_state< T, SAFE_MATH > state, jit::register_map &registers, const jit::register_usage &usage, const jit::argument_set &thread_shared, jit::register_map &thread_mem, const size_t iterations=1)
Create kernel postfix.
Definition cpu_context.hpp:662
void copy_to_device(graph::shared_leaf< T, SAFE_MATH > node, T *source)
Copy buffer contents to the device.
Definition cpu_context.hpp:500
T check_value(const size_t index, const graph::shared_leaf< T, SAFE_MATH > &node)
Check the value.
Definition cpu_context.hpp:489
void create_reduction(std::ostringstream &source_buffer, const size_t size)
Create a reduction kernel.
Definition cpu_context.hpp:763
cpu_context(const size_t index)
Construct a cpu context.
Definition cpu_context.hpp:122
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, const jit::texture1d_list &tex1d_list, const jit::texture2d_list &tex2d_list)
Create a kernel calling function.
Definition cpu_context.hpp:235
void wait()
Hold the current thread until the command buffer has completed.
Definition cpu_context.hpp:437
static constexpr size_t random_state_size
Size of random state needed.
Definition cpu_context.hpp:96
void copy_to_host(const graph::shared_leaf< T, SAFE_MATH > node, T *destination)
Copy buffer contents to host.
Definition cpu_context.hpp:513
void create_kernel_prefix(std::ostringstream &source_buffer, const std::string 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 size, const std::vector< bool > &is_constant, jit::register_map &registers, const jit::register_usage &usage, jit::texture1d_list &textures1d, jit::texture2d_list &textures2d, jit::argument_set &thread_shared, jit::register_map &thread_mem, const size_t iterations=1)
Create kernel prefix.
Definition cpu_context.hpp:559
static std::string device_type()
Device description.
Definition cpu_context.hpp:113
T * get_buffer(graph::shared_leaf< T, SAFE_MATH > &node)
Get the buffer for a node.
Definition cpu_context.hpp:776
void compile(const std::string kernel_source, std::vector< std::string > names, const bool add_reduction=false)
Compile the kernels.
Definition cpu_context.hpp:134
int remaining_const_memory
Remaining constant memory in bytes. NOT USED.
Definition cpu_context.hpp:99
std::function< void(void)> create_zero_call(graph::input_nodes< T, SAFE_MATH > &inputs)
Create kernel call that will be memset a buffer to zero.
Definition cpu_context.hpp:363
std::function< T(void)> create_max_call(graph::shared_leaf< T, SAFE_MATH > &argument, std::function< void(void)> run)
Create a max compute pipeline.
Definition cpu_context.hpp:339
void create_header(std::ostringstream &source_buffer)
Create the source header.
Definition cpu_context.hpp:525
static size_t max_concurrency()
Get the maximum number of concurrent instances.
Definition cpu_context.hpp:106
A timing object.
Definition timing.hpp:18
void print() const
Print the result.
Definition timing.hpp:52
Complex scalar concept.
Definition register.hpp:25
LLVM_ATTRIBUTE_USED void linkComponents()
This just exposes the functions so the debugger links.
Definition cpu_context.hpp:47
Name space for GPU backends.
Definition cpu_context.hpp:52
llvm::SmallVector< const char *, 8 > split_string(char *string)
Split a string by the space delimiter.
Definition cpu_context.hpp:63
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
shared_variable< T, SAFE_MATH > variable_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a variable node.
Definition node.hpp:2169
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
shared_random< T, SAFE_MATH > random_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a random node.
Definition random.hpp:539
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_map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:261
std::unordered_map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:259
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::string to_string(const char prefix, const NODE *pointer)
Convert a graph::leaf_node pointer to a string.
Definition register.hpp:247
std::unordered_set< void * > argument_set
Type for tacking thread shared memory.
Definition register.hpp:271
Name space for output files.
Definition output.hpp:16
Piecewise nodes.
Random constants and distributions.
Random state structure.
Definition random.hpp:44
Routines to time the ray execution.