LCOV - code coverage report
Current view: top level - src/dbm - dbm_mempool.c (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 55 58 94.8 %
Date: 2024-12-21 06:28:57 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*----------------------------------------------------------------------------*/
       2             : /*  CP2K: A general program to perform molecular dynamics simulations         */
       3             : /*  Copyright 2000-2024 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 <stddef.h>
      11             : #include <stdio.h>
      12             : #include <stdlib.h>
      13             : 
      14             : #include "../offload/offload_library.h"
      15             : #include "../offload/offload_runtime.h"
      16             : #include "dbm_mempool.h"
      17             : #include "dbm_mpi.h"
      18             : 
      19             : /*******************************************************************************
      20             :  * \brief Private routine for actually allocating system memory.
      21             :  * \author Ole Schuett
      22             :  ******************************************************************************/
      23        6170 : static void *actual_malloc(const size_t size, const bool on_device) {
      24        6170 :   (void)on_device; // mark used
      25             : 
      26             : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
      27             :   if (on_device) {
      28             :     void *memory;
      29             :     offload_activate_chosen_device();
      30             :     offloadMalloc(&memory, size);
      31             :     assert(memory != NULL);
      32             :     return memory;
      33             :   }
      34             : #else
      35        6170 :   (void)on_device; // mark used
      36             : #endif
      37             : 
      38        6170 :   void *memory = dbm_mpi_alloc_mem(size);
      39        6170 :   assert(memory != NULL);
      40        6170 :   return memory;
      41             : }
      42             : 
      43             : /*******************************************************************************
      44             :  * \brief Private routine for actually freeing system memory.
      45             :  * \author Ole Schuett
      46             :  ******************************************************************************/
      47        7818 : static void actual_free(void *memory, const bool on_device) {
      48        7818 :   if (memory == NULL) {
      49             :     return;
      50             :   }
      51             : 
      52             : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_DBM)
      53             :   if (on_device) {
      54             :     offload_activate_chosen_device();
      55             :     offloadFree(memory);
      56             :     return;
      57             :   }
      58             : #else
      59        6170 :   (void)on_device; // mark used
      60             : #endif
      61             : 
      62        6170 :   dbm_mpi_free_mem(memory);
      63             : }
      64             : 
      65             : /*******************************************************************************
      66             :  * \brief Private struct for storing a chunk of memory.
      67             :  * \author Ole Schuett
      68             :  ******************************************************************************/
      69             : struct dbm_memchunk {
      70             :   bool on_device;
      71             :   size_t size;
      72             :   void *mem;
      73             :   struct dbm_memchunk *next;
      74             : };
      75             : typedef struct dbm_memchunk dbm_memchunk_t;
      76             : 
      77             : /*******************************************************************************
      78             :  * \brief Private linked list of memory chunks that are available.
      79             :  * \author Ole Schuett
      80             :  ******************************************************************************/
      81             : static dbm_memchunk_t *mempool_available_head = NULL;
      82             : 
      83             : /*******************************************************************************
      84             :  * \brief Private linked list of memory chunks that are in use.
      85             :  * \author Ole Schuett
      86             :  ******************************************************************************/
      87             : static dbm_memchunk_t *mempool_allocated_head = NULL;
      88             : 
      89             : /*******************************************************************************
      90             :  * \brief Private routine for allocating host or device memory from the pool.
      91             :  * \author Ole Schuett
      92             :  ******************************************************************************/
      93     1233578 : static void *internal_mempool_malloc(const size_t size, const bool on_device) {
      94     1233578 :   if (size == 0) {
      95             :     return NULL;
      96             :   }
      97             : 
      98     1155150 :   dbm_memchunk_t *chunk;
      99             : 
     100     2310300 : #pragma omp critical(dbm_mempool_modify)
     101             :   {
     102             :     // Find a suitable chuck in mempool_available.
     103     1155150 :     dbm_memchunk_t **indirect = &mempool_available_head;
     104     1155150 :     while (*indirect != NULL && (*indirect)->on_device != on_device) {
     105           0 :       indirect = &(*indirect)->next;
     106             :     }
     107     1155150 :     chunk = *indirect;
     108             : 
     109             :     // If a chunck was found, remove it from mempool_available.
     110     1155150 :     if (chunk != NULL) {
     111     1153502 :       assert(chunk->on_device == on_device);
     112     1153502 :       *indirect = chunk->next;
     113             :     }
     114             : 
     115             :     // If no chunk was found, allocate a new one.
     116     1153502 :     if (chunk == NULL) {
     117        1648 :       chunk = malloc(sizeof(dbm_memchunk_t));
     118        1648 :       assert(chunk != NULL);
     119        1648 :       chunk->on_device = on_device;
     120        1648 :       chunk->size = 0;
     121        1648 :       chunk->mem = NULL;
     122             :     }
     123             : 
     124             :     // Resize chunk if needed.
     125     1155150 :     if (chunk->size < size) {
     126        6170 :       actual_free(chunk->mem, chunk->on_device);
     127        6170 :       chunk->mem = actual_malloc(size, chunk->on_device);
     128        6170 :       chunk->size = size;
     129             :     }
     130             : 
     131             :     // Insert chunk into mempool_allocated.
     132     1155150 :     chunk->next = mempool_allocated_head;
     133     1155150 :     mempool_allocated_head = chunk;
     134             :   }
     135             : 
     136     1155150 :   return chunk->mem;
     137             : }
     138             : 
     139             : /*******************************************************************************
     140             :  * \brief Internal routine for allocating host memory from the pool.
     141             :  * \author Ole Schuett
     142             :  ******************************************************************************/
     143     1233578 : void *dbm_mempool_host_malloc(const size_t size) {
     144     1233578 :   return internal_mempool_malloc(size, false);
     145             : }
     146             : 
     147             : /*******************************************************************************
     148             :  * \brief Internal routine for allocating device memory from the pool
     149             :  * \author Ole Schuett
     150             :  ******************************************************************************/
     151           0 : void *dbm_mempool_device_malloc(const size_t size) {
     152           0 :   return internal_mempool_malloc(size, true);
     153             : }
     154             : 
     155             : /*******************************************************************************
     156             :  * \brief Internal routine for releasing memory back to the pool.
     157             :  * \author Ole Schuett
     158             :  ******************************************************************************/
     159     1233578 : void dbm_mempool_free(void *mem) {
     160     1233578 :   if (mem == NULL) {
     161             :     return;
     162             :   }
     163             : 
     164     2310300 : #pragma omp critical(dbm_mempool_modify)
     165             :   {
     166             :     // Find chuck in mempool_allocated.
     167     1155150 :     dbm_memchunk_t **indirect = &mempool_allocated_head;
     168     2359557 :     while (*indirect != NULL && (*indirect)->mem != mem) {
     169     1204407 :       indirect = &(*indirect)->next;
     170             :     }
     171     1155150 :     dbm_memchunk_t *chunk = *indirect;
     172     1155150 :     assert(chunk != NULL && chunk->mem == mem);
     173             : 
     174             :     // Remove chuck from mempool_allocated.
     175     1155150 :     *indirect = chunk->next;
     176             : 
     177             :     // Add chuck to mempool_available.
     178     1155150 :     chunk->next = mempool_available_head;
     179     1155150 :     mempool_available_head = chunk;
     180             :   }
     181             : }
     182             : 
     183             : /*******************************************************************************
     184             :  * \brief Internal routine for freeing all memory in the pool.
     185             :  * \author Ole Schuett
     186             :  ******************************************************************************/
     187        9178 : void dbm_mempool_clear(void) {
     188        9178 :   assert(omp_get_num_threads() == 1);
     189        9178 :   assert(mempool_allocated_head == NULL); // check for memory leak
     190             : 
     191             :   // while (mempool_allocated_head != NULL) {
     192             :   //  dbm_memchunk_t *chunk = mempool_allocated_head;
     193             :   //  mempool_allocated_head = chunk->next;
     194             :   //  printf("Found alloacted memory chunk of size: %lu\n", chunk->size);
     195             :   //  actual_free(chunk->mem, chunk->on_device);
     196             :   //  free(chunk);
     197             :   //}
     198             : 
     199             :   // Free chunks in mempool_avavailable.
     200       10826 :   while (mempool_available_head != NULL) {
     201        1648 :     dbm_memchunk_t *chunk = mempool_available_head;
     202        1648 :     mempool_available_head = chunk->next;
     203        1648 :     actual_free(chunk->mem, chunk->on_device);
     204        1648 :     free(chunk);
     205             :   }
     206        9178 : }
     207             : 
     208             : // EOF

Generated by: LCOV version 1.15