src/grid/mempool.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    
    /* A memory pool implementation for fixed-size blocks 
       It uses Simple Segregated Storage, see e.g:
       http://www.boost.org/doc/libs/1_55_0/libs/pool/doc/html/boost_pool/pool/pooling.html
    */
    
    typedef struct _Pool Pool;
    
    struct _Pool {
      Pool * next; // next pool
    };
    
    typedef struct {
      char * first, * lastb; // first and last free blocks
      size_t size;           // block size
      size_t poolsize;       // pool size
      Pool * pool, * last;   // first and last pools
    } Mempool;
    
    typedef struct {
      char * next;
    } FreeBlock;
    
    Mempool * mempool_new (size_t poolsize, size_t size)
    {
      // check for 64 bytes alignment
      assert (poolsize % 8 == 0);
      assert (size >= sizeof(FreeBlock));
      // to get the effective pool size, we cap this amount to 2^20 = 1MB
      // i.e. something comparable to the size of a L2 cache
      poolsize = min(1 << 20, poolsize + sizeof(Pool));
      Mempool * m = qcalloc (1, Mempool);
      m->poolsize = poolsize;
      m->size = size;
      return m;
    }
    
    void mempool_destroy (Mempool * m)
    {
      Pool * p = m->pool;
      while (p) {
        Pool * next = p->next;
        free (p);
        p = next;
      }
      free (m);
    }
    
    void * mempool_alloc (Mempool * m)
    {
      if (!m->first) {
        // allocate new pool
        Pool * p = (Pool *) malloc (m->poolsize);
        p->next = NULL;
        if (m->last)
          m->last->next = p;
        else
          m->pool = p;
        m->last = p;
        m->first = m->lastb = ((char *)m->last) + sizeof(Pool);
        FreeBlock * b = (FreeBlock *) m->first;
        b->next = NULL;
      }
      void * ret = m->first;
      FreeBlock * b = (FreeBlock *) ret;
      char * next = b->next;
      if (!next) {
        m->lastb += m->size;
        next = m->lastb;
        if (next + m->size > ((char *) m->last) + m->poolsize)
          next = NULL;
        else {
          FreeBlock * b = (FreeBlock *) next;
          b->next = NULL;
        }
      }
      m->first = next;
    @if TRASH
      double * v = (double *) ret;
      for (int i = 0; i < m->size/sizeof(double); i++)
        v[i] = undefined;
    @endif
      return ret;
    }
    
    void * mempool_alloc0 (Mempool * m)
    {
      void * ret = mempool_alloc (m);
      memset (ret, 0, m->size);
      return ret;
    }
    
    void mempool_free (Mempool * m, void * p)
    {
    @if TRASH
      double * v = (double *) p;
      for (int i = 0; i < m->size/sizeof(double); i++)
        v[i] = undefined;
    @endif
      FreeBlock * b = (FreeBlock *) p;
      b->next = m->first;
      m->first = (char *) p;
    }