(git:6344619)
Loading...
Searching...
No Matches
dbm_multiply.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------------*/
2/* CP2K: A general program to perform molecular dynamics simulations */
3/* Copyright 2000-2026 CP2K developers group <https://cp2k.org> */
4/* */
5/* SPDX-License-Identifier: BSD-3-Clause */
6/*----------------------------------------------------------------------------*/
7#include "dbm_multiply.h"
10#include "dbm_hyperparams.h"
11#include "dbm_internal.h"
12#include "dbm_library.h"
13#include "dbm_multiply_comm.h"
14#include "dbm_multiply_cpu.h"
15#include "dbm_multiply_gpu.h"
16
17#include <assert.h>
18#include <limits.h>
19#include <math.h>
20#include <omp.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25/*******************************************************************************
26 * \brief Private routine for computing the max filter threshold for each row.
27 * \author Ole Schuett
28 ******************************************************************************/
29static float *compute_rows_max_eps(const bool trans, const dbm_matrix_t *matrix,
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);
35
36#pragma omp parallel
37 {
38#pragma omp for
39 for (int ishard = 0; ishard < dbm_get_num_shards(matrix); ishard++) {
40 dbm_shard_t *shard = &matrix->shards[ishard];
41 for (int iblock = 0; iblock < shard->nblocks; iblock++) {
42 const dbm_block_t *blk = &shard->blocks[iblock];
43 const int row = (trans) ? blk->col : blk->row;
44#pragma omp atomic
45 ++nblocks_per_row[row];
46 }
47 }
48#pragma omp master
49 cp_mpi_sum_int(nblocks_per_row, nrows, matrix->dist->comm);
50#pragma omp barrier
51#pragma omp for
52 for (int i = 0; i < nrows; i++) {
53 const float f =
54 ((float)filter_eps) / ((float)imax(1, nblocks_per_row[i]));
55 row_max_eps[i] = f * f;
56 }
57 } // end of omp parallel region
58
59 free(nblocks_per_row);
60 return row_max_eps; // Ownership of row_max_eps transfers to caller.
61}
62
63/*******************************************************************************
64 * \brief Private struct for storing the context of the multiplication backend.
65 * \author Ole Schuett
66 ******************************************************************************/
67typedef struct {
68#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
69 dbm_multiply_gpu_context_t gpu;
70#endif
71 int cpu_options; // Binary or'ed dbm_multiply_cpu_options (enum).
73
74/*******************************************************************************
75 * \brief Private routine for initializing the multiplication backend.
76 * \author Ole Schuett
77 ******************************************************************************/
79 backend_context_t *const ctx = calloc(1, sizeof(backend_context_t));
80 // BLAS and LIBXS benefit in general from DBM_MULTIPLY_TASK_REORDER.
82
83#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
84 dbm_multiply_gpu_start(DBM_MAX_BATCH_SIZE, dbm_get_num_shards(matrix_c),
85 matrix_c->shards, &ctx->gpu);
86#else
87 (void)matrix_c; // mark as used
88#endif
89
90 return ctx;
91}
92
93/*******************************************************************************
94 * \brief Private routine for handing newly arrived packs to the backend.
95 * \author Ole Schuett
96 ******************************************************************************/
97static bool backend_upload_packs(const dbm_pack_t *pack_a,
98 const dbm_pack_t *pack_b,
99 backend_context_t *ctx) {
100#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
101 return dbm_multiply_gpu_upload_packs(pack_a, pack_b, &ctx->gpu);
102#else
103 (void)pack_a; // mark as used
104 (void)pack_b;
105 (void)ctx;
106 return false;
107#endif
108}
109
110/*******************************************************************************
111 * \brief Private routine for sending a batch to the multiplication backend.
112 * \author Ole Schuett
113 ******************************************************************************/
114static void backend_process_batch(const int ntasks,
115 const dbm_task_t batch[ntasks],
116 const double alpha, const dbm_pack_t *pack_a,
117 const dbm_pack_t *pack_b, const int kshard,
118 dbm_shard_t *shard_c, const bool finish,
119 const bool force_cpu,
120 backend_context_t *ctx) {
121 if (NULL != ctx) {
122#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
123 if (!force_cpu) {
124 dbm_multiply_gpu_process_batch(ntasks, batch, alpha, shard_c, kshard,
125 finish, &ctx->gpu);
126 } else
127#endif
128 {
129 (void)kshard;
130 (void)finish;
131 (void)force_cpu;
132 dbm_multiply_cpu_process_batch(ntasks, batch, alpha, pack_a, pack_b,
133 shard_c, ctx->cpu_options);
134 }
135 } else { // Validate against host (aka CPU).
136 dbm_multiply_cpu_process_batch(ntasks, batch, alpha, pack_a, pack_b,
138 }
139}
140
141/*******************************************************************************
142 * \brief Private routine for shutting down the multiplication backend.
143 * \author Ole Schuett
144 ******************************************************************************/
146#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
147 dbm_multiply_gpu_stop(&ctx->gpu);
148#endif
149 free(ctx);
150}
151
152/*******************************************************************************
153 * \brief Private routine returning the seconds since tick, which it resets.
154 * \author Hans Pabst
155 ******************************************************************************/
156static double phase_lap(double *tick) {
157 const double now = omp_get_wtime();
158 const double result = now - *tick;
159 *tick = now;
160 return result;
161}
162
163/*******************************************************************************
164 * \brief Private routine for multiplying two packs (C += alpha * A * B).
165 *
166 * Blocks in each pack are grouped by shard (free_index % nshards) and sorted
167 * by sum_index within each group. The algorithm:
168 * 1. Builds shard-boundary lookup tables for A (rows) and B (cols).
169 * 2. For each (shard_row, shard_col) pair, determines the contiguous A and B
170 * block ranges belonging to that shard.
171 * 3. Performs a merge-join over sum_index: advances A and B cursors in
172 *lockstep, caching the B sub-range for each sum_index so that multiple A blocks
173 *with the same sum_index reuse it without rescanning.
174 * 4. Applies a norm-based filter (alpha^2 * norm_a * norm_b < eps) for early
175 * rejection before looking up or allocating the C block.
176 * 5. Accumulates matching pairs into a batched GEMM task list, flushing to the
177 * backend (CPU or GPU) every DBM_MAX_BATCH_SIZE tasks.
178 *
179 * \author Ole Schuett and Hans Pabst
180 ******************************************************************************/
181static void multiply_packs(const bool transa, const bool transb,
182 const double alpha, const dbm_pack_t *pack_a,
183 const dbm_pack_t *pack_b,
184 const dbm_matrix_t *matrix_a,
185 const dbm_matrix_t *matrix_b, dbm_matrix_t *matrix_c,
186 const float *rows_max_eps,
187 const bool retain_sparsity, const bool force_cpu,
188 int64_t *flop, backend_context_t *ctx) {
189 // For validation, FLOPS do not count, and relying on ctx is not necessary.
190 backend_context_t *const context = (NULL != flop ? ctx : NULL);
191 const float alpha2 = (float)(alpha * alpha);
192 int64_t flop_sum = 0;
193
194 const int nshard_rows = matrix_c->dist->rows.nshards;
195 const int nshard_cols = matrix_c->dist->cols.nshards;
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);
199
200 const int *sum_index_sizes_a =
201 (transa) ? matrix_a->row_sizes : matrix_a->col_sizes;
202 const int *sum_index_sizes_b =
203 (transb) ? matrix_b->col_sizes : matrix_b->row_sizes;
204 const int *free_index_sizes_a =
205 (transa) ? matrix_a->col_sizes : matrix_a->row_sizes;
206 const int *free_index_sizes_b =
207 (transb) ? matrix_b->row_sizes : matrix_b->col_sizes;
208
209#pragma omp parallel reduction(+ : flop_sum)
210 {
211 // Thread-private array covering given work in piece-wise fashion.
212 dbm_task_t *batch =
214 // Thread-local stats, added to the library's counters once at the end.
215 int64_t counters[DBM_NUM_COUNTERS] = {0};
216
217 // Blocks are ordered first by shard. Creating lookup tables of boundaries.
218#pragma omp for nowait
219 for (int iblock = 1; iblock < pack_a->nblocks; iblock++) {
220 const int shard_row = pack_a->blocks[iblock].free_index % nshard_rows;
221 const int prev_shard_row =
222 pack_a->blocks[iblock - 1].free_index % nshard_rows;
223 if (prev_shard_row != shard_row) {
224 shard_row_start[shard_row] = iblock;
225 }
226 }
227#pragma omp for
228 for (int jblock = 1; jblock < pack_b->nblocks; jblock++) {
229 const int shard_col = pack_b->blocks[jblock].free_index % nshard_cols;
230 const int prev_shard_col =
231 pack_b->blocks[jblock - 1].free_index % nshard_cols;
232 if (prev_shard_col != shard_col) {
233 shard_col_start[shard_col] = jblock;
234 }
235 }
236
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;
241 dbm_shard_t *const shard_c = &matrix_c->shards[ishard];
242 int ntasks = 0;
243
244 // Determine contiguous block ranges for this shard in A and B.
245 // Use a merge-join to find pairs of blocks with matching sum indices.
246 // This utilizes that blocks within a shard are ordered by sum_index.
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) {
250 if (pack_a->blocks[t].free_index % nshard_rows != shard_row) {
251 iblock_end = t;
252 break;
253 }
254 }
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) {
258 if (pack_b->blocks[t].free_index % nshard_cols != shard_col) {
259 jblock_end = t;
260 break;
261 }
262 }
263 if (iblock_start >= iblock_end || jblock_start >= jblock_end) {
264 backend_process_batch(ntasks, batch, alpha, pack_a, pack_b, ishard,
265 shard_c, true, force_cpu, context);
266 continue;
267 }
268
269 // Merge over sum_index (both ranges sorted by sum_index).
270 // Cache the B sub-range for each sum_index so that multiple A blocks
271 // sharing the same sum_index reuse it without re-scanning B.
272 int i = iblock_start, j = jblock_start, last_sum_index = -1;
273 int b_range_start = -1, b_range_end = -1;
274
275 while (i < iblock_end) {
276 const dbm_pack_block_t *blk_a = &pack_a->blocks[i];
277 const int sum_a = blk_a->sum_index;
278
279 // Advance j until sum_b >= sum_a.
280 while (j < jblock_end && pack_b->blocks[j].sum_index < sum_a) {
281 ++j;
282 }
283 if (j >= jblock_end) {
284 break; // No more matches possible.
285 }
286
287 const int sum_b = pack_b->blocks[j].sum_index;
288 if (sum_b > sum_a) {
289 ++i;
290 continue; // Need next A block with higher sum_index.
291 }
292
293 // sum_a == sum_b: establish (or reuse) B range with this sum_index.
294 if (sum_a != last_sum_index) {
295 b_range_start = j;
296 int t = j + 1;
297 while (t < jblock_end && pack_b->blocks[t].sum_index == sum_a) {
298 ++t;
299 }
300 b_range_end = t;
301 last_sum_index = sum_a;
302 }
303
304 // Iterate over B blocks in current sum_index range.
305 for (int jb = b_range_start; jb < b_range_end; ++jb) {
306 const dbm_pack_block_t *const blk_b = &pack_b->blocks[jb];
307
308 // Norm filter first (early reject).
309 const float result_norm = alpha2 * blk_a->norm * blk_b->norm;
310 if (result_norm < rows_max_eps[blk_a->free_index]) {
311 continue;
312 }
313
314 // Check block sizes.
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];
318 assert(m == matrix_c->row_sizes[blk_a->free_index]);
319 assert(n == matrix_c->col_sizes[blk_b->free_index]);
320 assert(k == sum_index_sizes_b[blk_b->sum_index]);
321
322 if (m == 0 || n == 0 || k == 0) {
323 continue;
324 }
325
326 // Get C block.
327 const int row = blk_a->free_index, col = blk_b->free_index;
328 dbm_block_t *blk_c = dbm_shard_lookup(shard_c, row, col);
329 if (blk_c == NULL) {
330 if (retain_sparsity) {
331 continue;
332 }
333 assert(dbm_get_shard_index(matrix_c, row, col) == ishard);
334 assert(dbm_get_stored_coordinates(matrix_c, row, col) ==
335 matrix_c->dist->my_rank);
336 blk_c = dbm_shard_promise_new_block(shard_c, row, col, m * n);
337 }
338
339 // Count flops.
340 const int64_t task_flops = 2LL * m * n * k;
341 flop_sum += task_flops;
342 ++counters[dbm_library_counter_index(m, n, k)];
343
344 // Add block multiplication to batch.
345 dbm_task_t *const tptr = &batch[ntasks];
346 tptr->offset_a = blk_a->offset;
347 tptr->offset_b = blk_b->offset;
348 tptr->offset_c = blk_c->offset;
349 tptr->m = m;
350 tptr->n = n;
351 tptr->k = k;
352 ++ntasks;
353
354 if (ntasks == DBM_MAX_BATCH_SIZE) {
355 backend_process_batch(ntasks, batch, alpha, pack_a, pack_b,
356 ishard, shard_c, false, force_cpu, context);
357 ntasks = 0;
358 }
359 }
360
361 // Advance i; if next A block has same sum_index, B range is reused.
362 ++i;
363 }
364 backend_process_batch(ntasks, batch, alpha, pack_a, pack_b, ishard,
365 shard_c, true, force_cpu, context);
366 }
367 }
368
369 dbm_library_counters_add(counters);
371 }
372
373 free(shard_row_start);
374 free(shard_col_start);
375
376 if (NULL != flop) {
377 *flop += flop_sum;
378 }
379}
380
381/*******************************************************************************
382 * \brief Performs a multiplication of two dbm_matrix_t matrices.
383 * See dbm_matrix.h for details.
384 * \author Ole Schuett
385 ******************************************************************************/
386void dbm_multiply(const bool transa, const bool transb, const double alpha,
387 const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b,
388 const double beta, dbm_matrix_t *matrix_c,
389 const bool retain_sparsity, const double filter_eps,
390 int64_t *flop) {
391 assert(omp_get_num_threads() == 1);
392 assert(matrix_a != NULL && matrix_b != NULL && matrix_c != NULL);
393 double phase[DBM_NUM_PHASES] = {0}, tick = omp_get_wtime();
394 int64_t phase_bytes[DBM_NUM_PHASES] = {0};
395
396 // Throughout the matrix multiplication code the "sum_index" and "free_index"
397 // denote the summation (aka dummy) and free index from the Einstein notation.
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;
402
403 // Sanity check matrix dimensions.
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);
407
408 // Prepare matrix_c (host).
409 dbm_scale(matrix_c, beta);
410
411 // Determine if validation shall be performed.
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)));
415 const int verify =
416 (NULL == verify_env ? (NULL == maxeps_env ? 0 : 1) : atoi(verify_env));
417 dbm_matrix_t *matrix_d = NULL;
418 phase[DBM_PHASE_SETUP] += phase_lap(&tick);
419 if (0 != verify) {
420 dbm_distribution_t *const dist_shared = matrix_c->dist;
421 dbm_create(&matrix_d, dist_shared, matrix_c->name, matrix_c->nrows,
422 matrix_c->ncols, matrix_c->row_sizes, matrix_c->col_sizes);
423 dbm_copy(matrix_d, matrix_c);
424 tick = omp_get_wtime(); // validation is not a phase
425 }
426
427 // Compute filter thresholds for each row.
428 float *rows_max_eps = compute_rows_max_eps(transa, matrix_a, filter_eps);
429
430 // Start uploading matrix_c to the GPU.
431 backend_context_t *ctx = backend_start(matrix_c);
432 phase[DBM_PHASE_SETUP] += phase_lap(&tick);
433
434 // Redistribute matrix_a and matrix_b across MPI ranks.
435 dbm_comm_iterator_t *iter =
436 dbm_comm_iterator_start(transa, transb, matrix_a, matrix_b, matrix_c);
437 const double redistribute = phase_lap(&tick);
438 phase[DBM_PHASE_ALLTOALL] += iter->seconds_alltoall;
439 phase[DBM_PHASE_SORT] += iter->seconds_sort;
441 phase[DBM_PHASE_PACK] +=
442 redistribute - iter->seconds_alltoall - iter->seconds_sort;
443
444 // Count flops if requested.
445 if (NULL != flop) {
446 *flop = 0;
447 }
448
449 // Main loop.
450 dbm_pack_t *pack_a, *pack_b;
451 while (dbm_comm_iterator_next(iter, &pack_a, &pack_b)) {
452 phase[DBM_PHASE_SHIFT] += phase_lap(&tick);
453 const bool uploaded = backend_upload_packs(pack_a, pack_b, ctx);
454 (void)uploaded; // mark used
455 phase[DBM_PHASE_UPLOAD] += 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 /*!uploaded*/,
458 flop, ctx);
459 phase[DBM_PHASE_MULTIPLY] += phase_lap(&tick);
460 }
461
462 // Wait for all other MPI ranks to complete, then release ressources.
465 phase[DBM_PHASE_SHIFT] += phase_lap(&tick);
466 backend_stop(ctx);
467 phase[DBM_PHASE_FINISH] += phase_lap(&tick);
468
469 if (NULL != matrix_d) {
470 ctx = backend_start(matrix_d);
471 iter =
472 dbm_comm_iterator_start(transa, transb, matrix_a, matrix_b, matrix_d);
473 while (dbm_comm_iterator_next(iter, &pack_a, &pack_b)) {
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);
476 }
478 backend_stop(ctx);
479 const double epsilon = dbm_maxeps(matrix_d, matrix_c);
480 if (maxeps < epsilon) {
481 if (1 == verify) {
482 fprintf(stderr, "WARN ACC/LIBDBM: diff=%g\n", epsilon);
483 } else {
484 fprintf(stderr, "ERROR ACC/LIBDBM: diff=%g\n", epsilon);
485 exit(EXIT_FAILURE);
486 }
487 }
488 dbm_release(matrix_d);
489 tick = omp_get_wtime(); // validation is not a phase
490 }
491
492 // Release filter thresholds.
493 free(rows_max_eps);
494
495 // Final filter pass.
496 dbm_filter(matrix_c, filter_eps);
497 phase[DBM_PHASE_SETUP] += phase_lap(&tick);
499}
500
501// EOF
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.
Definition cp_mpi.c:414
#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.
Definition dbm_library.c:93
static int64_t phase_bytes[DBM_NUM_PHASES]
Definition dbm_library.c:24
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...
#define DBM_NUM_COUNTERS
Definition dbm_library.h:26
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...
Definition dbm_library.h:33
@ DBM_NUM_PHASES
Definition dbm_library.h:62
@ DBM_PHASE_ALLTOALL
Definition dbm_library.h:56
@ DBM_PHASE_FINISH
Definition dbm_library.h:61
@ DBM_PHASE_SORT
Definition dbm_library.h:57
@ DBM_PHASE_MULTIPLY
Definition dbm_library.h:60
@ DBM_PHASE_UPLOAD
Definition dbm_library.h:59
@ DBM_PHASE_SHIFT
Definition dbm_library.h:58
@ DBM_PHASE_SETUP
Definition dbm_library.h:54
@ DBM_PHASE_PACK
Definition dbm_library.h:55
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 ...
Definition dbm_matrix.c:282
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.
Definition dbm_matrix.c:22
void dbm_scale(dbm_matrix_t *matrix, const double alpha)
Multiplies all entries in the given matrix by the given factor alpha.
Definition dbm_matrix.c:368
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...
Definition dbm_matrix.c:90
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.
Definition dbm_matrix.c:565
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.
Definition dbm_matrix.c:697
void dbm_release(dbm_matrix_t *matrix)
Releases a matrix and all its ressources.
Definition dbm_matrix.c:72
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.
Definition dbm_matrix.h:245
static int dbm_get_num_shards(const dbm_matrix_t *matrix)
Internal routine that returns the number of shards for given matrix.
Definition dbm_matrix.h:237
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.
Definition dbm_shard.c:205
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.
Definition dbm_shard.c:181
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.
Definition dbm_shard.h:20
Internal struct for storing a communication iterator.
Internal struct for storing a two dimensional distribution.
Internal struct for storing a matrix.
Definition dbm_matrix.h:19
int * row_sizes
Definition dbm_matrix.h:24
char * name
Definition dbm_matrix.h:21
int * col_sizes
Definition dbm_matrix.h:25
dbm_shard_t * shards
Definition dbm_matrix.h:27
dbm_distribution_t * dist
Definition dbm_matrix.h:20
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.
Definition dbm_shard.h:30
dbm_block_t * blocks
Definition dbm_shard.h:33
Internal struct for storing a task, ie. a single block multiplication.