ViennaCL - The Vienna Computing Library: viennacl/ocl/context.hpp Source File

ViennaCL - The Vienna Computing Library 1.7.1 Free open-source GPU-accelerated linear algebra and solver library. |

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
context.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_OCL_CONTEXT_HPP_
2 #define VIENNACL_OCL_CONTEXT_HPP_
3
4 /* =========================================================================
5 Copyright (c) 2010-2016, Institute for Microelectronics,
6 Institute for Analysis and Scientific Computing,
7 TU Wien.
8 Portions of this software are copyright by UChicago Argonne, LLC.
9
10 -----------------
11 ViennaCL - The Vienna Computing Library
12 -----------------
13
14 Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15
16 (A list of authors and contributors can be found in the manual)
17
18 License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20
25 #ifdef __APPLE__
26 #include <OpenCL/cl.h>
27 #else
28 #include <CL/cl.h>
29 #endif
30
31 #include <algorithm>
32 #include <fstream>
33 #include <vector>
34 #include <map>
35 #include <cstdlib>
36 #include "viennacl/ocl/forwards.h"
37 #include "viennacl/ocl/error.hpp"
38 #include "viennacl/ocl/handle.hpp"
39 #include "viennacl/ocl/kernel.hpp"
40 #include "viennacl/ocl/program.hpp"
41 #include "viennacl/ocl/device.hpp"
42 #include "viennacl/ocl/platform.hpp"
43 #include "viennacl/ocl/command_queue.hpp"
44 #include "viennacl/tools/sha1.hpp"
45 #include "viennacl/tools/shared_ptr.hpp"
46 namespace viennacl
47 {
48 namespace ocl
49 {
55 class context
56 {
57 typedef std::vector< tools::shared_ptr<viennacl::ocl::program> > program_container_type;
58
59 public:
60 context() : initialized_(false),
61 device_type_(CL_DEVICE_TYPE_DEFAULT),
62 current_device_id_(0),
63 default_device_num_(1),
64 pf_index_(0),
65 current_queue_id_(0)
66 {
67 if (std::getenv("VIENNACL_CACHE_PATH"))
68 cache_path_ = std::getenv("VIENNACL_CACHE_PATH");
69 else
70 cache_path_ = "";
71 }
72
74
75 std::string cache_path() const { return cache_path_; }
76
78 void cache_path(std::string new_path) { cache_path_ = new_path; }
79
81
82 vcl_size_t default_device_num() const { return default_device_num_; }
83
85 void default_device_num(vcl_size_t new_num) { default_device_num_ = new_num; }
86
88
89 cl_device_type default_device_type()
90 {
91 return device_type_;
92 }
93
95 void default_device_type(cl_device_type dtype)
96 {
97 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
98 std::cout << "ViennaCL: Setting new device type for context " << h_ << std::endl;
99 #endif
100 if (!initialized_)
101 device_type_ = dtype; //assume that the user provided a correct value
102 }
103
105
106 std::vector<viennacl::ocl::device> const & devices() const
107 {
108 return devices_;
109 }
110
112 viennacl::ocl::device const & current_device() const
113 {
114 //std::cout << "Current device id in context: " << current_device_id_ << std::endl;
115 return devices_[current_device_id_];
116 }
117
119 void switch_device(vcl_size_t i)
120 {
121 assert(i < devices_.size() && bool("Provided device index out of range!"));
122 current_device_id_ = i;
123 }
124
126 void switch_device(viennacl::ocl::device const & d)
127 {
128 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
129 std::cout << "ViennaCL: Setting new current device for context " << h_ << std::endl;
130 #endif
131 bool found = false;
132 for (vcl_size_t i=0; i<devices_.size(); ++i)
133 {
134 if (devices_[i] == d)
135 {
136 found = true;
137 current_device_id_ = i;
138 break;
139 }
140 }
141 if (found == false)
142 std::cerr << "ViennaCL: Warning: Could not set device " << d.name() << " for context." << std::endl;
143 }
144
146 void add_device(viennacl::ocl::device const & d)
147 {
148 assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
149 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
150 std::cout << "ViennaCL: Adding new device to context " << h_ << std::endl;
151 #endif
152 if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
153 devices_.push_back(d);
154 }
155
157 void add_device(cl_device_id d)
158 {
159 assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
160 add_device(viennacl::ocl::device(d));
161 }
162
163
165
167 void init()
168 {
169 init_new();
170 }
171
173 void init(cl_context c)
174 {
175 init_existing(c);
176 }
177
178 /* void existing_context(cl_context context_id)
179 {
180 assert(!initialized_ && bool("ViennaCL: FATAL error: Provided a new context for an already initialized context."));
181 #i#if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
182 std::cout << "ViennaCL: Reusing existing context " << h_ << std::endl;
183 #e#endif
184 h_ = context_id;
185 }*/
186
188
196 cl_mem create_memory_without_smart_handle(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
197 {
198 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
199 std::cout << "ViennaCL: Creating memory of size " << size << " for context " << h_ << " (unsafe, returning cl_mem directly)" << std::endl;
200 #endif
201 if (ptr)
202 flags |= CL_MEM_COPY_HOST_PTR;
203 cl_int err;
204 cl_mem mem = clCreateBuffer(h_.get(), flags, size, ptr, &err);
205 VIENNACL_ERR_CHECK(err);
206 return mem;
207 }
208
209
216 viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
217 {
218 return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, size, ptr), *this);
219 }
220
226 template< typename NumericT, typename A, template<typename, typename> class VectorType >
227 viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, const VectorType<NumericT, A> & buffer) const
228 {
229 return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, static_cast<cl_uint>(sizeof(NumericT) * buffer.size()), (void*)&buffer[0]), *this);
230 }
231
233
235 void add_queue(cl_device_id dev, cl_command_queue q)
236 {
237 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
238 std::cout << "ViennaCL: Adding existing queue " << q << " for device " << dev << " to context " << h_ << std::endl;
239 #endif
240 viennacl::ocl::handle<cl_command_queue> queue_handle(q, *this);
241 queues_[dev].push_back(viennacl::ocl::command_queue(queue_handle));
242 queues_[dev].back().handle().inc();
243 }
244
246 void add_queue(cl_device_id dev)
247 {
248 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
249 std::cout << "ViennaCL: Adding new queue for device " << dev << " to context " << h_ << std::endl;
250 #endif
251 cl_int err;
252 #ifdef VIENNACL_PROFILING_ENABLED
253 viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, CL_QUEUE_PROFILING_ENABLE, &err), *this);
254 #else
255 viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, 0, &err), *this);
256 #endif
257 VIENNACL_ERR_CHECK(err);
258
259 queues_[dev].push_back(viennacl::ocl::command_queue(temp));
260 }
261
263 void add_queue(viennacl::ocl::device d) { add_queue(d.id()); }
264
265 //get queue for default device:
266 viennacl::ocl::command_queue & get_queue()
267 {
268 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
269 std::cout << "ViennaCL: Getting queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
270 std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
271 #endif
272
273 return queues_[devices_[current_device_id_].id()][current_queue_id_];
274 }
275
276 viennacl::ocl::command_queue const & get_queue() const
277 {
278 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
279
280 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
281 std::cout << "ViennaCL: Getting const queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
282 std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
283 #endif
284
285 // find queue:
286 QueueContainer::const_iterator it = queues_.find(devices_[current_device_id_].id());
287 if (it != queues_.end()) {
288 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
289 std::cout << "ViennaCL: Queue handle " << (it->second)[current_queue_id_].handle() << std::endl;
290 #endif
291 return (it->second)[current_queue_id_];
292 }
293
294 throw queue_not_found("Could not obtain current command queue");
295
296 //return ((*it)->second)[current_queue_id_];
297 }
298
299 //get a particular queue:
301 viennacl::ocl::command_queue & get_queue(cl_device_id dev, vcl_size_t i = 0)
302 {
303 if (i >= queues_[dev].size())
304 throw invalid_command_queue();
305
306 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
307 std::cout << "ViennaCL: Getting queue " << i << " for device " << dev << " in context " << h_ << std::endl;
308 #endif
309 unsigned int device_index;
310 for (device_index = 0; device_index < devices_.size(); ++device_index)
311 {
312 if (devices_[device_index] == dev)
313 break;
314 }
315
316 assert(device_index < devices_.size() && bool("Device not within context"));
317
318 return queues_[devices_[device_index].id()][i];
319 }
320
322 // TODO: work out the const issues
323 viennacl::ocl::command_queue const & current_queue() //const
324 {
325 return queues_[devices_[current_device_id_].id()][current_queue_id_];
326 }
327
329 void switch_queue(vcl_size_t i)
330 {
331 assert(i < queues_[devices_[current_device_id_].id()].size() && bool("In class 'context': Provided queue index out of range for device!"));
332 current_queue_id_ = i;
333 }
334
336 void switch_queue(viennacl::ocl::command_queue const & q)
337 {
338 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
339 std::cout << "ViennaCL: Setting new current queue for context " << h_ << std::endl;
340 #endif
341 bool found = false;
342 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
343
344 // For each device:
345 vcl_size_t j = 0;
346 for (QueueContainer::const_iterator it=queues_.begin(); it != queues_.end(); it++,j++)
347 {
348 const std::vector<viennacl::ocl::command_queue> & qv = (it->second);
349 // For each queue candidate
350 for (vcl_size_t i=0; i<qv.size(); ++i)
351 {
352 if (qv[i] == q)
353 {
354 found = true;
355 current_device_id_ = j;
356 current_queue_id_ = i;
357 break;
358 }
359 }
360 }
361 if (found == false)
362 std::cerr << "ViennaCL: Warning: Could not set queue " << q.handle().get() << " for context." << std::endl;
363 }
364
366
368 viennacl::ocl::program & add_program(cl_program p, std::string const & prog_name)
369 {
370 programs_.push_back(tools::shared_ptr<ocl::program>(new viennacl::ocl::program(p, *this, prog_name)));
371 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
372 std::cout << "ViennaCL: Adding program '" << prog_name << "' with cl_program to context " << h_ << std::endl;
373 #endif
374 return *programs_.back();
375 }
376
379 viennacl::ocl::program & add_program(std::string const & source, std::string const & prog_name)
380 {
381 const char * source_text = source.c_str();
382 vcl_size_t source_size = source.size();
383 cl_int err;
384
385 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
386 std::cout << "ViennaCL: Adding program '" << prog_name << "' with source to context " << h_ << std::endl;
387 #endif
388
389 cl_program temp = 0;
390
391 //
392 // Retrieves the program in the cache
393 //
394 if (cache_path_.size())
395 {
396 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
397 std::cout << "ViennaCL: Cache at " << cache_path_ << std::endl;
398 #endif
399
400 std::string prefix;
401 for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
402 prefix += it->name() + it->vendor() + it->driver_version();
403 std::string sha1 = tools::sha1(prefix + source);
404
405 std::ifstream cached((cache_path_+sha1).c_str(),std::ios::binary);
406 if (cached)
407 {
408 vcl_size_t len;
409 std::vector<unsigned char> buffer;
410
411 cached.read((char*)&len, sizeof(vcl_size_t));
412 buffer.resize(len);
413 cached.read((char*)(&buffer[0]), std::streamsize(len));
414
415 cl_int status;
416 cl_device_id devid = devices_[0].id();
417 const unsigned char * bufdata = &buffer[0];
418 temp = clCreateProgramWithBinary(h_.get(),1,&devid,&len, &bufdata,&status,&err);
419 VIENNACL_ERR_CHECK(err);
420 }
421 }
422
423 if (!temp)
424 {
425 temp = clCreateProgramWithSource(h_.get(), 1, (const char **)&source_text, &source_size, &err);
426 VIENNACL_ERR_CHECK(err);
427 }
428
429 const char * options = build_options_.c_str();
430 err = clBuildProgram(temp, 0, NULL, options, NULL, NULL);
431 #ifndef VIENNACL_BUILD_INFO
432 if (err != CL_SUCCESS)
433 #endif
434 {
435 cl_build_status status;
436 clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL);
437 std::cout << "Build Status = " << status << " ( Err = " << err << " )" << std::endl;
438
439 char *build_log;
440 size_t ret_val_size; // don't use vcl_size_t here
441 err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
442 build_log = new char[ret_val_size+1];
443 err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
444 build_log[ret_val_size] = '\0';
445 std::cout << "Log: " << build_log << std::endl;
446 delete[] build_log;
447
448 std::cout << "Sources: " << source << std::endl;
449 }
450 VIENNACL_ERR_CHECK(err);
451
452 //
453 // Store the program in the cache
454 //
455 if (cache_path_.size())
456 {
457 vcl_size_t len;
458
459 std::vector<vcl_size_t> sizes(devices_.size());
460 clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,0,NULL,&len);
461 clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,len,(void*)&sizes[0],NULL);
462
463 std::vector<unsigned char*> binaries;
464 for (vcl_size_t i = 0; i < devices_.size(); ++i)
465 binaries.push_back(new unsigned char[sizes[i]]);
466
467 clGetProgramInfo(temp,CL_PROGRAM_BINARIES,0,NULL,&len);
468 clGetProgramInfo(temp,CL_PROGRAM_BINARIES,len,&binaries[0],NULL);
469
470 std::string prefix;
471 for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
472 prefix += it->name() + it->vendor() + it->driver_version();
473 std::string sha1 = tools::sha1(prefix + source);
474 std::ofstream cached((cache_path_+sha1).c_str(),std::ios::binary);
475
476 cached.write((char*)&sizes[0], sizeof(vcl_size_t));
477 cached.write((char*)binaries[0], std::streamsize(sizes[0]));
478
479 for (vcl_size_t i = 0; i < devices_.size(); ++i)
480 delete[] binaries[i];
481
482 VIENNACL_ERR_CHECK(err);
483 }
484
485
486 programs_.push_back(tools::shared_ptr<ocl::program>(new ocl::program(temp, *this, prog_name)));
487
488 viennacl::ocl::program & prog = *programs_.back();
489
490 //
491 // Extract kernels
492 //
493 cl_kernel kernels[1024];
494 cl_uint num_kernels_in_prog;
495 err = clCreateKernelsInProgram(prog.handle().get(), 1024, kernels, &num_kernels_in_prog);
496 VIENNACL_ERR_CHECK(err);
497
498 for (cl_uint i=0; i<num_kernels_in_prog; ++i)
499 {
500 char kernel_name[128];
501 err = clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, 128, kernel_name, NULL);
502 prog.add_kernel(kernels[i], std::string(kernel_name));
503 }
504
505 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
506 std::cout << "ViennaCL: Stored program '" << programs_.back()->name() << "' in context " << h_ << std::endl;
507 std::cout << "ViennaCL: There is/are " << programs_.size() << " program(s)" << std::endl;
508 #endif
509
510 return prog;
511 }
512
514 void delete_program(std::string const & name)
515 {
516 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
517 std::cout << "ViennaCL: Deleting program '" << name << "' from context " << h_ << std::endl;
518 #endif
519 for (program_container_type::iterator it = programs_.begin();
520 it != programs_.end();
521 ++it)
522 {
523 if ((*it)->name() == name)
524 {
525 programs_.erase(it);
526 return;
527 }
528 }
529 }
530
532 viennacl::ocl::program & get_program(std::string const & name)
533 {
534 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
535 std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
536 std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
537 #endif
538 for (program_container_type::iterator it = programs_.begin();
539 it != programs_.end();
540 ++it)
541 {
542 //std::cout << "Name: " << (*it)->name() << std::endl;
543 if ((*it)->name() == name)
544 return **it;
545 }
546 std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
547 throw program_not_found(name);
548 //return programs_[0]; //return a defined object
549 }
550
551 viennacl::ocl::program const & get_program(std::string const & name) const
552 {
553 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
554 std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
555 std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
556 #endif
557 for (program_container_type::const_iterator it = programs_.begin();
558 it != programs_.end();
559 ++it)
560 {
561 //std::cout << "Name: " << (*it)->name() << std::endl;
562 if ((*it)->name() == name)
563 return **it;
564 }
565 std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
566 throw program_not_found(name);
567 //return programs_[0]; //return a defined object
568 }
569
571 bool has_program(std::string const & name)
572 {
573 for (program_container_type::iterator it = programs_.begin();
574 it != programs_.end();
575 ++it)
576 {
577 if ((*it)->name() == name) return true;
578 }
579 return false;
580 }
581
583 viennacl::ocl::program & get_program(vcl_size_t id)
584 {
585 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
586 std::cout << "ViennaCL: Getting program '" << id << "' from context " << h_ << std::endl;
587 std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
588 #endif
589
590 if (id >= programs_.size())
591 throw invalid_program();
592
593 return *programs_[id];
594 }
595
596 program_container_type get_programs()
597 {
598 return programs_;
599 }
600
602 vcl_size_t program_num() { return programs_.size(); }
603
605 viennacl::ocl::kernel & get_kernel(std::string const & program_name, std::string const & kernel_name) { return get_program(program_name).get_kernel(kernel_name); }
606
608 vcl_size_t device_num() { return devices_.size(); }
609
611 const viennacl::ocl::handle<cl_context> & handle() const { return h_; }
612
614 std::string build_options() const { return build_options_; }
615
617 void build_options(std::string op) { build_options_ = op; }
618
620 vcl_size_t platform_index() const { return pf_index_; }
621
623 void platform_index(vcl_size_t new_index)
624 {
625 assert(!initialized_ && bool("Platform ID must be set before context is initialized!"));
626 pf_index_ = new_index;
627 }
628
630 bool operator<(context const & other) const
631 {
632 return h_.get() < other.h_.get();
633 }
634
635 bool operator==(context const & other) const
636 {
637 return h_.get() == other.h_.get();
638 }
639
640 private:
642 void init_new()
643 {
644 assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
645
646 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
647 std::cout << "ViennaCL: Initializing new ViennaCL context." << std::endl;
648 #endif
649
650 cl_int err;
651 std::vector<cl_device_id> device_id_array;
652 if (devices_.empty()) //get the default device if user has not yet specified a list of devices
653 {
654 //create an OpenCL context for the provided devices:
655 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
656 std::cout << "ViennaCL: Setting all devices for context..." << std::endl;
657 #endif
658
659 platform pf(pf_index_);
660 std::vector<device> devices = pf.devices(device_type_);
661 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
662 std::cout << "ViennaCL: Number of devices for context: " << devices.size() << std::endl;
663 #endif
664 vcl_size_t device_num = std::min<vcl_size_t>(default_device_num_, devices.size());
665 for (vcl_size_t i=0; i<device_num; ++i)
666 devices_.push_back(devices[i]);
667
668 if (devices.size() == 0)
669 {
670 std::cerr << "ViennaCL: FATAL ERROR: No devices of type '";
671 switch (device_type_)
672 {
673 case CL_DEVICE_TYPE_CPU: std::cout << "CPU"; break;
674 case CL_DEVICE_TYPE_GPU: std::cout << "GPU"; break;
675 case CL_DEVICE_TYPE_ACCELERATOR: std::cout << "ACCELERATOR"; break;
676 case CL_DEVICE_TYPE_DEFAULT: std::cout << "DEFAULT"; break;
677 default:
678 std::cout << "UNKNOWN" << std::endl;
679 }
680 std::cout << "' found!" << std::endl;
681 }
682 }
683
684 //extract list of device ids:
685 for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
686 iter != devices_.end();
687 ++iter)
688 device_id_array.push_back(iter->id());
689
690 h_ = clCreateContext(0,
691 static_cast<cl_uint>(devices_.size()),
692 &(device_id_array[0]),
693 NULL, NULL, &err);
694 VIENNACL_ERR_CHECK(err);
695
696 initialized_ = true;
697 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
698 std::cout << "ViennaCL: Initialization of new ViennaCL context done." << std::endl;
699 #endif
700 }
701
703 void init_existing(cl_context c)
704 {
705 assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
706 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
707 std::cout << "ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
708 #endif
709
710 //set context handle:
711 h_ = c;
712 h_.inc(); // if the user provides the context, then the user will also call release() on the context. Without inc(), we would get a seg-fault due to double-free at program termination.
713
714 if (devices_.empty())
715 {
716 //get devices for context:
717 cl_int err;
718 cl_uint num_devices;
719 vcl_size_t temp;
720 //Note: The obvious
721 // err = clGetContextInfo(h_, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL);
722 //does not work with NVIDIA OpenCL stack!
723 err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, VIENNACL_OCL_MAX_DEVICE_NUM * sizeof(cl_device_id), NULL, &temp);
724 VIENNACL_ERR_CHECK(err);
725 assert(temp > 0 && bool("ViennaCL: FATAL error: Provided context does not contain any devices!"));
726 num_devices = static_cast<cl_uint>(temp / sizeof(cl_device_id));
727
728 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
729 std::cout << "ViennaCL: Reusing context with " << num_devices << " devices." << std::endl;
730 #endif
731
732 std::vector<cl_device_id> device_ids(num_devices);
733 err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, num_devices * sizeof(cl_device_id), &(device_ids[0]), NULL);
734 VIENNACL_ERR_CHECK(err);
735
736 for (vcl_size_t i=0; i<num_devices; ++i)
737 devices_.push_back(viennacl::ocl::device(device_ids[i]));
738 }
739 current_device_id_ = 0;
740
741 initialized_ = true;
742 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
743 std::cout << "ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
744 #endif
745 }
746
747
748 bool initialized_;
749 std::string cache_path_;
750 cl_device_type device_type_;
751 viennacl::ocl::handle<cl_context> h_;
752 std::vector< viennacl::ocl::device > devices_;
753 vcl_size_t current_device_id_;
754 vcl_size_t default_device_num_;
755 program_container_type programs_;
756 std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
757 std::string build_options_;
758 vcl_size_t pf_index_;
759 vcl_size_t current_queue_id_;
760 }; //context
761
762
763
765 inline viennacl::ocl::kernel & viennacl::ocl::program::add_kernel(cl_kernel kernel_handle, std::string const & kernel_name)
766 {
767 assert(p_context_ != NULL && bool("Pointer to context invalid in viennacl::ocl::program object"));
768 kernels_.push_back(tools::shared_ptr<ocl::kernel>(new ocl::kernel(kernel_handle, *this, *p_context_, kernel_name)));
769 return *kernels_.back();
770 }
771
773 inline viennacl::ocl::kernel & viennacl::ocl::program::get_kernel(std::string const & name)
774 {
775 //std::cout << "Requiring kernel " << name << " from program " << name_ << std::endl;
776 for (kernel_container_type::iterator it = kernels_.begin();
777 it != kernels_.end();
778 ++it)
779 {
780 if ((*it)->name() == name)
781 return **it;
782 }
783 std::cerr << "ViennaCL: FATAL ERROR: Could not find kernel '" << name << "' from program '" << name_ << "'" << std::endl;
784 std::cout << "Number of kernels in program: " << kernels_.size() << std::endl;
785 throw kernel_not_found("Kernel not found");
786 //return kernels_[0]; //return a defined object
787 }
788
789
790 inline void viennacl::ocl::kernel::set_work_size_defaults()
791 {
792 assert( p_program_ != NULL && bool("Kernel not initialized, program pointer invalid."));
793 assert( p_context_ != NULL && bool("Kernel not initialized, context pointer invalid."));
794
795 if ( (p_context_->current_device().type() == CL_DEVICE_TYPE_GPU)
796 || (p_context_->current_device().type() == CL_DEVICE_TYPE_ACCELERATOR) // Xeon Phi
797 )
798 {
799 local_work_size_[0] = 128; local_work_size_[1] = 0; local_work_size_[2] = 0;
800 global_work_size_[0] = 128*128; global_work_size_[1] = 0; global_work_size_[2] = 0;
801 }
802 else //assume CPU type:
803 {
804 //conservative assumption: one thread per CPU core:
805 local_work_size_[0] = 1; local_work_size_[1] = 0; local_work_size_[2] = 0;
806
807 size_type units = p_context_->current_device().max_compute_units();
808 size_type s = 1;
809
810 while (s < units) // find next power of 2. Important to make reductions work on e.g. six-core CPUs.
811 s *= 2;
812
813 global_work_size_[0] = s * local_work_size_[0]; global_work_size_[1] = 0; global_work_size_[2] = 0;
814 }
815 }
816
817 }
818 }
819
820 #endif
viennacl::ocl::context::current_device
viennacl::ocl::device const & current_device() const
Returns the current device.
Definition: context.hpp:112
forwards.h
This file provides the forward declarations for the OpenCL layer of ViennaCL.
viennacl::ocl::context::switch_queue
void switch_queue(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:329
sha1.hpp
viennacl::ocl::program::add_kernel
viennacl::ocl::kernel & add_kernel(cl_kernel kernel_handle, std::string const &kernel_name)
Adds a kernel to the program.
Definition: context.hpp:765
viennacl::ocl::device::id
cl_device_id id() const
Returns the OpenCL device id.
Definition: device.hpp:981
viennacl::ocl::context::platform_index
void platform_index(vcl_size_t new_index)
Sets the platform ID of the platform to be used for the context.
Definition: context.hpp:623
viennacl::ocl::context::get_programs
program_container_type get_programs()
Definition: context.hpp:596
viennacl::ocl::context::create_memory_without_smart_handle
cl_mem create_memory_without_smart_handle(cl_mem_flags flags, unsigned int size, void *ptr=NULL) const
Creates a memory buffer within the context. Does not wrap the OpenCL handle into the smart-pointer-li...
Definition: context.hpp:196
device.hpp
Represents an OpenCL device within ViennaCL.
platform.hpp
Implements a OpenCL platform within ViennaCL.
viennacl::ocl::context::add_queue
void add_queue(cl_device_id dev)
Adds a queue for the given device to the context.
Definition: context.hpp:246
viennacl::ocl::context::default_device_type
void default_device_type(cl_device_type dtype)
Sets the device type for this context.
Definition: context.hpp:95
viennacl::ocl::platform
Wrapper class for an OpenCL platform.
Definition: platform.hpp:45
viennacl::ocl::context::build_options
std::string build_options() const
Returns the current build option string.
Definition: context.hpp:614
viennacl::ocl::context::switch_device
void switch_device(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:119
viennacl::ocl::context::get_queue
viennacl::ocl::command_queue & get_queue()
Definition: context.hpp:266
viennacl::ocl::kernel
Represents an OpenCL kernel within ViennaCL.
Definition: kernel.hpp:58
viennacl::ocl::context::get_program
viennacl::ocl::program & get_program(std::string const &name)
Returns the program with the provided name.
Definition: context.hpp:532
viennacl::ocl::queue_not_found
Definition: error.hpp:66
viennacl::ocl::context::build_options
void build_options(std::string op)
Sets the build option string, which is passed to the OpenCL compiler in subsequent compilations...
Definition: context.hpp:617
viennacl::ocl::context::operator==
bool operator==(context const &other) const
Definition: context.hpp:635
viennacl::ocl::program::handle
const viennacl::ocl::handle< cl_program > & handle() const
Definition: program.hpp:72
viennacl::ocl::context::delete_program
void delete_program(std::string const &name)
Delete the program with the provided name.
Definition: context.hpp:514
viennacl::ocl::context::default_device_type
cl_device_type default_device_type()
Returns the default device type for the context.
Definition: context.hpp:89
viennacl::ocl::context
Manages an OpenCL context and provides the respective convenience functions for creating buffers...
Definition: context.hpp:55
viennacl::ocl::device
A class representing a compute device (e.g. a GPU)
Definition: device.hpp:49
viennacl::ocl::program_not_found
Definition: error.hpp:72
viennacl::ocl::command_queue
A class representing a command queue.
Definition: command_queue.hpp:45
viennacl::ocl::context::context
context()
Definition: context.hpp:60
viennacl::ocl::context::program_num
vcl_size_t program_num()
Returns the number of programs within this context.
Definition: context.hpp:602
viennacl::ocl::context::platform_index
vcl_size_t platform_index() const
Returns the platform ID of the platform to be used for the context.
Definition: context.hpp:620
viennacl::ocl::context::handle
const viennacl::ocl::handle< cl_context > & handle() const
Returns the context handle.
Definition: context.hpp:611
viennacl::ocl::command_queue::handle
viennacl::ocl::handle< cl_command_queue > const & handle() const
Definition: command_queue.hpp:81
NumericT
float NumericT
Definition: bisect.cpp:40
command_queue.hpp
Implementations of command queue representations.
viennacl::ocl::context::default_device_num
vcl_size_t default_device_num() const
Returns the maximum number of devices to be set up for the context.
Definition: context.hpp:82
VIENNACL_ERR_CHECK
#define VIENNACL_ERR_CHECK(err)
Definition: error.hpp:681
shared_ptr.hpp
Implementation of a shared pointer class (cf. std::shared_ptr, boost::shared_ptr). Will be used until C++11 is widely available.
viennacl::ocl::context::init
void init()
Initializes a new context.
Definition: context.hpp:167
viennacl::ocl::context::add_program
viennacl::ocl::program & add_program(cl_program p, std::string const &prog_name)
Adds a program to the context.
Definition: context.hpp:368
viennacl::ocl::handle::get
const OCL_TYPE & get() const
Definition: handle.hpp:191
viennacl::traits::size
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:239
viennacl::ocl::context::operator<
bool operator<(context const &other) const
Less-than comparable for compatibility with std:map.
Definition: context.hpp:630
viennacl::ocl::invalid_program
Exception thrown if an OpenCL program object handle is invalid (e.g. not initialized).
Definition: error.hpp:353
viennacl::ocl::handle::inc
void inc()
Manually increment the OpenCL reference count. Typically called automatically, but is necessary if us...
Definition: handle.hpp:216
viennacl::ocl::context::init
void init(cl_context c)
Initializes the context from an existing, user-supplied context.
Definition: context.hpp:173
viennacl::ocl::context::get_kernel
viennacl::ocl::kernel & get_kernel(std::string const &program_name, std::string const &kernel_name)
Convenience function for retrieving the kernel of a program directly from the context.
Definition: context.hpp:605
program.hpp
Implements an OpenCL program class for ViennaCL.
viennacl::ocl::context::get_program
viennacl::ocl::program & get_program(vcl_size_t id)
Returns the program with the provided id.
Definition: context.hpp:583
viennacl::ocl::context::cache_path
std::string cache_path() const
Returns the compiled kernel cache path.
Definition: context.hpp:75
handle.hpp
Implementation of a smart-pointer-like class for handling OpenCL handles.
viennacl::ocl::context::add_queue
void add_queue(viennacl::ocl::device d)
Adds a queue for the given device to the context.
Definition: context.hpp:263
viennacl::tools::shared_ptr
A shared pointer class similar to boost::shared_ptr. Reimplemented in order to avoid a Boost-dependen...
Definition: shared_ptr.hpp:83
viennacl::ocl::context::add_device
void add_device(viennacl::ocl::device const &d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:146
viennacl::ocl::context::cache_path
void cache_path(std::string new_path)
Sets the compiled kernel cache path.
Definition: context.hpp:78
viennacl::vcl_size_t
std::size_t vcl_size_t
Definition: forwards.h:75
viennacl::ocl::program
Wrapper class for an OpenCL program.
Definition: program.hpp:42
viennacl::ocl::context::add_queue
void add_queue(cl_device_id dev, cl_command_queue q)
Adds an existing queue for the given device to the context.
Definition: context.hpp:235
viennacl::ocl::device::name
std::string name() const
Device name string.
Definition: device.hpp:566
viennacl::ocl::context::get_program
viennacl::ocl::program const & get_program(std::string const &name) const
Definition: context.hpp:551
viennacl::ocl::context::default_device_num
void default_device_num(vcl_size_t new_num)
Sets the maximum number of devices to be set up for the context.
Definition: context.hpp:85
viennacl::ocl::invalid_command_queue
Exception thrown if an invalid OpenCL command queue is provided to an OpenCL function.
Definition: error.hpp:273
error.hpp
Error handling for the OpenCL layer of ViennaCL.
viennacl::ocl::context::switch_queue
void switch_queue(viennacl::ocl::command_queue const &q)
If the supplied command_queue is used within the context, it becomes the current active command_queue...
Definition: context.hpp:336
viennacl::ocl::context::has_program
bool has_program(std::string const &name)
Returns whether the program with the provided name exists or not.
Definition: context.hpp:571
VIENNACL_OCL_MAX_DEVICE_NUM
#define VIENNACL_OCL_MAX_DEVICE_NUM
Definition: device_utils.hpp:25
kernel.hpp
Representation of an OpenCL kernel in ViennaCL.
viennacl::ocl::context::get_queue
viennacl::ocl::command_queue & get_queue(cl_device_id dev, vcl_size_t i=0)
Returns the queue with the provided index for the given device.
Definition: context.hpp:301
viennacl::tools::sha1
std::string sha1(std::string const &src)
Definition: sha1.hpp:220
viennacl::ocl::context::current_queue
viennacl::ocl::command_queue const & current_queue()
Returns the current device.
Definition: context.hpp:323
viennacl::ocl::kernel_not_found
Definition: error.hpp:78
viennacl::ocl::context::add_device
void add_device(cl_device_id d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:157
viennacl::ocl::program::get_kernel
viennacl::ocl::kernel & get_kernel(std::string const &name)
Returns the kernel with the provided name.
Definition: context.hpp:773
viennacl::ocl::context::devices
std::vector< viennacl::ocl::device > const & devices() const
Returns a vector with all devices in this context.
Definition: context.hpp:106
viennacl::ocl::context::device_num
vcl_size_t device_num()
Returns the number of devices within this context.
Definition: context.hpp:608
viennacl::ocl::context::switch_device
void switch_device(viennacl::ocl::device const &d)
If the supplied device is used within the context, it becomes the current active device.
Definition: context.hpp:126
viennacl::ocl::context::create_memory
viennacl::ocl::handle< cl_mem > create_memory(cl_mem_flags flags, const VectorType< NumericT, A > &buffer) const
Creates a memory buffer within the context initialized from the supplied data.
Definition: context.hpp:227
viennacl::ocl::handle< cl_mem >
viennacl::ocl::context::get_queue
viennacl::ocl::command_queue const & get_queue() const
Definition: context.hpp:276
viennacl::ocl::context::add_program
viennacl::ocl::program & add_program(std::string const &source, std::string const &prog_name)
Adds a new program with the provided source to the context. Compiles the program and extracts all ker...
Definition: context.hpp:379
viennacl::ocl::context::create_memory
viennacl::ocl::handle< cl_mem > create_memory(cl_mem_flags flags, unsigned int size, void *ptr=NULL) const
Creates a memory buffer within the context.
Definition: context.hpp:216