<T>LAPACK 0.1.1
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
MatrixEntry.hpp
Go to the documentation of this file.
1
3//
4// Copyright (c) 2021-2023, University of Colorado Denver. All rights reserved.
5//
6// This file is part of <T>LAPACK.
7// <T>LAPACK is free software: you can redistribute it and/or modify it under
8// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
9
10#ifndef TLAPACK_STARPU_MATRIXENTRY_HH
11#define TLAPACK_STARPU_MATRIXENTRY_HH
12
13#include <starpu.h>
14
15#include <tuple>
16
19
20namespace tlapack {
21namespace starpu {
22
23 namespace internal {
24
25 enum class Operation : int {
26 Assign = 0,
27 Add = 1,
28 Subtract = 2,
29 Multiply = 3,
30 Divide = 4
31 };
32
35 {
38 return {};
39 }
40
48 template <class T, class U, internal::Operation op>
49 constexpr void data_op_data(void** buffers, void* args) noexcept
50 {
51 T& x = *((T*)STARPU_VARIABLE_GET_PTR(buffers[0]));
52 const U& y = *((U*)STARPU_VARIABLE_GET_PTR(buffers[1]));
53
54 if constexpr (op == internal::Operation::Assign)
55 x = y;
56 else if constexpr (op == internal::Operation::Add)
57 x += y;
58 else if constexpr (op == internal::Operation::Subtract)
59 x -= y;
60 else if constexpr (op == internal::Operation::Multiply)
61 x *= y;
62 else if constexpr (op == internal::Operation::Divide)
63 x /= y;
64 }
65
73 template <class T, class U, internal::Operation op>
74 constexpr void data_op_value(void** buffers, void* args) noexcept
75 {
76 T& x = *((T*)STARPU_VARIABLE_GET_PTR(buffers[0]));
77 const U& y = *((U*)args);
78
79 if constexpr (op == internal::Operation::Assign)
80 x = y;
81 else if constexpr (op == internal::Operation::Add)
82 x += y;
83 else if constexpr (op == internal::Operation::Subtract)
84 x -= y;
85 else if constexpr (op == internal::Operation::Multiply)
86 x *= y;
87 else if constexpr (op == internal::Operation::Divide)
88 x /= y;
89 }
90
98 template <class T, internal::Operation op>
99 constexpr void matrixentry_op_matrixentry(void** buffers,
100 void* args) noexcept
101 {
102 using args_t = std::tuple<idx_t, idx_t, idx_t, idx_t>;
103
104 // get dimensions
105 const idx_t& ld = STARPU_MATRIX_GET_LD(buffers[0]);
106
107 // get arguments
108 const args_t& cl_args = *(args_t*)args;
109 const idx_t& i = std::get<0>(cl_args);
110 const idx_t& j = std::get<1>(cl_args);
111 const idx_t& k = std::get<2>(cl_args);
112 const idx_t& l = std::get<3>(cl_args);
113
114 // get entries
116 T& x = ((T*)A)[i + ld * j];
117 const T& y = ((T*)A)[k + ld * l];
118
119 // perform operation
120 if constexpr (op == internal::Operation::Assign)
121 x = y;
122 else if constexpr (op == internal::Operation::Add)
123 x += y;
124 else if constexpr (op == internal::Operation::Subtract)
125 x -= y;
126 else if constexpr (op == internal::Operation::Multiply)
127 x *= y;
128 else if constexpr (op == internal::Operation::Divide)
129 x /= y;
130 }
131
132 } // namespace internal
133
144 template <typename T>
145 struct MatrixEntry {
148 const idx_t pos[2];
149
152 const idx_t pos[2]) noexcept
153 : root_handle(root_handle), pos{pos[0], pos[1]}
154 {
155 struct starpu_data_filter f_var = {
157 .nchildren = 1,
159 .filter_arg_ptr = (void*)pos};
161 }
162
163 // Disable copy and move constructors, and copy assignment
164 MatrixEntry(MatrixEntry&&) = delete;
165 MatrixEntry(const MatrixEntry&) = delete;
166 MatrixEntry& operator=(const MatrixEntry&) = delete;
167
173
175 constexpr operator T() const noexcept
176 {
178 const T x = *((T*)starpu_variable_get_local_ptr(handle));
180
181 return x;
182 }
183
185 template <class U,
186 std::enable_if_t<std::is_same_v<real_type<U>, T>, int> = 0>
187 constexpr operator MatrixEntry<U>() const noexcept
188 {
190 const T x = *((T*)starpu_variable_get_local_ptr(handle));
192
193 return x;
194 }
195
196 // Arithmetic operators with assignment
197
198 template <class U>
199 constexpr MatrixEntry& operator=(MatrixEntry<U>&& x) noexcept
200 {
202 }
203 constexpr MatrixEntry& operator=(const T& x) noexcept
204 {
206 }
207
208 template <class U>
209 constexpr MatrixEntry& operator+=(const MatrixEntry<U>& x) noexcept
210 {
211 return operate_and_assign<internal::Operation::Add, U>(x);
212 }
213 constexpr MatrixEntry& operator+=(const T& x) noexcept
214 {
215 return operate_and_assign<internal::Operation::Add, T>(x);
216 }
217
218 template <class U>
219 constexpr MatrixEntry& operator-=(const MatrixEntry<U>& x) noexcept
220 {
221 return operate_and_assign<internal::Operation::Subtract, U>(x);
222 }
223 constexpr MatrixEntry& operator-=(const T& x) noexcept
224 {
225 return operate_and_assign<internal::Operation::Subtract, T>(x);
226 }
227
228 template <class U>
229 constexpr MatrixEntry& operator*=(const MatrixEntry<U>& x) noexcept
230 {
231 return operate_and_assign<internal::Operation::Multiply, U>(x);
232 }
233 constexpr MatrixEntry& operator*=(const T& x) noexcept
234 {
235 return operate_and_assign<internal::Operation::Multiply, T>(x);
236 }
237
238 template <class U>
239 constexpr MatrixEntry& operator/=(const MatrixEntry<U>& x) noexcept
240 {
241 return operate_and_assign<internal::Operation::Divide, U>(x);
242 }
243 constexpr MatrixEntry& operator/=(const T& x) noexcept
244 {
245 return operate_and_assign<internal::Operation::Divide, T>(x);
246 }
247
248 // Math functions to satisfy the concept Scalar
249
250 constexpr friend real_type<T> abs(const MatrixEntry& x) noexcept
251 {
252 return abs(T(x));
253 }
254
255 // Display value in ostream
256
257 constexpr friend std::ostream& operator<<(std::ostream& out,
258 const MatrixEntry& x)
259 {
260 return out << T(x);
261 }
262
263 private:
267 template <internal::Operation op, class U>
268 static constexpr struct starpu_codelet gen_cl_op_value() noexcept
269 {
270 using internal::Operation;
271 struct starpu_codelet cl = internal::codelet_init();
272
273 cl.cpu_funcs[0] = internal::data_op_value<T, U, op>;
274 cl.nbuffers = 1;
275 cl.modes[0] = (op == Operation::Assign) ? STARPU_W : STARPU_RW;
276 cl.name = (op == Operation::Assign)
277 ? "assign_value"
278 : (op == Operation::Add)
279 ? "add_value"
280 : (op == Operation::Subtract)
281 ? "subtract_value"
282 : (op == Operation::Multiply)
283 ? "multiply_value"
284 : (op == Operation::Divide)
285 ? "divide_value"
286 : "unknown";
287
288 // The following lines are needed to make the codelet const
289 // See _starpu_codelet_check_deprecated_fields() in StarPU:
290 cl.where |= STARPU_CPU;
291 cl.checked = 1;
292
293 return cl;
294 }
295
296 static constexpr const struct starpu_codelet cl_op_value[] = {
297 gen_cl_op_value<internal::Operation::Assign, T>(),
298 gen_cl_op_value<internal::Operation::Add, T>(),
299 gen_cl_op_value<internal::Operation::Subtract, T>(),
300 gen_cl_op_value<internal::Operation::Multiply, T>(),
301 gen_cl_op_value<internal::Operation::Divide, T>()};
302 static constexpr const struct starpu_codelet cl_op_rvalue[] = {
303 gen_cl_op_value<internal::Operation::Assign, real_type<T>>(),
304 gen_cl_op_value<internal::Operation::Add, real_type<T>>(),
305 gen_cl_op_value<internal::Operation::Subtract, real_type<T>>(),
306 gen_cl_op_value<internal::Operation::Multiply, real_type<T>>(),
307 gen_cl_op_value<internal::Operation::Divide, real_type<T>>()};
308
312 template <internal::Operation op, class U>
313 static constexpr struct starpu_codelet gen_cl_op_data() noexcept
314 {
315 using internal::Operation;
316 struct starpu_codelet cl = internal::codelet_init();
317
318 cl.cpu_funcs[0] = internal::data_op_data<T, U, op>;
319 cl.nbuffers = 2;
320 cl.modes[0] = (op == Operation::Assign) ? STARPU_W : STARPU_RW;
321 cl.modes[1] = STARPU_R;
322 cl.name = (op == Operation::Assign)
323 ? "assign_data"
324 : (op == Operation::Add)
325 ? "add_data"
326 : (op == Operation::Subtract)
327 ? "subtract_data"
328 : (op == Operation::Multiply)
329 ? "multiply_data"
330 : (op == Operation::Divide)
331 ? "divide_data"
332 : "unknown";
333
334 // The following lines are needed to make the codelet const
335 // See _starpu_codelet_check_deprecated_fields() in StarPU:
336 cl.where |= STARPU_CPU;
337 cl.checked = 1;
338
339 return cl;
340 }
341
342 static constexpr const struct starpu_codelet cl_op_data[] = {
343 gen_cl_op_data<internal::Operation::Assign, T>(),
344 gen_cl_op_data<internal::Operation::Add, T>(),
345 gen_cl_op_data<internal::Operation::Subtract, T>(),
346 gen_cl_op_data<internal::Operation::Multiply, T>(),
347 gen_cl_op_data<internal::Operation::Divide, T>()};
348 static constexpr const struct starpu_codelet cl_op_rdata[] = {
349 gen_cl_op_data<internal::Operation::Assign, real_type<T>>(),
350 gen_cl_op_data<internal::Operation::Add, real_type<T>>(),
351 gen_cl_op_data<internal::Operation::Subtract, real_type<T>>(),
352 gen_cl_op_data<internal::Operation::Multiply, real_type<T>>(),
353 gen_cl_op_data<internal::Operation::Divide, real_type<T>>()};
354
358 template <internal::Operation op>
359 static constexpr struct starpu_codelet gen_cl_op_entries() noexcept
360 {
361 using internal::Operation;
362 struct starpu_codelet cl = internal::codelet_init();
363
364 cl.cpu_funcs[0] = internal::matrixentry_op_matrixentry<T, op>;
365 cl.nbuffers = 1;
366 cl.modes[0] = STARPU_RW;
367 cl.name = (op == Operation::Assign)
368 ? "copy_entry"
369 : (op == Operation::Add)
370 ? "add_entry"
371 : (op == Operation::Subtract)
372 ? "subtract_entry"
373 : (op == Operation::Multiply)
374 ? "multiply_entry"
375 : (op == Operation::Divide)
376 ? "divide_entry"
377 : "unknown";
378
379 // The following lines are needed to make the codelet const
380 // See _starpu_codelet_check_deprecated_fields() in StarPU:
381 cl.where |= STARPU_CPU;
382 cl.checked = 1;
383
384 return cl;
385 }
386
387 static constexpr const struct starpu_codelet cl_op_entries[] = {
388 gen_cl_op_entries<internal::Operation::Assign>(),
389 gen_cl_op_entries<internal::Operation::Add>(),
390 gen_cl_op_entries<internal::Operation::Subtract>(),
391 gen_cl_op_entries<internal::Operation::Multiply>(),
392 gen_cl_op_entries<internal::Operation::Divide>()};
393
403 template <internal::Operation op,
404 class U,
405 std::enable_if_t<(std::is_same_v<U, T> ||
406 std::is_same_v<U, real_type<T>>),
407 int> = 0>
408 MatrixEntry& operate_and_assign(const MatrixEntry<U>& x)
409 {
410 // Allocate space for the task
411 struct starpu_task* task = starpu_task_create();
412
413 if (this->root_handle == x.root_handle) {
414 // If both variables are in the same matrix handle, we must
415 // directly perform the operation on the entries of the
416 // handle
417
418 using args_t = std::tuple<idx_t, idx_t, idx_t, idx_t>;
419
420 // Allocate space for the arguments
421 args_t* args_ptr = new args_t;
422
423 // Initialize arguments
424 std::get<0>(*args_ptr) = pos[0];
425 std::get<1>(*args_ptr) = pos[1];
426 std::get<2>(*args_ptr) = x.pos[0];
427 std::get<3>(*args_ptr) = x.pos[1];
428
429 // Initialize task
430 task->cl = (struct starpu_codelet*)&(cl_op_entries[int(op)]);
431 task->handles[0] = this->root_handle;
432 task->cl_arg = (void*)args_ptr;
433 task->cl_arg_size = sizeof(args_t);
434 task->callback_func = [](void* args) noexcept {
435 delete (args_t*)args;
436 };
437 task->callback_arg = (void*)args_ptr;
438 }
439 else {
440 // Initialize task
441 task->cl = (struct starpu_codelet*)&(
442 std::is_same_v<U, T> ? cl_op_data[int(op)]
443 : cl_op_rdata[int(op)]);
444 task->handles[0] = this->handle;
445 task->handles[1] = x.handle;
446 }
447
448 // Submit task and check for errors
449 const int ret = starpu_task_submit(task);
450 STARPU_CHECK_RETURN_VALUE(ret, "starpu_task_submit");
451
452 return *this;
453 }
454
464 template <internal::Operation op,
465 class U,
466 std::enable_if_t<(std::is_same_v<U, T> ||
467 std::is_same_v<U, real_type<T>>),
468 int> = 0>
469 MatrixEntry& operate_and_assign(const T& x)
470 {
471 // Allocate space for the value and initialize it
472 T* x_ptr = new T(x);
473
474 // Create and initialize task
475 struct starpu_task* task = starpu_task_create();
476 task->cl = (struct starpu_codelet*)&(std::is_same_v<U, T>
477 ? cl_op_value[int(op)]
478 : cl_op_rvalue[int(op)]);
479 task->handles[0] = this->handle;
480 task->cl_arg = (void*)x_ptr;
481 task->cl_arg_size = sizeof(T);
482 task->callback_func = [](void* arg) noexcept { delete (T*)arg; };
483 task->callback_arg = (void*)x_ptr;
484
485 // Submit task and check for errors
486 const int ret = starpu_task_submit(task);
487 STARPU_CHECK_RETURN_VALUE(ret, "starpu_task_submit");
488
489 return *this;
490 }
491 };
492
493 // Arithmetic operators with MatrixEntry
494
495 template <class lhs_t,
496 class rhs_t,
497 std::enable_if_t<
498 (std::is_same_v<lhs_t, rhs_t>) ||
499 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
500 int> = 0>
501 constexpr auto operator+(const MatrixEntry<lhs_t>& x,
502 const rhs_t& y) noexcept
503 {
504 using T = scalar_type<lhs_t, rhs_t>;
505 return T(x) + T(y);
506 }
507
508 template <class lhs_t,
509 class rhs_t,
510 std::enable_if_t<
511 (std::is_same_v<lhs_t, rhs_t>) ||
512 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
513 int> = 0>
514 constexpr auto operator+(const lhs_t& x,
515 const MatrixEntry<rhs_t>& y) noexcept
516 {
517 using T = scalar_type<lhs_t, rhs_t>;
518 return T(x) + T(y);
519 }
520
521 template <class lhs_t,
522 class rhs_t,
523 std::enable_if_t<
524 (std::is_same_v<lhs_t, rhs_t>) ||
525 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
526 int> = 0>
527 constexpr auto operator+(const MatrixEntry<lhs_t>& x,
528 const MatrixEntry<rhs_t>& y) noexcept
529 {
530 using T = scalar_type<lhs_t, rhs_t>;
531 return T(x) + T(y);
532 }
533
534 template <class lhs_t,
535 class rhs_t,
536 std::enable_if_t<
537 (std::is_same_v<lhs_t, rhs_t>) ||
538 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
539 int> = 0>
540 constexpr auto operator-(const MatrixEntry<lhs_t>& x,
541 const rhs_t& y) noexcept
542 {
543 using T = scalar_type<lhs_t, rhs_t>;
544 return T(x) - T(y);
545 }
546
547 template <class lhs_t,
548 class rhs_t,
549 std::enable_if_t<
550 (std::is_same_v<lhs_t, rhs_t>) ||
551 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
552 int> = 0>
553 constexpr auto operator-(const lhs_t& x,
554 const MatrixEntry<rhs_t>& y) noexcept
555 {
556 using T = scalar_type<lhs_t, rhs_t>;
557 return T(x) - T(y);
558 }
559
560 template <class lhs_t,
561 class rhs_t,
562 std::enable_if_t<
563 (std::is_same_v<lhs_t, rhs_t>) ||
564 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
565 int> = 0>
566 constexpr auto operator-(const MatrixEntry<lhs_t>& x,
567 const MatrixEntry<rhs_t>& y) noexcept
568 {
569 using T = scalar_type<lhs_t, rhs_t>;
570 return T(x) - T(y);
571 }
572
573 template <class lhs_t,
574 class rhs_t,
575 std::enable_if_t<
576 (std::is_same_v<lhs_t, rhs_t>) ||
577 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
578 int> = 0>
579 constexpr auto operator*(const MatrixEntry<lhs_t>& x,
580 const rhs_t& y) noexcept
581 {
582 using T = scalar_type<lhs_t, rhs_t>;
583 return T(x) * T(y);
584 }
585
586 template <class lhs_t,
587 class rhs_t,
588 std::enable_if_t<
589 (std::is_same_v<lhs_t, rhs_t>) ||
590 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
591 int> = 0>
592 constexpr auto operator*(const lhs_t& x,
593 const MatrixEntry<rhs_t>& y) noexcept
594 {
595 using T = scalar_type<lhs_t, rhs_t>;
596 return T(x) * T(y);
597 }
598
599 template <class lhs_t,
600 class rhs_t,
601 std::enable_if_t<
602 (std::is_same_v<lhs_t, rhs_t>) ||
603 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
604 int> = 0>
605 constexpr auto operator*(const MatrixEntry<lhs_t>& x,
606 const MatrixEntry<rhs_t>& y) noexcept
607 {
608 using T = scalar_type<lhs_t, rhs_t>;
609 return T(x) * T(y);
610 }
611
612 template <class lhs_t,
613 class rhs_t,
614 std::enable_if_t<
615 (std::is_same_v<lhs_t, rhs_t>) ||
616 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
617 int> = 0>
618 constexpr auto operator/(const MatrixEntry<lhs_t>& x,
619 const rhs_t& y) noexcept
620 {
621 using T = scalar_type<lhs_t, rhs_t>;
622 return T(x) / T(y);
623 }
624
625 template <class lhs_t,
626 class rhs_t,
627 std::enable_if_t<
628 (std::is_same_v<lhs_t, rhs_t>) ||
629 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
630 int> = 0>
631 constexpr auto operator/(const lhs_t& x,
632 const MatrixEntry<rhs_t>& y) noexcept
633 {
634 using T = scalar_type<lhs_t, rhs_t>;
635 return T(x) / T(y);
636 }
637
638 template <class lhs_t,
639 class rhs_t,
640 std::enable_if_t<
641 (std::is_same_v<lhs_t, rhs_t>) ||
642 (std::is_same_v<real_type<lhs_t>, real_type<rhs_t>>),
643 int> = 0>
644
645 constexpr auto operator/(const MatrixEntry<lhs_t>& x,
646 const MatrixEntry<rhs_t>& y) noexcept
647 {
648 using T = scalar_type<lhs_t, rhs_t>;
649 return T(x) / T(y);
650 }
651
652} // namespace starpu
653} // namespace tlapack
654
655#endif // TLAPACK_STARPU_MATRIXENTRY_HH
constexpr void data_op_data(void **buffers, void *args) noexcept
MatrixEntry operation with assignment using two StarPU variable buffers.
Definition MatrixEntry.hpp:49
constexpr struct starpu_codelet codelet_init() noexcept
Return an empty starpu_codelet struct.
Definition MatrixEntry.hpp:34
constexpr void matrixentry_op_matrixentry(void **buffers, void *args) noexcept
MatrixEntry operation with assignment using a two matrix entries.
Definition MatrixEntry.hpp:99
constexpr void data_op_value(void **buffers, void *args) noexcept
MatrixEntry operation with assignment using a StarPU variable buffer and a value.
Definition MatrixEntry.hpp:74
typename traits::real_type_traits< Types..., int >::type real_type
The common real type of the list of types.
Definition scalar_type_traits.hpp:113
Types for StarPU.
Arithmetic data type used by Matrix.
Definition MatrixEntry.hpp:145
const idx_t pos[2]
Position of the entry in the matrix.
Definition MatrixEntry.hpp:148
const starpu_data_handle_t root_handle
Matrix handle.
Definition MatrixEntry.hpp:146
~MatrixEntry() noexcept
Destructor cleans StarPU partition plan.
Definition MatrixEntry.hpp:169
starpu_data_handle_t handle
Entry handle.
Definition MatrixEntry.hpp:147
constexpr MatrixEntry(starpu_data_handle_t root_handle, const idx_t pos[2]) noexcept
MatrixEntry constructor from a variable handle.
Definition MatrixEntry.hpp:151