added Verlet scheme and NxN non-bonded functionality
[gromacs.git] / src / gmxlib / smalloc.c
blob8a78196c2c7cda42d14ddc49a75c71cc0c4c9fa2
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 * VERSION 3.2.0
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * GROningen Mixture of Alchemy and Childrens' Stories
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 /* This file is completely threadsafe - keep it that way! */
41 #ifdef GMX_THREAD_MPI
42 #include "thread_mpi/threads.h"
43 #endif
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "gmx_fatal.h"
50 #include "smalloc.h"
51 #include "main.h"
52 #ifdef WITH_DMALLOC
53 #include "dmalloc.h"
54 #endif
56 #ifdef DEBUG
57 static void log_action(int bMal,const char *what,const char *file,int line,
58 int nelem,int size,void *ptr)
60 static int btot=0;
61 char *NN = "NULL";
62 int bytes;
64 bytes=size*nelem;
65 if (!bMal)
66 bytes=-bytes;
68 #ifdef GMX_THREAD_MPI
69 tMPI_Thread_mutex_lock(&gmx_logfile_mtx);
70 #endif
72 /* This total memory count is not correct, since with realloc
73 * it adds the whole size again, not just the increment.
75 /* This static variable is protected by the mutex too... */
76 btot+=bytes;
78 bytes/=1024;
79 if (debug && (bytes != 0)) {
80 fprintf(debug,"%s:%d kB (%7d kB) [%s, line %d, nelem %d, size %d]\n",
81 what ? what : NN,bytes,btot/1024,
82 file ? file : NN,line,nelem,size);
84 /* Print to stderr for things larger than 1 MB */
85 if (bytes >= 1024 || bytes <= -1024) {
86 char *fname=NULL;
87 if (file) {
88 fname = strrchr(file,DIR_SEPARATOR);
89 if (fname) {
90 fname++;
91 } else {
92 fname = file;
95 printf("%s: %.1f MB [%s, line %d, nelem %d, size %d]\n",
96 what ? what : NN,bytes/1024.0,
97 file ? fname : NN,line,nelem,size);
99 #ifdef GMX_THREAD_MPI
100 tMPI_Thread_mutex_unlock(&gmx_logfile_mtx);
101 #endif
103 #endif
105 static char *gmx_large_int_str(gmx_large_int_t i,char *buf)
107 sprintf(buf,gmx_large_int_pfmt,i);
109 return buf;
112 void *save_malloc(const char *name,const char *file,int line,size_t size)
114 void *p;
116 p=NULL;
117 if (size==0)
118 p=NULL;
119 else
121 if ((p=malloc(size))==NULL) {
122 char cbuf[22];
123 gmx_fatal(errno,__FILE__,__LINE__,
124 "Not enough memory. Failed to malloc %s bytes for %s\n"
125 "(called from file %s, line %d)",
126 gmx_large_int_str((gmx_large_int_t)size,cbuf),
127 name,file,line);
129 (void) memset(p,0,size);
131 #ifdef DEBUG
132 log_action(1,name,file,line,1,size,p);
133 #endif
134 return p;
137 void *save_calloc(const char *name,const char *file,int line,
138 size_t nelem,size_t elsize)
140 void *p;
142 p=NULL;
143 if ((nelem==0)||(elsize==0))
144 p=NULL;
145 else
147 #ifdef PRINT_ALLOC_KB
148 int rank=0;
149 if (nelem*elsize >= PRINT_ALLOC_KB*1024) {
150 #ifdef GMX_MPI
151 #include <mpi.h>
152 MPI_Comm_rank(MPI_COMM_WORLD,&rank);
153 #endif
154 printf("Allocating %.1f MB for %s (called from file %s, line %d on %d)\n",
155 nelem*elsize/1048576.0,name,file,line,rank);
157 #endif
158 #ifdef GMX_BROKEN_CALLOC
159 /* emulate calloc(3) with malloc/memset on machines with
160 a broken calloc, e.g. in -lgmalloc on cray xt3. */
161 if ((p=malloc((size_t)nelem*(size_t)elsize))==NULL)
162 gmx_fatal(errno,__FILE__,__LINE__,
163 "Not enough memory. Failed to calloc %"gmx_large_int_fmt
164 " elements of size %"gmx_large_int_fmt
165 " for %s\n(called from file %s, line %d)",
166 (gmx_large_int_t)nelem,(gmx_large_int_t)elsize,
167 name,file,line);
168 memset(p, 0,(size_t) (nelem * elsize));
169 #else
170 if ((p=calloc((size_t)nelem,(size_t)elsize))==NULL)
171 gmx_fatal(errno,__FILE__,__LINE__,
172 "Not enough memory. Failed to calloc %"gmx_large_int_fmt
173 " elements of size %"gmx_large_int_fmt
174 " for %s\n(called from file %s, line %d)",
175 (gmx_large_int_t)nelem,(gmx_large_int_t)elsize,name,file,line);
176 #endif
178 #ifdef DEBUG
179 log_action(1,name,file,line,nelem,elsize,p);
180 #endif
181 return p;
184 void *save_realloc(const char *name,const char *file,int line,void *ptr,
185 size_t nelem,size_t elsize)
187 void *p;
188 size_t size = nelem*elsize;
190 p=NULL;
191 if (size==0)
193 save_free(name, file, line, ptr);
195 else
197 #ifdef PRINT_ALLOC_KB
198 int rank=0;
199 if (size >= PRINT_ALLOC_KB*1024) {
200 #ifdef GMX_MPI
201 #include <mpi.h>
202 MPI_Comm_rank(MPI_COMM_WORLD,&rank);
203 #endif
204 printf("Reallocating %.1f MB for %s (called from file %s, line %d on %d)\n",
205 size/1048576.0,name,file,line,rank);
207 #endif
208 if (ptr==NULL)
209 p=malloc((size_t)size);
210 else
211 p=realloc(ptr,(size_t)size);
212 if (p == NULL) {
213 char cbuf[22];
214 gmx_fatal(errno,__FILE__,__LINE__,
215 "Not enough memory. Failed to realloc %s bytes for %s, %s=%x\n"
216 "(called from file %s, line %d)",
217 gmx_large_int_str((gmx_large_int_t)size,cbuf),
218 name,name,ptr,file,line);
220 #ifdef DEBUG
221 log_action(1,name,file,line,1,size,p);
222 #endif
224 return p;
227 void save_free(const char *name,const char *file,int line, void *ptr)
229 #ifdef DEBUG
230 log_action(0,name,file,line,0,0,ptr);
231 #endif
232 if (ptr != NULL)
233 free(ptr);
236 size_t maxavail(void)
238 char *ptr;
239 size_t low,high,size;
241 low=0;
242 high=256e6;
243 while ((high-low) > 4) {
244 size=(high+low)/2;
245 if ((ptr=(char *)malloc((size_t)size))==NULL)
246 high=size;
247 else {
248 free(ptr);
249 low=size;
252 return low;
255 size_t memavail(void)
257 char *ptr;
258 size_t size;
260 size = maxavail();
261 if (size != 0) {
262 if ((ptr=(char *)malloc((size_t)size)) != NULL) {
263 size += memavail();
264 free(ptr);
267 return size;
270 /* If we don't have useful routines for allocating aligned memory,
271 * then we have to use the old-style GROMACS approach bitwise-ANDing
272 * pointers to ensure alignment. We store the pointer to the originally
273 * allocated region in the space before the returned pointer */
275 /* we create a positive define for the absence of an system-provided memalign */
276 #if (!defined HAVE_POSIX_MEMALIGN && !defined HAVE_MEMALIGN && \
277 !defined HAVE__ALIGNED_MALLOC)
278 #define GMX_OWN_MEMALIGN
279 #endif
282 /* Pointers allocated with this routine should only be freed
283 * with save_free_aligned, however this will only matter
284 * on systems that lack posix_memalign() and memalign() when
285 * freeing memory that needed to be adjusted to achieve
286 * the necessary alignment. */
287 void *save_malloc_aligned(const char *name,const char *file,int line,
288 unsigned nelem,size_t elsize,size_t alignment)
290 void **aligned=NULL;
291 void *malloced=NULL;
292 gmx_bool allocate_fail;
294 if (alignment == 0)
296 gmx_fatal(errno,__FILE__,__LINE__,
297 "Cannot allocate aligned memory with alignment of zero!\n(called from file %s, line %d)",file,line);
301 if (nelem ==0 || elsize == 0)
303 aligned = NULL;
305 else
307 #ifdef PRINT_ALLOC_KB
308 if (nelem*elsize >= PRINT_ALLOC_KB*1024)
310 printf("Allocating %.1f MB for %s\n",
311 nelem*elsize/(PRINT_ALLOC_KB*1024.0),name);
313 #endif
315 allocate_fail = FALSE; /* stop compiler warnings */
316 #ifdef HAVE_POSIX_MEMALIGN
317 allocate_fail = (0!=posix_memalign(&malloced, alignment, nelem*elsize));
318 #elif defined HAVE_MEMALIGN
319 allocate_fail = ((malloced=memalign(alignment, nelem*elsize)) == NULL);
320 #elif defined HAVE__ALIGNED_MALLOC
321 allocate_fail = ((malloced=_aligned_malloc(nelem*elsize, alignment))
322 == NULL);
323 #else
324 allocate_fail = ((malloced = malloc(nelem*elsize+alignment+
325 sizeof(void*)))==NULL);
326 #endif
327 if (allocate_fail)
329 gmx_fatal(errno,__FILE__,__LINE__,
330 "Not enough memory. Failed to allocate %u aligned elements of size %u for %s\n(called from file %s, line %d)",nelem,elsize,name,file,line);
332 /* we start with the original pointer */
333 aligned=(void**)malloced;
335 #ifdef GMX_OWN_MEMALIGN
336 /* Make the aligned pointer, and save the underlying pointer that
337 * we're allowed to free(). */
339 /* we first make space to store that underlying pointer: */
340 aligned = aligned + 1;
341 /* then we apply a bit mask */
342 aligned = (void *) (((size_t) aligned + alignment - 1) &
343 (~((size_t) (alignment-1))));
344 /* and we store the original pointer in the area just before the
345 pointer we're going to return */
346 aligned[-1] = malloced;
347 #endif
349 return (void*)aligned;
352 void *save_calloc_aligned(const char *name,const char *file,int line,
353 unsigned nelem,size_t elsize,size_t alignment)
355 void *aligned = save_malloc_aligned(name, file, line, nelem, elsize, alignment);
356 if (aligned != NULL)
358 memset(aligned, 0, (size_t)(nelem * elsize));
360 return aligned;
363 /* This routine can NOT be called with any pointer */
364 void save_free_aligned(const char *name,const char *file,int line,void *ptr)
366 int i, j;
367 void *free=ptr;
369 if (NULL != ptr)
371 #ifdef GMX_OWN_MEMALIGN
372 /* we get the pointer from just before the memaligned pointer */
373 free= ((void**)ptr)[-1];
374 #endif
376 #ifndef HAVE__ALIGNED_MALLOC
377 /* (Now) we're allowed to use a normal free() on this pointer. */
378 save_free(name,file,line,free);
379 #else
380 _aligned_free(free);
381 #endif