(git:15c1bfc)
Loading...
Searching...
No Matches
dbm_mempool.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------------*/
2/* CP2K: A general program to perform molecular dynamics simulations */
3/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
4/* */
5/* SPDX-License-Identifier: BSD-3-Clause */
6/*----------------------------------------------------------------------------*/
7
8#include <assert.h>
9#include <omp.h>
10#include <stdbool.h>
11#include <stddef.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "../offload/offload_library.h"
17#include "../offload/offload_runtime.h"
18#include "dbm_hyperparams.h"
19#include "dbm_mempool.h"
20#include "dbm_mpi.h"
21
22/*******************************************************************************
23 * \brief Private struct for storing a chunk of memory.
24 * \author Ole Schuett
25 ******************************************************************************/
26typedef struct dbm_memchunk {
27 void *mem; // first: allows to cast memchunk into mem-ptr...
29 size_t size, used;
31
32/*******************************************************************************
33 * \brief Private struct for storing a memory pool.
34 * \author Ole Schuett
35 ******************************************************************************/
36typedef struct dbm_mempool {
37 dbm_memchunk_t *available_head, *allocated_head; // single-linked lists
39
40/*******************************************************************************
41 * \brief Private pools for host and device memory.
42 * \author Ole Schuett
43 ******************************************************************************/
45
46/*******************************************************************************
47 * \brief Private some counters for statistics.
48 * \author Hans Pabst
49 ******************************************************************************/
51
52/*******************************************************************************
53 * \brief Private routine for actually allocating system memory.
54 * \author Ole Schuett
55 ******************************************************************************/
56static void *actual_malloc(const size_t size, const bool on_device) {
57 if (size == 0) {
58 return NULL;
59 }
60
61 void *memory;
62
63#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
64 if (on_device) {
65 offload_activate_chosen_device();
66 offloadMalloc(&memory, size);
67 } else {
68 offload_activate_chosen_device();
69 offloadMallocHost(&memory, size);
70 }
71#else
72 memory = dbm_mpi_alloc_mem(size);
73#endif
74
75 // Update statistics.
76 if (on_device) {
77#pragma omp atomic
79 } else {
80#pragma omp atomic
82 }
83
84 assert(memory != NULL);
85 return memory;
86}
87
88/*******************************************************************************
89 * \brief Private routine for actually freeing system memory.
90 * \author Ole Schuett
91 ******************************************************************************/
92static void actual_free(void *memory, const bool on_device) {
93 if (NULL == memory) {
94 return;
95 }
96
97#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
98 if (on_device) {
99 offload_activate_chosen_device();
100 offloadFree(memory);
101 } else {
102 offload_activate_chosen_device();
103 offloadFreeHost(memory);
104 }
105#else
106 (void)on_device; // mark used
107 dbm_mpi_free_mem(memory);
108#endif
109}
110
111/*******************************************************************************
112 * \brief Private routine for allocating host or device memory from the pool.
113 * \author Ole Schuett and Hans Pabst
114 ******************************************************************************/
115static void *internal_mempool_malloc(dbm_mempool_t *pool, const size_t size,
116 const bool on_device) {
117 if (size == 0) {
118 return NULL;
119 }
120
121 dbm_memchunk_t *chunk;
122
123#pragma omp critical(dbm_mempool_modify)
124 {
125 // Find a possible chunk to reuse or reclaim in available list.
126 dbm_memchunk_t **reuse = NULL, **reclaim = NULL; // ** for easy list removal
127 dbm_memchunk_t **indirect = &pool->available_head;
128 while (*indirect != NULL) {
129 const size_t s = (*indirect)->size;
130 if (size <= s && (reuse == NULL || s < (*reuse)->size)) {
131 reuse = indirect; // reuse smallest suitable chunk
132 if (s == size) {
133 break; // perfect match, exit early
134 }
135 } else if (reclaim == NULL || (*reclaim)->size < s) {
136 reclaim = indirect; // reclaim largest unsuitable chunk
137 }
138 indirect = &(*indirect)->next;
139 }
140
141 // Select an existing chunk or allocate a new one.
142 if (reuse != NULL) {
143 // Reusing an exising chunk that's already large enough.
144 chunk = *reuse;
145 *reuse = chunk->next; // remove chunk from available list.
146 } else if (reclaim != NULL) {
147 // Reclaiming an existing chunk (resize will happen outside crit. region).
148 chunk = *reclaim;
149 *reclaim = chunk->next; // remove chunk from available list.
150 } else {
151 // Found no available chunk, allocate a new one.
152 chunk = calloc(1, sizeof(dbm_memchunk_t));
153 assert(chunk != NULL);
154 }
155 }
156
157 // Resize chunk outside of critical region before adding it to allocated list.
158 if (chunk->size < size) {
159 actual_free(chunk->mem, on_device);
160 chunk->mem = actual_malloc(size, on_device);
161 chunk->size = size;
162 }
163
164 chunk->used = size; // for statistics
165
166 // Insert chunk into allocated list.
167#pragma omp critical(dbm_mempool_modify)
168 {
169 chunk->next = pool->allocated_head;
170 pool->allocated_head = chunk;
171 }
172
173 return chunk->mem;
174}
175
176/*******************************************************************************
177 * \brief Internal routine for allocating host memory from the pool.
178 * \author Ole Schuett
179 ******************************************************************************/
180void *dbm_mempool_host_malloc(const size_t size) {
181 return internal_mempool_malloc(&mempool_host, size, false);
182}
183
184/*******************************************************************************
185 * \brief Internal routine for allocating device memory from the pool
186 * \author Ole Schuett
187 ******************************************************************************/
188void *dbm_mempool_device_malloc(const size_t size) {
189 return internal_mempool_malloc(&mempool_device, size, true);
190}
191
192/*******************************************************************************
193 * \brief Private routine for releasing memory back to the pool.
194 * \author Ole Schuett
195 ******************************************************************************/
196static void internal_mempool_free(dbm_mempool_t *pool, const void *mem) {
197 if (mem == NULL) {
198 return;
199 }
200
201#pragma omp critical(dbm_mempool_modify)
202 {
203 // Find chunk in allocated list.
204 dbm_memchunk_t **indirect = &pool->allocated_head;
205 while (*indirect != NULL && (*indirect)->mem != mem) {
206 indirect = &(*indirect)->next;
207 }
208 dbm_memchunk_t *chunk = *indirect;
209 assert(chunk != NULL && chunk->mem == mem);
210
211 // Remove chunk from allocated list.
212 *indirect = chunk->next;
213
214 // Add chunk to available list.
215 chunk->next = pool->available_head;
216 pool->available_head = chunk;
217 }
218}
219
220/*******************************************************************************
221 * \brief Internal routine for releasing memory back to the pool.
222 * \author Ole Schuett
223 ******************************************************************************/
224void dbm_mempool_host_free(const void *memory) {
226}
227
228/*******************************************************************************
229 * \brief Internal routine for releasing memory back to the pool.
230 * \author Ole Schuett
231 ******************************************************************************/
232void dbm_mempool_device_free(const void *memory) {
234}
235
236/*******************************************************************************
237 * \brief Private routine for freeing all memory in the pool.
238 * \author Ole Schuett
239 ******************************************************************************/
240static void internal_mempool_clear(dbm_mempool_t *pool, const bool on_device) {
241#pragma omp critical(dbm_mempool_modify)
242 {
243 // Check for leaks, i.e. that the allocated list is empty.
244 assert(pool->allocated_head == NULL);
245
246 // Free all chunks in available list.
247 while (pool->available_head != NULL) {
248 dbm_memchunk_t *chunk = pool->available_head;
249 pool->available_head = chunk->next; // remove chunk
250 actual_free(chunk->mem, on_device);
251 free(chunk);
252 }
253 }
254}
255
256/*******************************************************************************
257 * \brief Internal routine for freeing all memory in the pool.
258 * \author Ole Schuett
259 ******************************************************************************/
264
265/*******************************************************************************
266 * \brief Private routine for summing alloc sizes of all chunks in given list.
267 * \author Ole Schuett
268 ******************************************************************************/
269static uint64_t sum_chunks_size(const dbm_memchunk_t *head) {
270 uint64_t size_sum = 0;
271 for (const dbm_memchunk_t *chunk = head; chunk != NULL; chunk = chunk->next) {
272 size_sum += chunk->size;
273 }
274 return size_sum;
275}
276
277/*******************************************************************************
278 * \brief Private routine for summing used sizes of all chunks in given list.
279 * \author Ole Schuett
280 ******************************************************************************/
281static uint64_t sum_chunks_used(const dbm_memchunk_t *head) {
282 uint64_t used_sum = 0;
283 for (const dbm_memchunk_t *chunk = head; chunk != NULL; chunk = chunk->next) {
284 used_sum += chunk->used;
285 }
286 return used_sum;
287}
288
289/*******************************************************************************
290 * \brief Internal routine to query statistics.
291 * \author Hans Pabst
292 ******************************************************************************/
310
311// EOF
static dbm_mempool_t mempool_host
Private pools for host and device memory.
Definition dbm_mempool.c:44
static uint64_t sum_chunks_used(const dbm_memchunk_t *head)
Private routine for summing used sizes of all chunks in given list.
void dbm_mempool_device_free(const void *memory)
Internal routine for releasing memory back to the pool.
static dbm_mempool_t mempool_device
Definition dbm_mempool.c:44
static void actual_free(void *memory, const bool on_device)
Private routine for actually freeing system memory.
Definition dbm_mempool.c:92
void dbm_mempool_statistics(dbm_memstats_t *memstats)
Internal routine to query statistics.
void * dbm_mempool_host_malloc(const size_t size)
Internal routine for allocating host memory from the pool.
void dbm_mempool_host_free(const void *memory)
Internal routine for releasing memory back to the pool.
void dbm_mempool_clear(void)
Internal routine for freeing all memory in the pool.
struct dbm_memchunk dbm_memchunk_t
Private struct for storing a chunk of memory.
static uint64_t sum_chunks_size(const dbm_memchunk_t *head)
Private routine for summing alloc sizes of all chunks in given list.
static uint64_t host_malloc_counter
Private some counters for statistics.
Definition dbm_mempool.c:50
static void internal_mempool_clear(dbm_mempool_t *pool, const bool on_device)
Private routine for freeing all memory in the pool.
static void * internal_mempool_malloc(dbm_mempool_t *pool, const size_t size, const bool on_device)
Private routine for allocating host or device memory from the pool.
static void * actual_malloc(const size_t size, const bool on_device)
Private routine for actually allocating system memory.
Definition dbm_mempool.c:56
void * dbm_mempool_device_malloc(const size_t size)
Internal routine for allocating device memory from the pool.
static void internal_mempool_free(dbm_mempool_t *pool, const void *mem)
Private routine for releasing memory back to the pool.
static uint64_t device_malloc_counter
Definition dbm_mempool.c:50
struct dbm_mempool dbm_mempool_t
Private struct for storing a memory pool.
void dbm_mpi_free_mem(void *mem)
Wrapper around MPI_Free_mem.
Definition dbm_mpi.c:499
void * dbm_mpi_alloc_mem(size_t size)
Wrapper around MPI_Alloc_mem.
Definition dbm_mpi.c:483
Private struct for storing a chunk of memory.
Definition dbm_mempool.c:26
struct dbm_memchunk * next
Definition dbm_mempool.c:28
Private struct for storing a memory pool.
Definition dbm_mempool.c:36
dbm_memchunk_t * allocated_head
Definition dbm_mempool.c:37
dbm_memchunk_t * available_head
Definition dbm_mempool.c:37
Internal struct for pool statistics.
Definition dbm_mempool.h:50
uint64_t host_size
Definition dbm_mempool.h:54
uint64_t device_used
Definition dbm_mempool.h:52
uint64_t host_mallocs
Definition dbm_mempool.h:56
uint64_t host_used
Definition dbm_mempool.h:52
uint64_t device_mallocs
Definition dbm_mempool.h:56
uint64_t device_size
Definition dbm_mempool.h:54