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