32d8aa0ebbb4815f02289e82ee070f609a8eae5a
[alexxy/gromacs.git] / src / gmxlib / selection / mempool.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief Memory pooling for selection evaluation.
33  *
34  * \todo
35  * Document these functions.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <assert.h>
42 #include <stdlib.h>
43
44 #include <gmx_fatal.h>
45 #include <smalloc.h>
46
47 #include <indexutil.h>
48
49 #include "mempool.h"
50
51 #define ALIGN_STEP 8
52
53 typedef struct gmx_sel_mempool_block_t
54 {
55     void                       *ptr;
56     size_t                      size;
57 } gmx_sel_mempool_block_t;
58
59 struct gmx_sel_mempool_t
60 {
61     size_t                      currsize;
62     size_t                      freesize;
63     char                       *buffer;
64     char                       *freeptr;
65     int                         nblocks;
66     gmx_sel_mempool_block_t    *blockstack;
67     int                         blockstack_nalloc;
68     size_t                      maxsize;
69 };
70
71 int
72 _gmx_sel_mempool_create(gmx_sel_mempool_t **mpp)
73 {
74     gmx_sel_mempool_t *mp;
75
76     snew(mp, 1);
77     mp->currsize          = 0;
78     mp->freesize          = 0;
79     mp->buffer            = NULL;
80     mp->freeptr           = NULL;
81     mp->nblocks           = 0;
82     mp->blockstack        = NULL;
83     mp->blockstack_nalloc = 0;
84     mp->maxsize           = 0;
85     *mpp = mp;
86     return 0;
87 }
88
89 void
90 _gmx_sel_mempool_destroy(gmx_sel_mempool_t *mp)
91 {
92     if (!mp->buffer)
93     {
94         int  i;
95
96         for (i = 0; i < mp->nblocks; ++i)
97         {
98             sfree(mp->blockstack[i].ptr);
99         }
100     }
101     sfree(mp->buffer);
102     sfree(mp->blockstack);
103     sfree(mp);
104 }
105
106 int
107 _gmx_sel_mempool_alloc(gmx_sel_mempool_t *mp, void **ptrp, size_t size)
108 {
109     void   *ptr = NULL;
110     size_t  size_walign;
111
112     *ptrp = NULL;
113     size_walign = ((size + ALIGN_STEP - 1) / ALIGN_STEP) * ALIGN_STEP;
114     if (mp->buffer)
115     {
116         if (mp->freesize < size)
117         {
118             gmx_bug("out of memory pool memory");
119             return ENOMEM;
120         }
121         ptr = mp->freeptr;
122         mp->freeptr  += size_walign;
123         mp->freesize -= size_walign;
124         mp->currsize += size_walign;
125     }
126     else
127     {
128         ptr = malloc(size);
129         if (!ptr)
130         {
131             gmx_mem("out of memory");
132             return ENOMEM;
133         }
134         mp->currsize += size_walign;
135         if (mp->currsize > mp->maxsize)
136         {
137             mp->maxsize = mp->currsize;
138         }
139     }
140
141     if (mp->nblocks >= mp->blockstack_nalloc)
142     {
143         mp->blockstack_nalloc = mp->nblocks + 10;
144         srenew(mp->blockstack, mp->blockstack_nalloc);
145     }
146     mp->blockstack[mp->nblocks].ptr  = ptr;
147     mp->blockstack[mp->nblocks].size = size_walign;
148     mp->nblocks++;
149
150     *ptrp = ptr;
151     return 0;
152 }
153
154 void
155 _gmx_sel_mempool_free(gmx_sel_mempool_t *mp, void *ptr)
156 {
157     int size;
158
159     if (ptr == NULL)
160     {
161         return;
162     }
163     assert(mp->nblocks > 0 && mp->blockstack[mp->nblocks - 1].ptr == ptr);
164     mp->nblocks--;
165     size = mp->blockstack[mp->nblocks].size;
166     mp->currsize -= size;
167     if (mp->buffer)
168     {
169         mp->freeptr = (char *)ptr;
170         mp->freesize += size;
171     }
172     else
173     {
174         sfree(ptr);
175     }
176 }
177
178 int
179 _gmx_sel_mempool_reserve(gmx_sel_mempool_t *mp, size_t size)
180 {
181     assert(mp->nblocks == 0 && !mp->buffer);
182     if (size == 0)
183     {
184         size = mp->maxsize;
185     }
186     mp->buffer = (char *)malloc(size);
187     if (!mp->buffer)
188     {
189         gmx_mem("out of memory");
190         return ENOMEM;
191     }
192     mp->freesize = size;
193     mp->freeptr  = mp->buffer;
194     return 0;
195 }
196
197 int
198 _gmx_sel_mempool_alloc_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g,
199                              int isize)
200 {
201     return _gmx_sel_mempool_alloc(mp, (void **)&g->index,
202                                   sizeof(*g->index)*isize);
203 }
204
205 void
206 _gmx_sel_mempool_free_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g)
207 {
208     _gmx_sel_mempool_free(mp, g->index);
209     g->index = NULL;
210 }