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

Generated by: LCOV version 1.15