Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / gmxlib / smalloc.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  *                        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.
14
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.
19  *
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.
26  *
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.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 /* This file is completely threadsafe - keep it that way! */
40
41 #ifdef GMX_THREAD_MPI
42 #include "thread_mpi/threads.h"
43 #endif
44
45
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
55
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)
59 {
60     static int btot = 0;
61     char      *NN   = "NULL";
62     int        bytes;
63
64     bytes = size*nelem;
65     if (!bMal)
66     {
67         bytes = -bytes;
68     }
69
70 #ifdef GMX_THREAD_MPI
71     tMPI_Thread_mutex_lock(&gmx_logfile_mtx);
72 #endif
73
74     /* This total memory count is not correct, since with realloc
75      * it adds the whole size again, not just the increment.
76      */
77     /* This static variable is protected by the mutex too... */
78     btot += bytes;
79
80     bytes /= 1024;
81     if (debug && (bytes != 0))
82     {
83         fprintf(debug, "%s:%d kB (%7d kB) [%s, line %d, nelem %d, size %d]\n",
84                 what ? what : NN, bytes, btot/1024,
85                 file ? file : NN, line, nelem, size);
86     }
87     /* Print to stderr for things larger than 1 MB */
88     if (bytes >= 1024 || bytes <= -1024)
89     {
90         char *fname = NULL;
91         if (file)
92         {
93             fname = strrchr(file, DIR_SEPARATOR);
94             if (fname)
95             {
96                 fname++;
97             }
98             else
99             {
100                 fname = file;
101             }
102         }
103         printf("%s: %.1f MB [%s, line %d, nelem %d, size %d]\n",
104                what ? what  : NN, bytes/1024.0,
105                file ? fname : NN, line, nelem, size);
106     }
107 #ifdef GMX_THREAD_MPI
108     tMPI_Thread_mutex_unlock(&gmx_logfile_mtx);
109 #endif
110 }
111 #endif
112
113 static char *gmx_large_int_str(gmx_large_int_t i, char *buf)
114 {
115     sprintf(buf, gmx_large_int_pfmt, i);
116
117     return buf;
118 }
119
120 void *save_malloc(const char *name, const char *file, int line, size_t size)
121 {
122     void *p;
123
124     p = NULL;
125     if (size == 0)
126     {
127         p = NULL;
128     }
129     else
130     {
131         if ((p = malloc(size)) == NULL)
132         {
133             char cbuf[22];
134             gmx_fatal(errno, __FILE__, __LINE__,
135                       "Not enough memory. Failed to malloc %s bytes for %s\n"
136                       "(called from file %s, line %d)",
137                       gmx_large_int_str((gmx_large_int_t)size, cbuf),
138                       name, file, line);
139         }
140         (void) memset(p, 0, size);
141     }
142 #ifdef DEBUG
143     log_action(1, name, file, line, 1, size, p);
144 #endif
145     return p;
146 }
147
148 void *save_calloc(const char *name, const char *file, int line,
149                   size_t nelem, size_t elsize)
150 {
151     void *p;
152
153     p = NULL;
154     if ((nelem == 0) || (elsize == 0))
155     {
156         p = NULL;
157     }
158     else
159     {
160 #ifdef PRINT_ALLOC_KB
161         int rank = 0;
162         if (nelem*elsize >= PRINT_ALLOC_KB*1024)
163         {
164 #ifdef GMX_MPI
165 #include <mpi.h>
166             MPI_Comm_rank(MPI_COMM_WORLD, &rank);
167 #endif
168             printf("Allocating %.1f MB for %s (called from file %s, line %d on %d)\n",
169                    nelem*elsize/1048576.0, name, file, line, rank);
170         }
171 #endif
172 #ifdef GMX_BROKEN_CALLOC
173         /* emulate calloc(3) with malloc/memset on machines with
174            a broken calloc, e.g. in -lgmalloc on cray xt3. */
175         if ((p = malloc((size_t)nelem*(size_t)elsize)) == NULL)
176         {
177             gmx_fatal(errno, __FILE__, __LINE__,
178                       "Not enough memory. Failed to calloc %"gmx_large_int_fmt
179                       " elements of size %"gmx_large_int_fmt
180                       " for %s\n(called from file %s, line %d)",
181                       (gmx_large_int_t)nelem, (gmx_large_int_t)elsize,
182                       name, file, line);
183         }
184         memset(p, 0, (size_t) (nelem * elsize));
185 #else
186         if ((p = calloc((size_t)nelem, (size_t)elsize)) == NULL)
187         {
188             gmx_fatal(errno, __FILE__, __LINE__,
189                       "Not enough memory. Failed to calloc %"gmx_large_int_fmt
190                       " elements of size %"gmx_large_int_fmt
191                       " for %s\n(called from file %s, line %d)",
192                       (gmx_large_int_t)nelem, (gmx_large_int_t)elsize, name, file, line);
193         }
194 #endif
195     }
196 #ifdef DEBUG
197     log_action(1, name, file, line, nelem, elsize, p);
198 #endif
199     return p;
200 }
201
202 void *save_realloc(const char *name, const char *file, int line, void *ptr,
203                    size_t nelem, size_t elsize)
204 {
205     void  *p;
206     size_t size = nelem*elsize;
207
208     p = NULL;
209     if (size == 0)
210     {
211         save_free(name, file, line, ptr);
212     }
213     else
214     {
215 #ifdef PRINT_ALLOC_KB
216         int rank = 0;
217         if (size >= PRINT_ALLOC_KB*1024)
218         {
219 #ifdef GMX_MPI
220 #include <mpi.h>
221             MPI_Comm_rank(MPI_COMM_WORLD, &rank);
222 #endif
223             printf("Reallocating %.1f MB for %s (called from file %s, line %d on %d)\n",
224                    size/1048576.0, name, file, line, rank);
225         }
226 #endif
227         if (ptr == NULL)
228         {
229             p = malloc((size_t)size);
230         }
231         else
232         {
233             p = realloc(ptr, (size_t)size);
234         }
235         if (p == NULL)
236         {
237             char cbuf[22];
238             gmx_fatal(errno, __FILE__, __LINE__,
239                       "Not enough memory. Failed to realloc %s bytes for %s, %s=%x\n"
240                       "(called from file %s, line %d)",
241                       gmx_large_int_str((gmx_large_int_t)size, cbuf),
242                       name, name, ptr, file, line);
243         }
244 #ifdef DEBUG
245         log_action(1, name, file, line, 1, size, p);
246 #endif
247     }
248     return p;
249 }
250
251 void save_free(const char *name, const char *file, int line, void *ptr)
252 {
253 #ifdef DEBUG
254     log_action(0, name, file, line, 0, 0, ptr);
255 #endif
256     if (ptr != NULL)
257     {
258         free(ptr);
259     }
260 }
261
262 size_t maxavail(void)
263 {
264     char  *ptr;
265     size_t low, high, size;
266
267     low  = 0;
268     high = 256e6;
269     while ((high-low) > 4)
270     {
271         size = (high+low)/2;
272         if ((ptr = (char *)malloc((size_t)size)) == NULL)
273         {
274             high = size;
275         }
276         else
277         {
278             free(ptr);
279             low = size;
280         }
281     }
282     return low;
283 }
284
285 size_t memavail(void)
286 {
287     char  *ptr;
288     size_t size;
289
290     size = maxavail();
291     if (size != 0)
292     {
293         if ((ptr = (char *)malloc((size_t)size)) != NULL)
294         {
295             size += memavail();
296             free(ptr);
297         }
298     }
299     return size;
300 }
301
302 /* If we don't have useful routines for allocating aligned memory,
303  * then we have to use the old-style GROMACS approach bitwise-ANDing
304  * pointers to ensure alignment. We store the pointer to the originally
305  * allocated region in the space before the returned pointer */
306
307 /* we create a positive define for the absence of an system-provided memalign */
308 #if (!defined HAVE_POSIX_MEMALIGN && !defined HAVE_MEMALIGN && \
309      !defined HAVE__ALIGNED_MALLOC)
310 #define GMX_OWN_MEMALIGN
311 #endif
312
313
314 /* Pointers allocated with this routine should only be freed
315  * with save_free_aligned, however this will only matter
316  * on systems that lack posix_memalign() and memalign() when
317  * freeing memory that needed to be adjusted to achieve
318  * the necessary alignment. */
319 void *save_malloc_aligned(const char *name, const char *file, int line,
320                           unsigned nelem, size_t elsize, size_t alignment)
321 {
322     void   **aligned  = NULL;
323     void    *malloced = NULL;
324     gmx_bool allocate_fail;
325
326     if (alignment == 0)
327     {
328         gmx_fatal(errno, __FILE__, __LINE__,
329                   "Cannot allocate aligned memory with alignment of zero!\n(called from file %s, line %d)", file, line);
330     }
331
332
333     if (nelem == 0 || elsize == 0)
334     {
335         aligned  = NULL;
336     }
337     else
338     {
339 #ifdef PRINT_ALLOC_KB
340         if (nelem*elsize >= PRINT_ALLOC_KB*1024)
341         {
342             printf("Allocating %.1f MB for %s\n",
343                    nelem*elsize/(PRINT_ALLOC_KB*1024.0), name);
344         }
345 #endif
346
347         allocate_fail = FALSE; /* stop compiler warnings */
348 #ifdef HAVE_POSIX_MEMALIGN
349         allocate_fail = (0 != posix_memalign(&malloced, alignment, nelem*elsize));
350 #elif defined HAVE_MEMALIGN
351         allocate_fail = ((malloced = memalign(alignment, nelem*elsize)) == NULL);
352 #elif defined HAVE__ALIGNED_MALLOC
353         allocate_fail = ((malloced = _aligned_malloc(nelem*elsize, alignment))
354                          == NULL);
355 #else
356         allocate_fail = ((malloced = malloc(nelem*elsize+alignment+
357                                             sizeof(void*))) == NULL);
358 #endif
359         if (allocate_fail)
360         {
361             gmx_fatal(errno, __FILE__, __LINE__,
362                       "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);
363         }
364         /* we start with the original pointer */
365         aligned = (void**)malloced;
366
367 #ifdef GMX_OWN_MEMALIGN
368         /* Make the aligned pointer, and save the underlying pointer that
369          * we're allowed to free(). */
370
371         /* we first make space to store that underlying pointer: */
372         aligned = aligned + 1;
373         /* then we apply a bit mask */
374         aligned = (void *) (((size_t) aligned + alignment - 1) &
375                             (~((size_t) (alignment-1))));
376         /* and we store the original pointer in the area just before the
377            pointer we're going to return */
378         aligned[-1] = malloced;
379 #endif
380     }
381     return (void*)aligned;
382 }
383
384 void *save_calloc_aligned(const char *name, const char *file, int line,
385                           unsigned nelem, size_t elsize, size_t alignment)
386 {
387     void *aligned = save_malloc_aligned(name, file, line, nelem, elsize, alignment);
388     if (aligned != NULL)
389     {
390         memset(aligned, 0, (size_t)(nelem * elsize));
391     }
392     return aligned;
393 }
394
395 /* This routine can NOT be called with any pointer */
396 void save_free_aligned(const char *name, const char *file, int line, void *ptr)
397 {
398     int   i, j;
399     void *free = ptr;
400
401     if (NULL != ptr)
402     {
403 #ifdef GMX_OWN_MEMALIGN
404         /* we get the pointer from just before the memaligned pointer */
405         free = ((void**)ptr)[-1];
406 #endif
407
408 #ifndef HAVE__ALIGNED_MALLOC
409         /* (Now) we're allowed to use a normal free() on this pointer. */
410         save_free(name, file, line, free);
411 #else
412         _aligned_free(free);
413 #endif
414     }
415 }