1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
//! Provides the interface for running parallel computations on one ore many devices. //! //! This is the abstraction over which you are interacting with your devices. You can create a //! backend for computation by first choosing a specifc [Framework][frameworks] such as OpenCL and //! afterwards selecting one or many available hardwares to create a backend. //! //! A backend provides you with the functionality of managing the memory of the devices and copying //! your objects from host to devices and the other way around. Additionally you can execute //! operations in parallel through kernel functions on the device(s) of the backend. //! //! ## Architecture //! //! The initialization of a backend happens through the BackendConfig, which defines which //! [framework][framework] should be used and which [programs][program] should be available for //! parallel execution. //! //! [frameworks]: ../frameworks/index.html //! [framework]: ../framework/index.html //! [program]: ../program/index.html //! //! ## Examples //! //! ``` //! extern crate collenchyma as co; //! use co::framework::*; //! use co::backend::{Backend, BackendConfig}; //! use co::frameworks::Native; //! #[allow(unused_variables)] //! fn main() { //! // Initialize a new Framewok. //! let framework = Native::new(); //! // After initialization, the available hardware through the Framework can be obtained. //! let hardwares = &framework.hardwares().to_vec(); //! // Create a Backend configuration with //! // - a Framework and //! // - the available hardwares you would like to use for computation (turn into a device). //! let backend_config = BackendConfig::new(framework, hardwares); //! // Create a ready to go backend from the configuration. //! let backend = Backend::new(backend_config); //! } //! ``` use error::Error; use framework::IFramework; use device::{IDevice, DeviceType}; #[derive(Debug, Clone)] /// Defines the main and highest struct of Collenchyma. pub struct Backend<F: IFramework> { /// Provides the Framework. /// /// The Framework implementation such as OpenCL, CUDA, etc. defines, which should be used and /// determines which hardwares will be available and how parallel kernel functions can be /// executed. /// /// Default: [Native][native] /// /// [native]: ../frameworks/native/index.html framework: Box<F>, /// Provides a device, created from one or many hardwares, which are ready to execute kernel /// methods and synchronize memory. device: DeviceType, } /// Defines the functionality of the Backend. impl<F: IFramework + Clone> Backend<F> { /// Initialize a new native Backend from a BackendConfig. pub fn new(config: BackendConfig<F>) -> Result<Backend<F>, Error> { let device = try!(config.framework.new_device(config.hardwares)); Ok( Backend { framework: Box::new(config.framework), device: device, } ) } /// Returns the available hardware. pub fn hardwares(&self) -> &[F::H] { self.framework.hardwares() } /// Returns the backend framework. pub fn framework(&self) -> &Box<F> { &self.framework } /// Returns the backend device. pub fn device(&self) -> &DeviceType { &self.device } } /// Describes a Backend. /// /// Serves as a marker trait and helps for extern implementation. pub trait IBackend { /// Represents the Framework of a Backend. type F: IFramework + Clone; /// Returns the backend device. fn device(&self) -> &DeviceType; /// Try to create a default backend. fn default() -> Result<Backend<Self::F>, Error> where Self: Sized { let hw_framework = Self::F::new(); let hardwares = hw_framework.hardwares(); let framework = Self::F::new(); // dirty dirty hack to get around borrowing let backend_config = BackendConfig::new(framework, hardwares); Backend::new(backend_config) } /// Synchronize backend. fn synchronize(&self) -> Result<(), ::framework::Error> { Ok(()) } } #[derive(Debug, Clone)] /// Provides Backend Configuration. /// /// Use it to initialize a new Backend. pub struct BackendConfig<'a, F: IFramework + 'a> { framework: F, hardwares: &'a [F::H], } impl<'a, F: IFramework + Clone> BackendConfig<'a, F> { /// Creates a new BackendConfig. pub fn new(framework: F, hardwares: &'a [F::H]) -> BackendConfig<'a, F> { BackendConfig { framework: framework.clone(), hardwares: hardwares, } } }