30 const double filter_eps) {
31 const int nrows = (trans) ? matrix->
ncols : matrix->
nrows;
32 int *nblocks_per_row = calloc(nrows,
sizeof(
int));
33 float *row_max_eps = malloc(nrows *
sizeof(
float));
34 assert((nblocks_per_row != NULL && row_max_eps != NULL) || nrows == 0);
41 for (
int iblock = 0; iblock < shard->
nblocks; iblock++) {
43 const int row = (trans) ? blk->
col : blk->
row;
45 ++nblocks_per_row[row];
52 for (
int i = 0;
i < nrows;
i++) {
54 ((float)filter_eps) / ((
float)
imax(1, nblocks_per_row[
i]));
55 row_max_eps[
i] = f * f;
59 free(nblocks_per_row);
68#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
69 dbm_multiply_gpu_context_t gpu;
83#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
85 matrix_c->
shards, &ctx->gpu);
100#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
101 return dbm_multiply_gpu_upload_packs(pack_a, pack_b, &ctx->gpu);
119 const bool force_cpu,
122#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
124 dbm_multiply_gpu_process_batch(ntasks, batch, alpha, shard_c, kshard,
146#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
147 dbm_multiply_gpu_stop(&ctx->gpu);
157 const double now = omp_get_wtime();
158 const double result = now - *tick;
186 const float *rows_max_eps,
187 const bool retain_sparsity,
const bool force_cpu,
191 const float alpha2 = (float)(alpha * alpha);
192 int64_t flop_sum = 0;
196 int *shard_row_start = calloc(nshard_rows,
sizeof(
int));
197 int *shard_col_start = calloc(nshard_cols,
sizeof(
int));
198 assert(NULL != shard_row_start && NULL != shard_col_start);
200 const int *sum_index_sizes_a =
202 const int *sum_index_sizes_b =
204 const int *free_index_sizes_a =
206 const int *free_index_sizes_b =
209#pragma omp parallel reduction(+ : flop_sum)
218#pragma omp for nowait
219 for (
int iblock = 1; iblock < pack_a->
nblocks; iblock++) {
221 const int prev_shard_row =
223 if (prev_shard_row != shard_row) {
224 shard_row_start[shard_row] = iblock;
228 for (
int jblock = 1; jblock < pack_b->
nblocks; jblock++) {
230 const int prev_shard_col =
232 if (prev_shard_col != shard_col) {
233 shard_col_start[shard_col] = jblock;
237#pragma omp for collapse(2) DBM_OMP_SCHEDULE
238 for (
int shard_row = 0; shard_row < nshard_rows; shard_row++) {
239 for (
int shard_col = 0; shard_col < nshard_cols; shard_col++) {
240 const int ishard = shard_row * nshard_cols + shard_col;
247 const int iblock_start = shard_row_start[shard_row];
248 int iblock_end = pack_a->
nblocks;
249 for (
int t = iblock_start; t < pack_a->
nblocks; ++t) {
255 const int jblock_start = shard_col_start[shard_col];
256 int jblock_end = pack_b->
nblocks;
257 for (
int t = jblock_start; t < pack_b->
nblocks; ++t) {
263 if (iblock_start >= iblock_end || jblock_start >= jblock_end) {
265 shard_c,
true, force_cpu, context);
272 int i = iblock_start, j = jblock_start, last_sum_index = -1;
273 int b_range_start = -1, b_range_end = -1;
275 while (
i < iblock_end) {
280 while (j < jblock_end && pack_b->blocks[j].sum_index < sum_a) {
283 if (j >= jblock_end) {
294 if (sum_a != last_sum_index) {
297 while (t < jblock_end && pack_b->blocks[t].sum_index == sum_a) {
301 last_sum_index = sum_a;
305 for (
int jb = b_range_start; jb < b_range_end; ++jb) {
309 const float result_norm = alpha2 * blk_a->
norm * blk_b->
norm;
310 if (result_norm < rows_max_eps[blk_a->
free_index]) {
315 const int m = free_index_sizes_a[blk_a->
free_index];
316 const int n = free_index_sizes_b[blk_b->
free_index];
317 const int k = sum_index_sizes_a[sum_a];
320 assert(k == sum_index_sizes_b[blk_b->
sum_index]);
322 if (m == 0 || n == 0 || k == 0) {
330 if (retain_sparsity) {
340 const int64_t task_flops = 2LL * m * n * k;
341 flop_sum += task_flops;
356 ishard, shard_c,
false, force_cpu, context);
365 shard_c,
true, force_cpu, context);
373 free(shard_row_start);
374 free(shard_col_start);
386void dbm_multiply(
const bool transa,
const bool transb,
const double alpha,
389 const bool retain_sparsity,
const double filter_eps,
391 assert(omp_get_num_threads() == 1);
392 assert(matrix_a != NULL && matrix_b != NULL && matrix_c != NULL);
398 const int num_sum_index_a = (transa) ? matrix_a->
nrows : matrix_a->
ncols;
399 const int num_sum_index_b = (transb) ? matrix_b->
ncols : matrix_b->
nrows;
400 const int num_free_index_a = (transa) ? matrix_a->
ncols : matrix_a->
nrows;
401 const int num_free_index_b = (transb) ? matrix_b->
nrows : matrix_b->
ncols;
404 assert(num_sum_index_a == num_sum_index_b);
405 assert(num_free_index_a == matrix_c->
nrows);
406 assert(num_free_index_b == matrix_c->
ncols);
412 const char *
const maxeps_env = getenv(
"DBM_MULTIPLY_MAXEPS");
413 const char *
const verify_env = getenv(
"DBM_MULTIPLY_VERIFY");
414 const double maxeps = (NULL == maxeps_env ? 1E-1 : fabs(atof(maxeps_env)));
416 (NULL == verify_env ? (NULL == maxeps_env ? 0 : 1) : atoi(verify_env));
424 tick = omp_get_wtime();
437 const double redistribute =
phase_lap(&tick);
456 multiply_packs(transa, transb, alpha, pack_a, pack_b, matrix_a, matrix_b,
457 matrix_c, rows_max_eps, retain_sparsity,
false ,
469 if (NULL != matrix_d) {
474 multiply_packs(transa, transb, alpha, pack_a, pack_b, matrix_a, matrix_b,
475 matrix_d, rows_max_eps, retain_sparsity,
true, NULL, ctx);
479 const double epsilon =
dbm_maxeps(matrix_d, matrix_c);
480 if (maxeps < epsilon) {
482 fprintf(stderr,
"WARN ACC/LIBDBM: diff=%g\n", epsilon);
484 fprintf(stderr,
"ERROR ACC/LIBDBM: diff=%g\n", epsilon);
489 tick = omp_get_wtime();
void cp_mpi_sum_int(int *values, const int count, const cp_mpi_comm_t comm)
Wrapper around MPI_Allreduce for op MPI_SUM and datatype MPI_INT.
#define DBM_MAX_BATCH_SIZE
static int imax(int x, int y)
Returns the larger of two given integers (missing from the C standard).
void dbm_library_counters_add(const int64_t counters[DBM_NUM_COUNTERS])
Add the calling thread's counts to the stats. This routine is thread-safe.
static int64_t phase_bytes[DBM_NUM_PHASES]
void dbm_library_phases_add(const double seconds[DBM_NUM_PHASES], const int64_t bytes[DBM_NUM_PHASES])
Add the durations (seconds) of a multiplication's phases to the stats. Called once per dbm_multiply o...
static int dbm_library_counter_index(const int m, const int n, const int k)
Internal routine for the stats counter of a block multiplication, i.e., min(3, floor(log10(x))) per m...
void dbm_filter(dbm_matrix_t *matrix, const double eps)
Removes all blocks from the matrix whose norm is below the threshold. Blocks of size zero are always ...
void dbm_create(dbm_matrix_t **matrix_out, dbm_distribution_t *dist, const char name[], const int nrows, const int ncols, const int row_sizes[nrows], const int col_sizes[ncols])
Creates a new matrix.
void dbm_scale(dbm_matrix_t *matrix, const double alpha)
Multiplies all entries in the given matrix by the given factor alpha.
void dbm_copy(dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b)
Copies content of matrix_b into matrix_a. Matrices must have the same row/col block sizes and distrib...
double dbm_maxeps(const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b)
Calculates maximum relative difference between matrix_a and matrix_b.
int dbm_get_stored_coordinates(const dbm_matrix_t *matrix, const int row, const int col)
Returns the MPI rank on which the given block should be stored.
void dbm_release(dbm_matrix_t *matrix)
Releases a matrix and all its ressources.
static int dbm_get_shard_index(const dbm_matrix_t *matrix, const int row, const int col)
Internal routine for getting a block's shard index.
static int dbm_get_num_shards(const dbm_matrix_t *matrix)
Internal routine that returns the number of shards for given matrix.
static float * compute_rows_max_eps(const bool trans, const dbm_matrix_t *matrix, const double filter_eps)
Private routine for computing the max filter threshold for each row.
static backend_context_t * backend_start(const dbm_matrix_t *matrix_c)
Private routine for initializing the multiplication backend.
static bool backend_upload_packs(const dbm_pack_t *pack_a, const dbm_pack_t *pack_b, backend_context_t *ctx)
Private routine for handing newly arrived packs to the backend.
static void backend_stop(backend_context_t *ctx)
Private routine for shutting down the multiplication backend.
static double phase_lap(double *tick)
Private routine returning the seconds since tick, which it resets.
static void multiply_packs(const bool transa, const bool transb, const double alpha, const dbm_pack_t *pack_a, const dbm_pack_t *pack_b, const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b, dbm_matrix_t *matrix_c, const float *rows_max_eps, const bool retain_sparsity, const bool force_cpu, int64_t *flop, backend_context_t *ctx)
Private routine for multiplying two packs (C += alpha * A * B).
static void backend_process_batch(const int ntasks, const dbm_task_t batch[ntasks], const double alpha, const dbm_pack_t *pack_a, const dbm_pack_t *pack_b, const int kshard, dbm_shard_t *shard_c, const bool finish, const bool force_cpu, backend_context_t *ctx)
Private routine for sending a batch to the multiplication backend.
void dbm_multiply(const bool transa, const bool transb, const double alpha, const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b, const double beta, dbm_matrix_t *matrix_c, const bool retain_sparsity, const double filter_eps, int64_t *flop)
Performs a multiplication of two dbm_matrix_t matrices. See dbm_matrix.h for details.
dbm_comm_iterator_t * dbm_comm_iterator_start(const bool transa, const bool transb, const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b, const dbm_matrix_t *matrix_c)
Internal routine for creating a communication iterator.
void dbm_comm_iterator_stop(dbm_comm_iterator_t *iter)
Internal routine for releasing the given communication iterator.
bool dbm_comm_iterator_next(dbm_comm_iterator_t *iter, dbm_pack_t **pack_a, dbm_pack_t **pack_b)
Internal routine for retrieving next pair of packs of given iterator.
void dbm_multiply_cpu_process_batch(int ntasks, const dbm_task_t batch[ntasks], double alpha, const dbm_pack_t *pack_a, const dbm_pack_t *pack_b, dbm_shard_t *shard_c, int options)
Internal routine for executing the tasks in given batch on the CPU.
@ DBM_MULTIPLY_BLAS_LIBRARY
@ DBM_MULTIPLY_TASK_REORDER
dbm_block_t * dbm_shard_promise_new_block(dbm_shard_t *shard, const int row, const int col, const int block_size)
Internal routine for allocating the metadata of a new block.
dbm_block_t * dbm_shard_lookup(const dbm_shard_t *shard, const int row, const int col)
Internal routine for looking up a block from a shard.
static void const int const int i
void offload_mempool_host_free(const void *memory)
Internal routine for releasing memory back to the pool.
void * offload_mempool_host_malloc(const size_t size)
Internal routine for allocating host memory from the pool.
Private struct for storing the context of the multiplication backend.
Internal struct for storing a block's metadata.
Internal struct for storing a communication iterator.
Internal struct for storing a two dimensional distribution.
Internal struct for storing a matrix.
dbm_distribution_t * dist
Internal struct for storing a dbm_block_t plus its norm.
Internal struct for storing a pack - essentially a shard for MPI.
dbm_pack_block_t * blocks
Internal struct for storing a matrix shard.
Internal struct for storing a task, ie. a single block multiplication.