matrix_proxy_classes.hpp
Go to the documentation of this file.
1 /*!
2  * \brief Implements the dense matrix class for the gpu
3  *
4  * \author O. Krause
5  * \date 2016
6  *
7  *
8  * \par Copyright 1995-2015 Shark Development Team
9  *
10  * <BR><HR>
11  * This file is part of Shark.
12  * <http://image.diku.dk/shark/>
13  *
14  * Shark is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published
16  * by the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Shark is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 #ifndef REMORA_GPU_MATRIX_PROXY_CLASSES_HPP
29 #define REMORA_GPU_MATRIX_PROXY_CLASSES_HPP
30 
31 #include "../expression_types.hpp"
32 #include "../detail/traits.hpp"
33 #include <boost/compute/iterator/strided_iterator.hpp>
34 #include <boost/compute/iterator/buffer_iterator.hpp>
35 
36 namespace remora{
37 
38 namespace detail{
39 template<class Arg1, class Arg2, class T>
40 struct induced_matrix_adaptor_element{
41  typedef T result_type;
42  Arg1 arg1;
43  Arg2 arg2;
44  gpu::dense_matrix_storage<T, dense_tag> storage;
45 };
46 
47 template<class Arg1, class Arg2,class T>
48 boost::compute::detail::meta_kernel& operator<< (
49  boost::compute::detail::meta_kernel& k,
50  induced_matrix_adaptor_element<Arg1, Arg2, T> const& e
51 ){
52  return k<< k.get_buffer_identifier<T>(e.storage.buffer, boost::compute::memory_object::global_memory)
53  <<" [ "<<e.storage.offset <<"+("<<e.arg1 <<")*"<<e.storage.leading_dimension<<"+"<< "("<<e.arg2<<")"<<']';
54 }
55 }
56 
57 template<class T,class Orientation>
58 class dense_matrix_adaptor<T, Orientation, gpu_tag>: public matrix_expression<dense_matrix_adaptor<T,Orientation, gpu_tag>, gpu_tag > {
59  private:
60  template<class IndexExpr1, class IndexExpr2>
61  detail::induced_matrix_adaptor_element<IndexExpr1, IndexExpr2, T> get_element(
62  IndexExpr1 const& expr1,IndexExpr2 const& expr2,
63  row_major
64  )const{
65  return {expr1, expr2,m_storage};
66  }
67  template<class IndexExpr1, class IndexExpr2>
68  detail::induced_matrix_adaptor_element<IndexExpr2, IndexExpr1,T> get_element(
69  IndexExpr1 const& expr1,IndexExpr2 const& expr2,
70  column_major
71  )const{
72  return {expr2, expr1,m_storage};
73  }
74 public:
75  typedef std::size_t size_type;
76  typedef typename std::remove_const<T>::type value_type;
77  typedef value_type const& const_reference;
78  typedef T& reference;
79 
80  typedef matrix_reference<dense_matrix_adaptor> closure_type;
81  typedef matrix_reference<dense_matrix_adaptor const> const_closure_type;
82  typedef gpu::dense_matrix_storage<T, dense_tag> storage_type;
83  typedef gpu::dense_matrix_storage<value_type const, dense_tag> const_storage_type;
84  typedef Orientation orientation;
85  typedef elementwise<dense_tag> evaluation_category;
86 
87  // Construction and destruction
88 
89  dense_matrix_adaptor(dense_matrix_adaptor<value_type, Orientation> const& expression)
90  : m_storage(expression.m_storage)
91  , m_queue(expression.m_queue)
92  , m_size1(expression.size1())
93  , m_size2(expression.size2())
94  {}
95 
96  /// \brief Constructor of a vector proxy from a block of memory
97  /// \param values the block of memory used
98  /// \param size1 size in 1st direction
99  /// \param size2 size in 2nd direction
100  /// \param stride1 distance in 1st direction between elements of the dense_matrix_adaptor in memory
101  /// \param stride2 distance in 2nd direction between elements of the dense_matrix_adaptor in memory
102  dense_matrix_adaptor(
103  storage_type storage,
104  boost::compute::command_queue& queue,
105  size_type size1, size_type size2
106  )
107  : m_storage(storage)
108  , m_queue(&queue)
109  , m_size1(size1)
110  , m_size2(size2){}
111 
112  template<class E>
113  dense_matrix_adaptor(vector_expression<E, gpu_tag> const& expression, std::size_t size1, std::size_t size2)
114  : m_queue(&expression().queue())
115  , m_size1(size1)
116  , m_size2(size2){
117  auto storage = expression().raw_storage();
118  m_storage.buffer = storage.buffer;
119  m_storage.offset = storage.offset;
120  m_storage.leading_dimension = orientation::index_m(size1, size2);
121  REMORA_RANGE_CHECK(storage.stride == 1);
122  }
123 
124  template<class E>
125  dense_matrix_adaptor(vector_expression<E, gpu_tag>& expression, std::size_t size1, std::size_t size2)
126  : m_queue(&expression().queue())
127  , m_size1(size1)
128  , m_size2(size2){
129  auto storage = expression().raw_storage();
130  m_storage.buffer = storage.buffer;
131  m_storage.offset = storage.offset;
132  m_storage.leading_dimension = orientation::index_m(size1, size2);
133  REMORA_RANGE_CHECK(storage.stride == 1);
134  }
135 
136 
137  // -------------------
138  // Assignment operators
139  // -------------------
140 
141  dense_matrix_adaptor& operator = (dense_matrix_adaptor const& e) {
142  REMORA_SIZE_CHECK(size1() == e().size1());
143  REMORA_SIZE_CHECK(size2() == e().size2());
144  return assign(*this, typename matrix_temporary<dense_matrix_adaptor>::type(e));
145  }
146  template<class E>
147  dense_matrix_adaptor& operator = (matrix_expression<E, gpu_tag> const& e) {
148  REMORA_SIZE_CHECK(size1() == e().size1());
149  REMORA_SIZE_CHECK(size2() == e().size2());
150  return assign(*this, typename matrix_temporary<dense_matrix_adaptor>::type(e));
151  }
152 
153  // ---------
154  // Storage interface
155  // ---------
156 
157  ///\brief Returns the number of rows of the matrix.
158  size_type size1() const {
159  return m_size1;
160  }
161  ///\brief Returns the number of columns of the matrix.
162  size_type size2() const {
163  return m_size2;
164  }
165 
166  boost::compute::command_queue& queue() const{
167  return *m_queue;
168  }
169  ///\brief Returns the underlying storage structure for low level access
170  storage_type raw_storage(){
171  return {m_storage.buffer, m_storage.offset, m_storage.leading_dimension};
172  }
173 
174  ///\brief Returns the underlying storage structure for low level access
175  const_storage_type raw_storage() const{
176  return {m_storage.buffer, m_storage.offset, m_storage.leading_dimension};
177  }
178 
179  // Element access
180  template <class IndexExpr1, class IndexExpr2>
181  auto operator()(IndexExpr1 const& i, IndexExpr2 const& j) const -> decltype(std::declval<dense_matrix_adaptor const&>().get_element(i,j,orientation())){
182  return this->get_element(i,j,orientation());
183  }
184 
185  // Iterator types
186  typedef boost::compute::strided_iterator<boost::compute::buffer_iterator<T> > row_iterator;
187  typedef boost::compute::strided_iterator<boost::compute::buffer_iterator<T> > column_iterator;
188  typedef boost::compute::strided_iterator<boost::compute::buffer_iterator<T const> > const_row_iterator;
189  typedef boost::compute::strided_iterator<boost::compute::buffer_iterator<T const> > const_column_iterator;
190 
191  const_row_iterator row_begin(size_type i) const {
192  return {buffer_begin() + i * stride1(), stride2()};
193  }
194  const_row_iterator row_end(size_type i) const {
195  return {buffer_begin() + i * stride1()+size2()*stride2(), stride2()};
196  }
197 
198  const_row_iterator column_begin(size_type j) const {
199  return {buffer_begin() + j * stride2(), stride1()};
200  }
201  const_column_iterator column_end(size_type j) const {
202  return {buffer_begin() + j * stride2()+size1()*stride1(), stride1()};
203  }
204 
205  row_iterator row_begin(size_type i){
206  return {buffer_begin() + i * stride1(), stride2()};
207  }
208  row_iterator row_end(size_type i){
209  return {buffer_begin() + i * stride1()+size2()*stride2(), stride2()};
210  }
211 
212  row_iterator column_begin(size_type j){
213  return {buffer_begin() + j * stride2(), stride1()};
214  }
215  column_iterator column_end(size_type j){
216  return {buffer_begin() + j * stride2()+size1()*stride1(), stride1()};
217  }
218 
219 private:
220  boost::compute::buffer_iterator<T const> buffer_begin()const{
221  return boost::compute::buffer_iterator<T>(m_storage.buffer, m_storage.offset);
222  }
223 
224  boost::compute::buffer_iterator<T> buffer_begin(){
225  return boost::compute::buffer_iterator<T>(m_storage.buffer, m_storage.offset);
226  }
227 
228  std::ptrdiff_t stride1() const {
229  return (std::ptrdiff_t) orientation::stride1(std::size_t(1), m_storage.leading_dimension);
230  }
231  std::ptrdiff_t stride2() const {
232  return (std::ptrdiff_t) orientation::stride2(std::size_t(1), m_storage.leading_dimension);
233  }
234 
235  storage_type m_storage;
236  boost::compute::command_queue* m_queue;
237  size_type m_size1;
238  size_type m_size2;
239 };
240 
241 }
242 
243 #endif