(git:d4bfb39)
Loading...
Searching...
No Matches
dbm_library.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_library.h"
8#include "../mpiwrap/cp_mpi.h"
9#include "../offload/offload_library.h"
10#include "../offload/offload_mempool.h"
11
12#include <assert.h>
13#include <inttypes.h>
14#include <omp.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#define DBM_LIBRARY_PRINT(FN, MSG, OUTPUT_UNIT) \
20 ((FN)(MSG, (int)strlen(MSG), OUTPUT_UNIT))
21#define DBM_NUM_COUNTERS 64
22
23static int64_t **per_thread_counters = NULL;
24static bool library_initialized = false;
25static int max_threads = 0;
26
27#if !defined(_OPENMP)
28#error "OpenMP is required. Please add -fopenmp to your C compiler flags."
29#endif
30
31/*******************************************************************************
32 * \brief Initializes the DBM library.
33 * \author Ole Schuett
34 ******************************************************************************/
35void dbm_library_init(void) {
36 assert(omp_get_num_threads() == 1);
37
39 fprintf(stderr, "DBM library was already initialized.\n");
40 abort();
41 }
42
43 offload_init();
44
45 max_threads = omp_get_max_threads();
46 per_thread_counters = malloc(max_threads * sizeof(int64_t *));
47 assert(per_thread_counters != NULL);
48
49 // Using parallel regions to ensure memory is allocated near a thread's core.
50#pragma omp parallel default(none) shared(per_thread_counters) \
51 num_threads(max_threads)
52 {
53 const int ithread = omp_get_thread_num();
54 const size_t counters_size = DBM_NUM_COUNTERS * sizeof(int64_t);
55 per_thread_counters[ithread] = malloc(counters_size);
56 assert(per_thread_counters[ithread] != NULL);
57 memset(per_thread_counters[ithread], 0, counters_size);
58 }
59
61}
62
63/*******************************************************************************
64 * \brief Finalizes the DBM library.
65 * \author Ole Schuett
66 ******************************************************************************/
68 assert(omp_get_num_threads() == 1);
69
71 fprintf(stderr, "Error: DBM library is not initialized.\n");
72 abort();
73 }
74
75 for (int i = 0; i < max_threads; i++) {
77 }
80
82 library_initialized = false;
83}
84
85/*******************************************************************************
86 * \brief Computes min(3, floor(log10(x))).
87 * \author Ole Schuett
88 ******************************************************************************/
89static int floorlog10(const int x) {
90 return (100 <= x ? (1000 <= x ? 3 : 2) : (10 <= x ? 1 : 0));
91}
92
93/*******************************************************************************
94 * \brief Add given block multiplication to stats. This routine is thread-safe.
95 * \author Ole Schuett
96 ******************************************************************************/
97void dbm_library_counter_increment(const int m, const int n, const int k) {
98 const int ithread = omp_get_thread_num();
99 assert(ithread < max_threads);
100 const int idx = 16 * floorlog10(m) + 4 * floorlog10(n) + floorlog10(k);
101 per_thread_counters[ithread][idx]++;
102}
103
104/*******************************************************************************
105 * \brief Comperator passed to qsort to compare two counters.
106 * \author Ole Schuett
107 ******************************************************************************/
108static int compare_counters(const void *a, const void *b) {
109 return *(const int64_t *)b - *(const int64_t *)a;
110}
111
112/*******************************************************************************
113 * \brief Prints statistics gathered by the DBM library.
114 * \author Ole Schuett
115 ******************************************************************************/
116void dbm_library_print_stats(const int fortran_comm,
117 void (*print_func)(const char *, int, int),
118 const int output_unit) {
119 assert(omp_get_num_threads() == 1);
120
121 if (!library_initialized) {
122 fprintf(stderr, "Error: DBM library is not initialized.\n");
123 abort();
124 }
125
126 const cp_mpi_comm_t comm = cp_mpi_comm_f2c(fortran_comm);
127 // Sum all counters across threads and mpi ranks.
128 int64_t counters[DBM_NUM_COUNTERS][2] = {{0}};
129 double total = 0.0;
130 for (int i = 0; i < DBM_NUM_COUNTERS; i++) {
131 counters[i][1] = i; // needed as inverse index after qsort
132 for (int j = 0; j < max_threads; j++) {
133 counters[i][0] += per_thread_counters[j][i];
134 }
135 cp_mpi_sum_int64(&counters[i][0], 1, comm);
136 total += counters[i][0];
137 }
138
139 // Sort counters.
140 qsort(counters, DBM_NUM_COUNTERS, 2 * sizeof(int64_t), &compare_counters);
141
142 // Determine if anything needs to be printed.
143 bool print = false;
144 for (int i = 0; i < DBM_NUM_COUNTERS && !print; i++) {
145 if (counters[i][0] != 0) {
146 print = true;
147 }
148 }
149 if (!print) {
150 return; // nothing to be printed
151 }
152
153 // Print counters.
154 DBM_LIBRARY_PRINT(print_func, "\n", output_unit);
157 " ----------------------------------------------------------------"
158 "---------------\n",
159 output_unit);
162 " - "
163 " -\n",
164 output_unit);
167 " - DBM STATISTICS "
168 " -\n",
169 output_unit);
172 " - "
173 " -\n",
174 output_unit);
177 " ----------------------------------------------------------------"
178 "---------------\n",
179 output_unit);
182 " M x N x K "
183 "COUNT PERCENT\n",
184 output_unit);
185
186 const char *labels[] = {"?", "??", "???", ">999"};
187 char buffer[100];
188 for (int i = 0; i < DBM_NUM_COUNTERS; i++) {
189 if (counters[i][0] == 0) {
190 continue; // skip empty counters
191 }
192 const double percent = 100.0 * counters[i][0] / total;
193 const int idx = counters[i][1];
194 const int m = (idx % 64) / 16;
195 const int n = (idx % 16) / 4;
196 const int k = (idx % 4) / 1;
197 snprintf(buffer, sizeof(buffer),
198 " %4s x %4s x %4s %46" PRId64 " %10.2f%%\n", labels[m],
199 labels[n], labels[k], counters[i][0], percent);
200 DBM_LIBRARY_PRINT(print_func, buffer, output_unit);
201 }
202
205 " ----------------------------------------------------------------"
206 "---------------\n",
207 output_unit);
208}
209
210// EOF
void cp_mpi_sum_int64(int64_t *values, const int count, const cp_mpi_comm_t comm)
Wrapper around MPI_Allreduce for op MPI_SUM and datatype MPI_INT64_T.
Definition cp_mpi.c:363
cp_mpi_comm_t cp_mpi_comm_f2c(const int fortran_comm)
Wrapper around MPI_Comm_f2c.
Definition cp_mpi.c:69
int cp_mpi_comm_t
Definition cp_mpi.h:18
static bool library_initialized
Definition dbm_library.c:24
void dbm_library_finalize(void)
Finalizes the DBM library.
Definition dbm_library.c:67
void dbm_library_counter_increment(const int m, const int n, const int k)
Add given block multiplication to stats. This routine is thread-safe.
Definition dbm_library.c:97
#define DBM_NUM_COUNTERS
Definition dbm_library.c:21
#define DBM_LIBRARY_PRINT(FN, MSG, OUTPUT_UNIT)
Definition dbm_library.c:19
static int floorlog10(const int x)
Computes min(3, floor(log10(x))).
Definition dbm_library.c:89
void dbm_library_init(void)
Initializes the DBM library.
Definition dbm_library.c:35
static int max_threads
Definition dbm_library.c:25
static int compare_counters(const void *a, const void *b)
Comperator passed to qsort to compare two counters.
static int64_t ** per_thread_counters
Definition dbm_library.c:23
static void print_func(const char *msg, int msglen, int output_unit)
Wrapper for printf, passed to dbm_library_print_stats.
Definition dbm_miniapp.c:25
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
static void const int const int i
void offload_mempool_clear(void)
Internal routine for freeing all memory in the pool.