From e43f947adc12f02b5d5f84a9a4d4cce0d902580c Mon Sep 17 00:00:00 2001 From: MichaelHirn Date: Thu, 26 Nov 2015 18:14:58 +0100 Subject: [PATCH] feat/computation: add basic design for backend-agnostic computation Pull request: #2 Approved by: MichaelHirn --- src/backend.rs | 25 ++++++++++++ src/binary.rs | 14 +++---- src/device.rs | 1 + src/framework.rs | 6 +++ src/frameworks/native/binary.rs | 24 +++++++++++ src/frameworks/native/function.rs | 20 ++++++++++ src/frameworks/native/libraries/blas.rs | 20 ++++++++++ src/frameworks/native/libraries/mod.rs | 3 ++ src/frameworks/native/mod.rs | 19 ++++++++- src/frameworks/opencl/kernel.rs | 8 +--- src/frameworks/opencl/libraries/blas.rs | 21 ++++++++++ src/frameworks/opencl/libraries/mod.rs | 3 ++ src/frameworks/opencl/mod.rs | 12 ++++++ src/frameworks/opencl/program.rs | 42 ++++++++++++++++++++ src/libraries/blas.rs | 53 ++++++++++++++++++++----- src/operation.rs | 2 +- tests/backend_specs.rs | 19 +++++++++ 17 files changed, 263 insertions(+), 29 deletions(-) create mode 100644 src/frameworks/native/binary.rs create mode 100644 src/frameworks/native/function.rs create mode 100644 src/frameworks/native/libraries/blas.rs create mode 100644 src/frameworks/native/libraries/mod.rs create mode 100644 src/frameworks/opencl/libraries/blas.rs create mode 100644 src/frameworks/opencl/libraries/mod.rs create mode 100644 src/frameworks/opencl/program.rs diff --git a/src/backend.rs b/src/backend.rs index 98a6f6b3..dbf1ea3b 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -41,6 +41,10 @@ use framework::{IFramework, FrameworkError}; use device::IDevice; +use libraries::blas::IBlas; +use frameworks::{Native, OpenCL}; +use operation::IOperation; +use std::collections::HashMap; #[derive(Debug, Clone)] /// Defines the main and highest struct of Collenchyma. @@ -87,6 +91,27 @@ impl Backend { pub fn device(&self) -> F::D { self.device.clone() } + + /// Returns the blas binary. + pub fn binary(&self) -> F::B { + self.framework().binary().clone() + } +} + +impl IBlas for Backend { + type B = ::frameworks::opencl::Program; + + fn binary(&self) -> Self::B { + self.binary() + } +} + +impl IBlas for Backend { + type B = ::frameworks::native::Binary; + + fn binary(&self) -> Self::B { + self.binary() + } } #[derive(Debug, Clone)] diff --git a/src/binary.rs b/src/binary.rs index 6b7e086c..aff8e239 100644 --- a/src/binary.rs +++ b/src/binary.rs @@ -57,13 +57,9 @@ use std::collections::HashMap; /// Defines the functionality for turning a library into backend-specific, executable operations. pub trait IBinary { - /// The Operation representation for this Binary. - type O: IOperation; - /// The Library representation for this Binary. - type L: ILibrary; - /// Returns the unique identifier of the Binary. - fn id(&self) -> isize; - /// Creates a HashMap of available, ready-to-use operations, based on the provided library and - /// tailored for a framework. - fn create_operations() -> HashMap; + // Returns the unique identifier of the Binary. + //fn id(&self) -> isize; + // Creates a HashMap of available, ready-to-use operations, based on the provided library and + // tailored for a framework. + //fn create_operations(); } diff --git a/src/device.rs b/src/device.rs index 99640f90..1dbe8ee3 100644 --- a/src/device.rs +++ b/src/device.rs @@ -8,6 +8,7 @@ use hardware::IHardware; use memory::{IMemory, MemoryType}; +use operation::IOperation; use std::hash::{Hash, Hasher}; use frameworks::native::device::Cpu; use frameworks::opencl::context::Context; diff --git a/src/framework.rs b/src/framework.rs index c756667f..87368bf5 100644 --- a/src/framework.rs +++ b/src/framework.rs @@ -20,6 +20,7 @@ use hardware::IHardware; use device::IDevice; +use binary::IBinary; use frameworks::opencl::Error as OpenCLError; use std::error; use std::fmt; @@ -30,6 +31,8 @@ pub trait IFramework { type H: IHardware; /// The Device representation for this Framework. type D: IDevice + Clone; + /// The Binary representation for this Framework. + type B: IBinary + Clone; /// Defines the Framework by a Name. /// @@ -48,6 +51,9 @@ pub trait IFramework { /// Returns the cached and available hardwares. fn hardwares(&self) -> Vec; + /// Returns the initialized binary. + fn binary(&self) -> Self::B; + /// Initializes a new Device from the provided hardwares. fn new_device(&self, Vec) -> Result; } diff --git a/src/frameworks/native/binary.rs b/src/frameworks/native/binary.rs new file mode 100644 index 00000000..c9baec98 --- /dev/null +++ b/src/frameworks/native/binary.rs @@ -0,0 +1,24 @@ +//! Provides a binary on native CPU. + +use binary::IBinary; +use frameworks::native::Function; + +#[derive(Debug, Copy, Clone)] +/// Defines a host CPU binary. +pub struct Binary { + id: isize, + /// The initialized Blas Dot Operation. + pub blas_dot: Function, +} + +impl Binary { + /// Initializes a native CPU hardware. + pub fn new(id: isize) -> Binary { + Binary { + id: id, + blas_dot: Function::new(1) + } + } +} + +impl IBinary for Binary {} diff --git a/src/frameworks/native/function.rs b/src/frameworks/native/function.rs new file mode 100644 index 00000000..3c648bd2 --- /dev/null +++ b/src/frameworks/native/function.rs @@ -0,0 +1,20 @@ +//! Provides a operation on native CPU. + +use hardware::{IHardware, HardwareType}; +use operation::IOperation; +use shared_memory::SharedMemory; + +#[derive(Debug, Copy, Clone)] +/// Defines a host CPU operation. +pub struct Function { + id: isize, +} + +impl Function { + /// Initializes a native CPU hardware. + pub fn new(id: isize) -> Function { + Function { id: id } + } +} + +impl IOperation for Function {} diff --git a/src/frameworks/native/libraries/blas.rs b/src/frameworks/native/libraries/blas.rs new file mode 100644 index 00000000..8aff9602 --- /dev/null +++ b/src/frameworks/native/libraries/blas.rs @@ -0,0 +1,20 @@ +//! Provides BLAS for a Native backend. + +use frameworks::Native; +use frameworks::native::{Function, Binary}; +use binary::IBinary; +use libraries::blas::*; + +impl IBlasBinary for Binary { + type Dot = Function; + + fn dot(&self) -> Self::Dot { + self.blas_dot + } +} + +impl IOperationDot for Function { + fn compute(&self, a: i32) { + println!("{}", format!("NATIVE")) + } +} diff --git a/src/frameworks/native/libraries/mod.rs b/src/frameworks/native/libraries/mod.rs new file mode 100644 index 00000000..31e04061 --- /dev/null +++ b/src/frameworks/native/libraries/mod.rs @@ -0,0 +1,3 @@ +//! Provides support for various libraries for a Native backend. + +mod blas; diff --git a/src/frameworks/native/mod.rs b/src/frameworks/native/mod.rs index 9957a98d..77af1821 100644 --- a/src/frameworks/native/mod.rs +++ b/src/frameworks/native/mod.rs @@ -9,17 +9,23 @@ use hardware::{HardwareType, IHardware}; use device::IDevice; use self::hardware::Hardware; pub use self::device::Cpu; +pub use self::function::Function; +pub use self::binary::Binary; pub mod device; pub mod flatbox; pub mod hardware; +pub mod function; +pub mod libraries; +pub mod binary; #[derive(Debug, Clone)] /// Provides the Native framework. /// /// Native means host CPU only. The setup one relies on by default. pub struct Native { - hardwares: Vec + hardwares: Vec, + binary: Binary, } /// Provides the Native framework trait for explicit Backend behaviour. @@ -32,11 +38,16 @@ impl INative for Native {} impl IFramework for Native { type H = Hardware; type D = Cpu; + type B = Binary; + const ID: &'static str = "NATIVE"; fn new() -> Native { match Native::load_hardwares() { - Ok(hardwares) => Native { hardwares: hardwares }, + Ok(hardwares) => Native { + hardwares: hardwares, + binary: Binary::new(1) + }, Err(err) => panic!(err) } } @@ -54,6 +65,10 @@ impl IFramework for Native { self.hardwares.clone() } + fn binary(&self) -> Binary { + self.binary.clone() + } + fn new_device(&self, devices: Vec) -> Result { Ok(Cpu::new(devices.to_vec())) } diff --git a/src/frameworks/opencl/kernel.rs b/src/frameworks/opencl/kernel.rs index fd0b0d07..98e80be7 100644 --- a/src/frameworks/opencl/kernel.rs +++ b/src/frameworks/opencl/kernel.rs @@ -5,7 +5,7 @@ use frameworks::opencl::OpenCL; use super::api::types as cl; use super::api::API; -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] /// Defines a OpenCL Kernel. /// /// A Kernel is OpenCL's version of Collenchyma's [operation][operation]. @@ -31,8 +31,4 @@ impl Kernel { } } -impl IOperation for Kernel { - fn id(&self) -> isize { - self.id - } -} +impl IOperation for Kernel {} diff --git a/src/frameworks/opencl/libraries/blas.rs b/src/frameworks/opencl/libraries/blas.rs new file mode 100644 index 00000000..744c0192 --- /dev/null +++ b/src/frameworks/opencl/libraries/blas.rs @@ -0,0 +1,21 @@ +//! Provides BLAS for a OpenCL backend. + +use frameworks::OpenCL; +use frameworks::opencl::Kernel; +use frameworks::opencl::Program; +use binary::IBinary; +use libraries::blas::*; + +impl IBlasBinary for Program { + type Dot = Kernel; + + fn dot(&self) -> Self::Dot { + self.blas_dot + } +} + +impl IOperationDot for Kernel { + fn compute(&self, a: i32) { + println!("{}", format!("OPENCL")) + } +} diff --git a/src/frameworks/opencl/libraries/mod.rs b/src/frameworks/opencl/libraries/mod.rs new file mode 100644 index 00000000..e47fd3ef --- /dev/null +++ b/src/frameworks/opencl/libraries/mod.rs @@ -0,0 +1,3 @@ +//! Provides support for various libraries for a OpenCL backend. + +mod blas; diff --git a/src/frameworks/opencl/mod.rs b/src/frameworks/opencl/mod.rs index 6d2fd8d2..182a2989 100644 --- a/src/frameworks/opencl/mod.rs +++ b/src/frameworks/opencl/mod.rs @@ -17,6 +17,8 @@ pub use self::platform::Platform; pub use self::context::Context; pub use self::memory::Memory; pub use self::queue::Queue; +pub use self::kernel::Kernel; +pub use self::program::Program; pub use self::device::{Device, DeviceInfo}; pub use self::api::{API, Error}; use self::api::types as cl; @@ -26,12 +28,16 @@ pub mod platform; pub mod context; pub mod memory; pub mod queue; +pub mod kernel; +pub mod program; +pub mod libraries; mod api; #[derive(Debug, Clone)] /// Provides the OpenCL Framework. pub struct OpenCL { hardwares: Vec, + binary: Program, } /// Provides the OpenCL framework trait for explicit Backend behaviour. @@ -44,6 +50,7 @@ impl IOpenCL for OpenCL {} impl IFramework for OpenCL { type H = Device; type D = Context; + type B = Program; const ID: &'static str = "OPENCL"; fn new() -> OpenCL { @@ -51,6 +58,7 @@ impl IFramework for OpenCL { Ok(hardwares) => { OpenCL { hardwares: hardwares, + binary: Program::from_isize(1) } }, Err(err) => panic!(err) @@ -77,6 +85,10 @@ impl IFramework for OpenCL { self.hardwares.clone() } + fn binary(&self) -> Self::B { + self.binary.clone() + } + /// Creates a new OpenCL context over one or many devices ready for computation. /// /// Contexts are used by the OpenCL runtime for managing objects such as command-queues, diff --git a/src/frameworks/opencl/program.rs b/src/frameworks/opencl/program.rs new file mode 100644 index 00000000..2c9e9e03 --- /dev/null +++ b/src/frameworks/opencl/program.rs @@ -0,0 +1,42 @@ +//! Provides a Rust wrapper around OpenCL's Program. + +use binary::IBinary; +use frameworks::opencl::{OpenCL, Kernel}; +use super::api::types as cl; +use super::api::API; + +#[derive(Debug, Copy, Clone)] +/// Defines a OpenCL Program. +/// +/// A Program is OpenCL's version of Collenchyma's [binary][binary]. +/// [binary]: ../../binary/index.html +pub struct Program { + id: isize, + /// The initialized BLAS dot Operation. + pub blas_dot: Kernel +} + +impl Program { + /// Initializes a new OpenCL device. + pub fn from_isize(id: isize) -> Program { + Program { + id: id, + blas_dot: Kernel::from_isize(1) + } + } + + /// Initializes a new OpenCL device from its C type. + pub fn from_c(id: cl::kernel_id) -> Program { + unsafe { Program { + id: id as isize, + blas_dot: Kernel::from_isize(1) + } } + } + + /// Returns the id as its C type. + pub fn id_c(&self) -> cl::kernel_id { + self.id as cl::kernel_id + } +} + +impl IBinary for Program {} diff --git a/src/libraries/blas.rs b/src/libraries/blas.rs index 9856585d..6571d496 100644 --- a/src/libraries/blas.rs +++ b/src/libraries/blas.rs @@ -4,22 +4,53 @@ use backend::Backend; use hardware::IHardware; use device::IDevice; use framework::IFramework; +use operation::IOperation; +use binary::IBinary; use frameworks::Native; +use frameworks::OpenCL; use shared_memory::SharedMemory; use blas::Vector; -#[derive(Debug, Copy, Clone)] -/// Blas -pub struct Blas; +/// Provides the functionality for a backend for Basic Linear Algebra Subprograms. +/// +/// BLAS (Basic Linear Algebra Subprograms) is a specification that prescribes a set of low-level +/// routines for performing common linear algebra operations such as vector addition, scalar +/// multiplication, dot products, linear combinations, and matrix multiplication. They are the de +/// facto standard low-level routines for linear algebra libraries; the routines have bindings for +/// both C and Fortran. Although the BLAS specification is general, BLAS implementations are often +/// optimized for speed on a particular machine, so using them can bring substantial performance +/// benefits. BLAS implementations will take advantage of special floating point hardware such as +/// vector registers or SIMD instructions.
+/// [Source][blas-source] +/// +/// [blas-source]: https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms +pub trait IBlas { + /// The Binary representation for this Library. + type B: IBlasBinary + IBinary; -/// Addition -pub trait Plus { - /// plus - fn plus(self, a: SharedMemory, b: SharedMemory, c: &mut SharedMemory); + /// Level 1 operation + fn dot(&self, a: i32) { + // check if operation is provided; + // create_mem; + // sync_mem; + self.binary().dot().compute(2) + } + + /// Returns the binary representation + fn binary(&self) -> Self::B; } -impl Plus for Backend { - fn plus(self, a: SharedMemory, b: SharedMemory, c: &mut SharedMemory) { - self.framework().plus(a, b, c) - } +/// Describes the operation binding for a Blas Binary implementation. +pub trait IBlasBinary { + /// Describes the Dot Operation. + type Dot: IOperationDot; + + /// Returns an initialized Dot operation. + fn dot(&self) -> Self::Dot; +} + +/// Describes a Dot Operation. +pub trait IOperationDot { + /// Computes the Dot operation. + fn compute(&self, a: i32); } diff --git a/src/operation.rs b/src/operation.rs index bbc08455..b40a2152 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -38,4 +38,4 @@ //! [program]: ../program/index.html /// Defines the functionality of an operation. -pub trait IOperation { } +pub trait IOperation {} diff --git a/tests/backend_specs.rs b/tests/backend_specs.rs index 37679668..5dd08cbf 100644 --- a/tests/backend_specs.rs +++ b/tests/backend_specs.rs @@ -6,6 +6,7 @@ mod backend_spec { use co::backend::{Backend, BackendConfig}; use co::frameworks::{OpenCL, Native}; + use co::libraries::blas::*; use co::framework::*; #[test] @@ -16,4 +17,22 @@ mod backend_spec { let backend = Backend::new(backend_config); println!("{:?}", backend); } + + #[test] + fn it_computes_on_native() { + let framework = Native::new(); + let hardwares = framework.hardwares(); + let backend_config = BackendConfig::new(framework, hardwares); + let backend = Backend::new(backend_config).unwrap(); + backend.dot(2); + } + + #[test] + fn it_computes_on_opencl() { + let framework = OpenCL::new(); + let hardwares = framework.hardwares(); + let backend_config = BackendConfig::new(framework, hardwares); + let backend = Backend::new(backend_config).unwrap(); + backend.dot(2); + } }