TDLS 0.4.0
Tiny Device-callable Linear Solvers
Loading...
Searching...
No Matches
solver_dynamic.hpp File Reference

Runtime-size variant of the CooperativeLUpp solver. More...

#include <type_traits>
#include <tdls/core/group.hpp>
#include <tdls/core/macros.hpp>
#include <tdls/core/math.hpp>
#include <tdls/core/target.hpp>
#include <tdls/solvers/cooperative_lupp/config.hpp>
Include dependency graph for solver_dynamic.hpp:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  tdls::CooperativeLUppSolverDynamic< T, Config >
 Runtime-size dense LU factorization with partial pivoting shared by a group of threads, solving one n x n system per group. More...
 

Macros

#define TDLS_COOP_LUPP_DYN_A(r, c)
 Strided element (r, c) of S, the stored matrix read column-major (A under the column-major layout, A^T under the row-major one): consecutive threads hold consecutive rows of S, thus consecutive addresses.
 
#define TDLS_COOP_LUPP_DYN_PIV(r)
 Strided pivot entry of row r.
 
#define TDLS_COOP_LUPP_DYN_B(r)
 Strided entry r of the right-hand side.
 
#define TDLS_COOP_LUPP_DYN_X(r)
 Strided entry r of the solution.
 
#define TDLS_COOP_LUPP_DYN_Y(r)
 Strided entry r of the right-hand side solved in place.
 

Detailed Description

Runtime-size variant of the CooperativeLUpp solver.

Author
Tristan Chenaille

Same algorithm as CooperativeLUppSolverStatic (solver_static.hpp): the LU with partial pivoting of MAGMA's register-blocked small-system kernel applied to S, the stored matrix read column-major (A under the column-major layout, A^T under the row-major one), the solve S x = b or S^T x = b, logical or physical row interchanges, the rows of S shared by a group of threads, a workspace and a deduced or caller-provided barrier, the pivot entries as pivot output and the pivots on the factored diagonal. The difference is that the system dimension n is a runtime function parameter instead of a template parameter. Only the number of rows per thread (Config.rows_per_thread) stays compile-time: it sizes the pivot entries and the right-hand-side entries kept by each thread, while the number of threads, threads_per_system(n), and every loop bound are runtime values.

Deliberate differences with the compile-time solver:

  • No unroll pragma anywhere: with runtime bounds nothing can be register-resident by full unrolling, so the unroll_loops knob of CooperativeLUppConfig is ignored.
  • The rows of a thread are updated in place in the matrix instead of a register copy: a row of runtime length cannot live in registers.
  • Under the row-major layout, the substitutions publish the positions of the rows once, and each thread loads the entries of S it needs itself, before the barrier of each step, instead of receiving a published row: the latency of the memory then sits off the chain of the steps. The arithmetic is unchanged.
  • No internal_rhs / internal_piv / internal_matrix booleans: every operand is the whole object, plain pointer + stride, in memory reachable by every thread of the group.
  • The size of the group depends on n, so the deduced barrier checks it at run time, and a pass that offers no deduced barrier refuses tdls::AutoSync at compile time. tdls::NoSync is checked at run time: n above Config.rows_per_thread, a group of several threads, stops the program with a message, wherever the pass can stop it (see core/group.hpp).

For equal shapes (n = N, same configuration), results are bitwise identical to the compile-time solver: factored rows, pivot entries and solution. The arithmetic sequence is the same, only the storage of the rows and the loop mechanics differ. A compiler that fuses multiplications and additions differently in the two (GCC with -march=native does) changes the last bits. Build with -ffp-contract=off (–fmad=false for nvcc) to compare them bit for bit.

The compile-time solver is the performance path; this variant is the flexibility path (dimensions unknown at compile time, fast builds).

The calling convention, the factored format and the pivot convention are those of the compile-time solver, described in solver_static.hpp. So are the guarantees of the group: a fixed sequence of barriers, no data race, inputs read by their owners on entry, results visible to the whole group on return. One exception: under the row-major layout and physical row interchanges, the substitutions read the factored matrix of the other threads before any barrier, so it must be visible to the group before the call, as it is after factorize. The workspace holds workspace_size(n) elements, laid out as there with n for N, without the restrict qualifier, for the reason given there. The matrix layout follows Config.layout, row-major by default, and selects the solve at compile time, as there.

Preconditions: n >= 1 and 0 <= tx < threads_per_system(n). The flat element index (for the matrix, n*n) must stay below 2^31; element offsets, index times stride, are computed in 64-bit arithmetic.

Macro Definition Documentation

◆ TDLS_COOP_LUPP_DYN_A

#define TDLS_COOP_LUPP_DYN_A ( r,
c )
Value:
A[TDLS_STRIDED((c) * n + (r), A_stride)]
#define TDLS_STRIDED(i, s)
Offset of entry i of a strided object, i times stride s, in 64-bit arithmetic (std::size_t); i and s ...
Definition macros.hpp:206

Strided element (r, c) of S, the stored matrix read column-major (A under the column-major layout, A^T under the row-major one): consecutive threads hold consecutive rows of S, thus consecutive addresses.

◆ TDLS_COOP_LUPP_DYN_B

#define TDLS_COOP_LUPP_DYN_B ( r)
Value:
b[TDLS_STRIDED(r, rhs_stride)]

Strided entry r of the right-hand side.

◆ TDLS_COOP_LUPP_DYN_PIV

#define TDLS_COOP_LUPP_DYN_PIV ( r)
Value:
piv[TDLS_STRIDED(r, piv_stride)]

Strided pivot entry of row r.

◆ TDLS_COOP_LUPP_DYN_X

#define TDLS_COOP_LUPP_DYN_X ( r)
Value:
x[TDLS_STRIDED(r, rhs_stride)]

Strided entry r of the solution.

◆ TDLS_COOP_LUPP_DYN_Y

#define TDLS_COOP_LUPP_DYN_Y ( r)
Value:
y[TDLS_STRIDED(r, rhs_stride)]

Strided entry r of the right-hand side solved in place.