1 /*!
2 \file  memory.c
3 \brief This file contains various allocation routines
4 
5 The allocation routines included are for 1D and 2D arrays of the
6 most datatypes that GKlib support. Many of these routines are
7 defined with the help of the macros in gk_memory.h. These macros
8 can be used to define other memory allocation routines.
9 
10 \date   Started 4/3/2007
11 \author George
12 \version\verbatim $Id: memory.c 10783 2011-09-21 23:19:56Z karypis $ \endverbatim
13 */
14 
15 
16 #include <GKlib.h>
17 
18 /* This is for the global mcore that tracks all heap allocations */
19 static __thread gk_mcore_t *gkmcore = NULL;
20 
21 
22 /*************************************************************************/
23 /*! Define the set of memory allocation routines for each data type */
24 /**************************************************************************/
GK_MKALLOC(gk_c,char)25 GK_MKALLOC(gk_c,   char)
26 GK_MKALLOC(gk_i,   int)
27 GK_MKALLOC(gk_i32, int32_t)
28 GK_MKALLOC(gk_i64, int64_t)
29 GK_MKALLOC(gk_z,   ssize_t)
30 GK_MKALLOC(gk_f,   float)
31 GK_MKALLOC(gk_d,   double)
32 GK_MKALLOC(gk_idx, gk_idx_t)
33 
34 GK_MKALLOC(gk_ckv,   gk_ckv_t)
35 GK_MKALLOC(gk_ikv,   gk_ikv_t)
36 GK_MKALLOC(gk_i32kv, gk_i32kv_t)
37 GK_MKALLOC(gk_i64kv, gk_i64kv_t)
38 GK_MKALLOC(gk_zkv,   gk_zkv_t)
39 GK_MKALLOC(gk_fkv,   gk_fkv_t)
40 GK_MKALLOC(gk_dkv,   gk_dkv_t)
41 GK_MKALLOC(gk_skv,   gk_skv_t)
42 GK_MKALLOC(gk_idxkv, gk_idxkv_t)
43 
44 
45 
46 
47 
48 
49 /*************************************************************************/
50 /*! This function allocates a two-dimensional matrix.
51   */
52 /*************************************************************************/
53 void gk_AllocMatrix(void ***r_matrix, size_t elmlen, size_t ndim1, size_t ndim2)
54 {
55   gk_idx_t i, j;
56   void **matrix;
57 
58   *r_matrix = NULL;
59 
60   if ((matrix = (void **)gk_malloc(ndim1*sizeof(void *), "gk_AllocMatrix: matrix")) == NULL)
61     return;
62 
63   for (i=0; i<ndim1; i++) {
64     if ((matrix[i] = (void *)gk_malloc(ndim2*elmlen, "gk_AllocMatrix: matrix[i]")) == NULL) {
65       for (j=0; j<i; j++)
66         gk_free((void **)&matrix[j], LTERM);
67       return;
68     }
69   }
70 
71   *r_matrix = matrix;
72 }
73 
74 
75 /*************************************************************************/
76 /*! This function frees a two-dimensional matrix.
77   */
78 /*************************************************************************/
gk_FreeMatrix(void *** r_matrix,size_t ndim1,size_t ndim2)79 void gk_FreeMatrix(void ***r_matrix, size_t ndim1, size_t ndim2)
80 {
81   gk_idx_t i;
82   void **matrix;
83 
84   if ((matrix = *r_matrix) == NULL)
85     return;
86 
87   for (i=0; i<ndim1; i++)
88     gk_free((void **)&matrix[i], LTERM);
89 
90   gk_free((void **)r_matrix, LTERM);
91 
92 }
93 
94 
95 /*************************************************************************/
96 /*! This function initializes tracking of heap allocations.
97 */
98 /*************************************************************************/
gk_malloc_init()99 int gk_malloc_init()
100 {
101   if (gkmcore == NULL)
102     gkmcore = gk_gkmcoreCreate();
103 
104   if (gkmcore == NULL)
105     return 0;
106 
107   gk_gkmcorePush(gkmcore);
108 
109   return 1;
110 }
111 
112 
113 /*************************************************************************/
114 /*! This function frees the memory that has been allocated since the
115     last call to gk_malloc_init().
116 */
117 /*************************************************************************/
gk_malloc_cleanup(int showstats)118 void gk_malloc_cleanup(int showstats)
119 {
120   if (gkmcore != NULL) {
121     gk_gkmcorePop(gkmcore);
122     if (gkmcore->cmop == 0) {
123       gk_gkmcoreDestroy(&gkmcore, showstats);
124       gkmcore = NULL;
125     }
126   }
127 }
128 
129 
130 /*************************************************************************/
131 /*! This function is my wrapper around malloc that provides the following
132     enhancements over malloc:
133     * It always allocates one byte of memory, even if 0 bytes are requested.
134       This is to ensure that checks of returned values do not lead to NULL
135       due to 0 bytes requested.
136     * It zeros-out the memory that is allocated. This is for a quick init
137       of the underlying datastructures.
138 */
139 /**************************************************************************/
gk_malloc(size_t nbytes,char * msg)140 void *gk_malloc(size_t nbytes, char *msg)
141 {
142   void *ptr=NULL;
143 
144   if (nbytes == 0)
145     nbytes++;  /* Force mallocs to actually allocate some memory */
146 
147   ptr = (void *)malloc(nbytes);
148 
149   if (ptr == NULL) {
150     fprintf(stderr, "   Current memory used:  %10zu bytes\n", gk_GetCurMemoryUsed());
151     fprintf(stderr, "   Maximum memory used:  %10zu bytes\n", gk_GetMaxMemoryUsed());
152     gk_errexit(SIGMEM, "***Memory allocation failed for %s. Requested size: %zu bytes",
153         msg, nbytes);
154     return NULL;
155   }
156 
157   /* add this memory allocation */
158   if (gkmcore != NULL) gk_gkmcoreAdd(gkmcore, GK_MOPT_HEAP, nbytes, ptr);
159 
160   /* zero-out the allocated space */
161 #ifndef NDEBUG
162   memset(ptr, 0, nbytes);
163 #endif
164 
165   return ptr;
166 }
167 
168 
169 /*************************************************************************
170 * This function is my wrapper around realloc
171 **************************************************************************/
gk_realloc(void * oldptr,size_t nbytes,char * msg)172 void *gk_realloc(void *oldptr, size_t nbytes, char *msg)
173 {
174   void *ptr=NULL;
175 
176   if (nbytes == 0)
177     nbytes++;  /* Force mallocs to actually allocate some memory */
178 
179   /* remove this memory de-allocation */
180   if (gkmcore != NULL && oldptr != NULL) gk_gkmcoreDel(gkmcore, oldptr);
181 
182   ptr = (void *)realloc(oldptr, nbytes);
183 
184   if (ptr == NULL) {
185     fprintf(stderr, "   Maximum memory used: %10zu bytes\n", gk_GetMaxMemoryUsed());
186     fprintf(stderr, "   Current memory used: %10zu bytes\n", gk_GetCurMemoryUsed());
187     gk_errexit(SIGMEM, "***Memory realloc failed for %s. " "Requested size: %zu bytes",
188         msg, nbytes);
189     return NULL;
190   }
191 
192   /* add this memory allocation */
193   if (gkmcore != NULL) gk_gkmcoreAdd(gkmcore, GK_MOPT_HEAP, nbytes, ptr);
194 
195   return ptr;
196 }
197 
198 
199 /*************************************************************************
200 * This function is my wrapper around free, allows multiple pointers
201 **************************************************************************/
gk_free(void ** ptr1,...)202 void gk_free(void **ptr1,...)
203 {
204   va_list plist;
205   void **ptr;
206 
207   if (*ptr1 != NULL) {
208     free(*ptr1);
209 
210     /* remove this memory de-allocation */
211     if (gkmcore != NULL) gk_gkmcoreDel(gkmcore, *ptr1);
212   }
213   *ptr1 = NULL;
214 
215   va_start(plist, ptr1);
216   while ((ptr = va_arg(plist, void **)) != LTERM) {
217     if (*ptr != NULL) {
218       free(*ptr);
219 
220       /* remove this memory de-allocation */
221       if (gkmcore != NULL) gk_gkmcoreDel(gkmcore, *ptr);
222     }
223     *ptr = NULL;
224   }
225   va_end(plist);
226 }
227 
228 
229 /*************************************************************************
230 * This function returns the current ammount of dynamically allocated
231 * memory that is used by the system
232 **************************************************************************/
gk_GetCurMemoryUsed()233 size_t gk_GetCurMemoryUsed()
234 {
235   if (gkmcore == NULL)
236     return 0;
237   else
238     return gkmcore->cur_hallocs;
239 }
240 
241 
242 /*************************************************************************
243 * This function returns the maximum ammount of dynamically allocated
244 * memory that was used by the system
245 **************************************************************************/
gk_GetMaxMemoryUsed()246 size_t gk_GetMaxMemoryUsed()
247 {
248   if (gkmcore == NULL)
249     return 0;
250   else
251     return gkmcore->max_hallocs;
252 }
253