1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* Quick arena hack for xpt. */
39 :
40 : /* XXX This exists because we don't want to drag in NSPR. It *seemed*
41 : * to make more sense to write a quick and dirty arena than to clone
42 : * plarena (like js/src did). This is not optimal, but it works.
43 : * Half of the code here is instrumentation.
44 : */
45 :
46 : #include "xpt_arena.h"
47 : #include <string.h>
48 : #include <stdio.h>
49 : #include <stdlib.h>
50 :
51 : /*************************/
52 : /* logging stats support */
53 :
54 : #if 0 && defined(DEBUG_jband)
55 : #define XPT_ARENA_LOGGING 1
56 : #endif
57 :
58 : #ifdef XPT_ARENA_LOGGING
59 :
60 : #define LOG_MALLOC(_a, _req, _used) \
61 : do{ \
62 : XPT_ASSERT((_a)); \
63 : ++(_a)->LOG_MallocCallCount; \
64 : (_a)->LOG_MallocTotalBytesRequested += (_req); \
65 : (_a)->LOG_MallocTotalBytesUsed += (_used); \
66 : } while(0)
67 :
68 : #define LOG_REAL_MALLOC(_a, _size) \
69 : do{ \
70 : XPT_ASSERT((_a)); \
71 : ++(_a)->LOG_RealMallocCallCount; \
72 : (_a)->LOG_RealMallocTotalBytesRequested += (_size); \
73 : } while(0)
74 :
75 : #define LOG_FREE(_a) \
76 : do{ \
77 : XPT_ASSERT((_a)); \
78 : ++(_a)->LOG_FreeCallCount; \
79 : } while(0)
80 :
81 : #define LOG_DONE_LOADING(_a) \
82 : do{ \
83 : XPT_ASSERT((_a)); \
84 : (_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount; \
85 : } while(0)
86 :
87 : #define PRINT_STATS(_a) xpt_DebugPrintArenaStats((_a))
88 : static void xpt_DebugPrintArenaStats(XPTArena *arena);
89 :
90 : #else /* !XPT_ARENA_LOGGING */
91 :
92 : #define LOG_MALLOC(_a, _req, _used) ((void)0)
93 : #define LOG_REAL_MALLOC(_a, _size) ((void)0)
94 : #define LOG_FREE(_a) ((void)0)
95 :
96 : #define LOG_DONE_LOADING(_a) ((void)0)
97 : #define PRINT_STATS(_a) ((void)0)
98 :
99 : #endif /* XPT_ARENA_LOGGING */
100 :
101 : /****************************************************/
102 :
103 : /* Block header for each block in the arena */
104 : typedef struct BLK_HDR BLK_HDR;
105 : struct BLK_HDR
106 : {
107 : BLK_HDR *next;
108 : size_t size;
109 : };
110 :
111 : #define XPT_MIN_BLOCK_SIZE 32
112 :
113 : /* XXX this is lame. Should clone the code to do this bitwise */
114 : #define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a)))
115 :
116 : struct XPTArena
117 : {
118 : BLK_HDR *first;
119 : PRUint8 *next;
120 : size_t space;
121 : size_t alignment;
122 : size_t block_size;
123 : char *name;
124 :
125 : #ifdef XPT_ARENA_LOGGING
126 : PRUint32 LOG_MallocCallCount;
127 : PRUint32 LOG_MallocTotalBytesRequested;
128 : PRUint32 LOG_MallocTotalBytesUsed;
129 : PRUint32 LOG_FreeCallCount;
130 : PRUint32 LOG_LoadingFreeCallCount;
131 : PRUint32 LOG_RealMallocCallCount;
132 : PRUint32 LOG_RealMallocTotalBytesRequested;
133 : #endif /* XPT_ARENA_LOGGING */
134 : };
135 :
136 : XPT_PUBLIC_API(XPTArena *)
137 219916 : XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name)
138 : {
139 219916 : XPTArena *arena = calloc(1, sizeof(XPTArena));
140 219916 : if (arena) {
141 219916 : XPT_ASSERT(alignment);
142 219916 : if (alignment > sizeof(double))
143 0 : alignment = sizeof(double);
144 219916 : arena->alignment = alignment;
145 :
146 219916 : if (block_size < XPT_MIN_BLOCK_SIZE)
147 0 : block_size = XPT_MIN_BLOCK_SIZE;
148 219916 : arena->block_size = ALIGN_RND(block_size, alignment);
149 :
150 : /* must have room for at least one item! */
151 219916 : XPT_ASSERT(arena->block_size >=
152 : ALIGN_RND(sizeof(BLK_HDR), alignment) +
153 : ALIGN_RND(1, alignment));
154 :
155 219916 : if (name) {
156 219916 : arena->name = XPT_STRDUP(arena, name);
157 : #ifdef XPT_ARENA_LOGGING
158 : /* fudge the stats since we are using space in the arena */
159 : arena->LOG_MallocCallCount = 0;
160 : arena->LOG_MallocTotalBytesRequested = 0;
161 : arena->LOG_MallocTotalBytesUsed = 0;
162 : #endif /* XPT_ARENA_LOGGING */
163 : }
164 : }
165 219916 : return arena;
166 : }
167 :
168 : XPT_PUBLIC_API(void)
169 219906 : XPT_DestroyArena(XPTArena *arena)
170 : {
171 : BLK_HDR* cur;
172 : BLK_HDR* next;
173 :
174 219906 : cur = arena->first;
175 2285994 : while (cur) {
176 1846182 : next = cur->next;
177 1846182 : free(cur);
178 1846182 : cur = next;
179 : }
180 219906 : free(arena);
181 219906 : }
182 :
183 : XPT_PUBLIC_API(void)
184 0 : XPT_DumpStats(XPTArena *arena)
185 : {
186 : PRINT_STATS(arena);
187 0 : }
188 :
189 :
190 : /*
191 : * Our alignment rule is that we always round up the size of each allocation
192 : * so that the 'arena->next' pointer one will point to properly aligned space.
193 : */
194 :
195 : XPT_PUBLIC_API(void *)
196 65692906 : XPT_ArenaMalloc(XPTArena *arena, size_t size)
197 : {
198 : PRUint8 *cur;
199 : size_t bytes;
200 :
201 65692906 : if (!size)
202 0 : return NULL;
203 :
204 65692906 : if (!arena) {
205 0 : XPT_ASSERT(0);
206 0 : return NULL;
207 : }
208 :
209 65692906 : bytes = ALIGN_RND(size, arena->alignment);
210 :
211 : LOG_MALLOC(arena, size, bytes);
212 :
213 65692906 : if (bytes > arena->space) {
214 : BLK_HDR* new_block;
215 1855882 : size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment);
216 1855882 : size_t new_space = arena->block_size;
217 :
218 4665216 : while (bytes > new_space - block_header_size)
219 953452 : new_space += arena->block_size;
220 :
221 1855882 : new_block = (BLK_HDR*) calloc(new_space/arena->alignment,
222 : arena->alignment);
223 1855882 : if (!new_block) {
224 0 : arena->next = NULL;
225 0 : arena->space = 0;
226 0 : return NULL;
227 : }
228 :
229 : LOG_REAL_MALLOC(arena, new_space);
230 :
231 : /* link block into the list of blocks for use when we destroy */
232 1855882 : new_block->next = arena->first;
233 1855882 : arena->first = new_block;
234 :
235 : /* save other block header info */
236 1855882 : new_block->size = new_space;
237 :
238 : /* set info for current block */
239 1855882 : arena->next = ((PRUint8*)new_block) + block_header_size;
240 1855882 : arena->space = new_space - block_header_size;
241 :
242 : #ifdef DEBUG
243 : /* mark block for corruption check */
244 1855882 : memset(arena->next, 0xcd, arena->space);
245 : #endif
246 : }
247 :
248 : #ifdef DEBUG
249 : {
250 : /* do corruption check */
251 : size_t i;
252 1979856074 : for (i = 0; i < bytes; ++i) {
253 1914163168 : XPT_ASSERT(arena->next[i] == 0xcd);
254 : }
255 : /* we guarantee that the block will be filled with zeros */
256 65692906 : memset(arena->next, 0, bytes);
257 : }
258 : #endif
259 :
260 65692906 : cur = arena->next;
261 65692906 : arena->next += bytes;
262 65692906 : arena->space -= bytes;
263 :
264 65692906 : return cur;
265 : }
266 :
267 :
268 : XPT_PUBLIC_API(char *)
269 219916 : XPT_ArenaStrDup(XPTArena *arena, const char * s)
270 : {
271 : size_t len;
272 : char* cur;
273 :
274 219916 : if (!s)
275 0 : return NULL;
276 :
277 219916 : len = strlen(s)+1;
278 219916 : cur = XPT_ArenaMalloc(arena, len);
279 219916 : memcpy(cur, s, len);
280 219916 : return cur;
281 : }
282 :
283 : XPT_PUBLIC_API(void)
284 0 : XPT_NotifyDoneLoading(XPTArena *arena)
285 : {
286 : #ifdef XPT_ARENA_LOGGING
287 : if (arena) {
288 : LOG_DONE_LOADING(arena);
289 : }
290 : #endif
291 0 : }
292 :
293 : XPT_PUBLIC_API(void)
294 5402703 : XPT_ArenaFree(XPTArena *arena, void *block)
295 : {
296 : LOG_FREE(arena);
297 5402703 : }
298 :
299 : #ifdef XPT_ARENA_LOGGING
300 : static void xpt_DebugPrintArenaStats(XPTArena *arena)
301 : {
302 : printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
303 : printf("Start xpt arena stats for \"%s\"\n",
304 : arena->name ? arena->name : "unnamed arena");
305 : printf("\n");
306 : printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount);
307 : printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested);
308 : printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
309 : printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0);
310 : printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
311 : printf("\n");
312 : printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount);
313 : printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0));
314 : printf("\n");
315 : printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount);
316 : printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 ));
317 : printf("\n");
318 : printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount);
319 : printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested);
320 : printf("%d byte block size specified at arena creation time\n", (int) arena->block_size);
321 : printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment);
322 : printf("\n");
323 : printf("End xpt arena stats\n");
324 : printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
325 : }
326 : #endif
327 :
328 : /***************************************************************************/
329 :
330 : #ifdef DEBUG
331 : XPT_PUBLIC_API(void)
332 0 : XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno)
333 : {
334 0 : fprintf(stderr, "Assertion failed: %s, file %s, line %d\n",
335 : s, file, lineno);
336 0 : abort();
337 : }
338 : #endif
339 :
340 : XPT_PUBLIC_API(size_t)
341 0 : XPT_SizeOfArena(XPTArena *arena, xptMallocSizeOfFun mallocSizeOf)
342 : {
343 0 : size_t n = mallocSizeOf(arena);
344 :
345 : /*
346 : * We don't measure arena->name separately because it's allocated out of
347 : * the arena itself.
348 : */
349 :
350 : BLK_HDR* cur;
351 : BLK_HDR* next;
352 :
353 0 : cur = arena->first;
354 0 : while (cur) {
355 0 : next = cur->next;
356 0 : n += mallocSizeOf(cur);
357 0 : cur = next;
358 : }
359 :
360 0 : return n;
361 : }
|