5
/* $Id: bufalloc.c,v 1.2 2001-06-07 23:23:23 d3h325 Exp $
6
* storage manager for a chunk of memory passed by user in armci_init_buf_alloc
7
* derived from K&R that manages a chunk of memory
14
extern char *buf_allocate(); /* Used to get memory from the system */
15
extern void armci_die();
17
#define VALID1 0xaaaaaaaa /* For validity check on headers */
18
#define VALID2 0x55555555
20
#define ALIGNMENT (1 << LOG_ALIGN)
21
#define DEFAULT_NALLOC (1024 - ALIGNMENT)
24
static struct shmalloc_struct {
25
size_t total; /* Amount request from system in units */
26
long nchunk; /* No. of chunks of system memory */
27
long inuse; /* Amount in use in units */
28
long maxuse; /* Maximum value of inuse */
29
long nfrags; /* No. of fragments divided into */
30
long nmcalls; /* No. of calls to shmalloc */
31
long nfcalls; /* No. of calls to buf_free */
37
unsigned valid1; /* Token to check if is not overwritten */
38
union header *ptr; /* next block if on free list */
39
size_t size; /* size of this block*/
40
unsigned valid2; /* Another token acting as a guard */
42
char align[ALIGNMENT]; /* Align to ALIGNMENT byte boundary */
44
typedef union header Header;
46
static Header base; /* empty list to get started */
47
static Header *freep = NULL; /* start of free list */
48
static Header *usedp = NULL; /* start of used list */
49
static size_t nalloc = DEFAULT_NALLOC;
50
static size_t max_nalloc = DEFAULT_NALLOC;
51
static int do_verify = 0; /* Flag for automatic heap verification */
52
static int initialized=0;
55
static void buf_error(char* s, unsigned long i)
57
void buf_alloc_print_stats();
59
fprintf(stderr,"buf_alloc error: %s %ld(0x%lx)\n", s, i, i);
62
buf_alloc_print_stats();
64
armci_die("buf_alloc: fatal error", i);
67
void armci_buf_alloc_request(size_t size, size_t maxsize)
69
nalloc = (size+ALIGNMENT-1) >> LOG_ALIGN;
70
max_nalloc = (maxsize+ALIGNMENT-1) >> LOG_ALIGN;
73
void armci_buf_alloc_debug(int code)
79
void armci_buf_alloc_verify()
85
/* Check the used list */
86
for (p=usedp; p; p=p->s.ptr) {
87
if (p->s.valid1 != VALID1 || p->s.valid2 != VALID2)
88
buf_error("invalid header on usedlist", (unsigned long) p->s.valid1);
91
if (p->s.size > usage.total)
92
buf_error("invalid size in header usedlist",(unsigned long)p->s.size);
96
/* Check the free list */
99
if (p->s.valid1 != VALID1 || p->s.valid2 != VALID2)
100
buf_error("invalid header on freelist", (unsigned long) p->s.valid1);
103
if (p->s.size > usage.total)
104
buf_error("invalid size in header freelist",(unsigned long)p->s.size);
113
static void addtofree(char* ap)
115
Header *bp, *p, **up;
120
if (do_verify) armci_buf_alloc_verify();
122
/* only do something if pointer is not NULL */
125
bp = (Header *) ap - 1; /* Point to block header */
127
if (bp->s.valid1 != VALID1 || bp->s.valid2 != VALID2)
128
buf_error("buf_free: pointer not from buf_alloc", (unsigned long) ap);
131
usage.inuse -= bp->s.size; /* Decrement memory usage */
134
/* Extract the block from the used linked list ... for debug only */
135
for (up=&usedp; ; up = &((*up)->s.ptr)) {
137
buf_error("buf_free:block not found in used list\n",(unsigned long)ap);
144
/* Join the memory back into the free linked list */
145
for (p=freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
146
if (p >= p->s.ptr && (bp > p || bp < p->s.ptr))
147
break; /* Freed block at start or end of arena */
149
if (bp + bp->s.size == p->s.ptr) {/* join to upper neighbour */
150
bp->s.size += p->s.ptr->s.size;
151
bp->s.ptr = p->s.ptr->s.ptr;
153
usage.nfrags--; /* Lost a fragment */
156
bp->s.ptr = p->s.ptr;
158
if (p + p->s.size == bp) { /* Join to lower neighbour */
159
p->s.size += bp->s.size;
160
p->s.ptr = bp->s.ptr;
162
usage.nfrags--; /* Lost a fragment */
173
void armci_init_buf_alloc(size_t len, void* buffer)
178
/* need to initialize the free list */
179
if (sizeof(Header) != ALIGNMENT)
180
buf_error("Alignment is not valid", (unsigned long) ALIGNMENT);
182
if(initialized)armci_die("armci_init_buf_alloc: already initialized",0);
185
usage.total = 0; /* Initialize statistics */
194
base.s.ptr = freep = prevp = &base; /* Initialize linked list */
196
base.s.valid1 = VALID1;
197
base.s.valid2 = VALID2;
199
nu = len/sizeof(Header); /* nu must by a multiplicity of nalloc */
200
max_nalloc = nu*nalloc;
201
if(nu<1) armci_die("buffer less than nalloc",(int)len);
205
usage.total += nu; /* Have just got nu more units */
206
usage.nchunk++; /* One more chunk */
207
usage.nfrags++; /* Currently one more frag */
208
usage.inuse += nu; /* Inuse will be decremented by buf_free */
213
up->s.valid1 = VALID1;
214
up->s.valid2 = VALID2;
216
/* Insert into linked list of blocks in use so that buf_free works
217
... for debug only */
221
addtofree((char *)(up+1)); /* Try to join into the free list */
225
/*\ return a chunk memory of given size
227
char *armci_buf_alloc(size_t nbytes)
233
/* need to initialize the free list */
234
if ((prevp = freep) == NULL) armci_die("not initialized", 0);
240
if (do_verify) armci_buf_alloc_verify();
242
/* Rather than divide make the alignment a known power of 2 */
243
nunits = ((nbytes + sizeof(Header) - 1)>>LOG_ALIGN) + 1;
245
for (p=prevp->s.ptr; ; prevp = p, p = p->s.ptr) {
246
if (p->s.size >= nunits) { /* Big enuf */
247
if (p->s.size == nunits) /* exact fit */
248
prevp->s.ptr = p->s.ptr;
249
else { /* allocate tail end */
253
p->s.valid1 = VALID1;
254
p->s.valid2 = VALID2;
256
usage.nfrags++; /* Have just increased the fragmentation */
260
/* Insert into linked list of blocks in use ... for debug only */
265
usage.inuse += nunits; /* Record usage */
266
if (usage.inuse > usage.maxuse)
267
usage.maxuse = usage.inuse;
270
return_ptr = (char *) (p+1);
274
if (p == freep){ /* wrapped around the free list */
275
return_ptr = (char *) NULL;
283
void armci_buf_free(char *ap)
285
Header *bp, *p, **up;
289
if (do_verify) armci_buf_alloc_verify();
291
/* only do something if pointer is not NULL */
295
bp = (Header *) ap - 1; /* Point to block header */
297
if (bp->s.valid1 != VALID1 || bp->s.valid2 != VALID2)
298
buf_error("buf_free: pointer not from buf_alloc", (unsigned long) ap);
301
usage.inuse -= bp->s.size; /* Decrement memory usage */
304
/* Extract the block from the used linked list for debug only */
305
for (up=&usedp; ; up = &((*up)->s.ptr)) {
307
buf_error("buf_free:block not found in used list\n",(unsigned long)ap);
314
/* Join the memory back into the free linked list */
315
for (p=freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
316
if (p >= p->s.ptr && (bp > p || bp < p->s.ptr))
317
break; /* Freed block at start or end of arena */
319
if (bp + bp->s.size == p->s.ptr) {/* join to upper neighbour */
320
bp->s.size += p->s.ptr->s.size;
321
bp->s.ptr = p->s.ptr->s.ptr;
323
usage.nfrags--; /* Lost a fragment */
326
bp->s.ptr = p->s.ptr;
328
if (p + p->s.size == bp) { /* Join to lower neighbour */
329
p->s.size += bp->s.size;
330
p->s.ptr = bp->s.ptr;
332
usage.nfrags--; /* Lost a fragment */
345
Return stats on buf_alloc performance. Use arg list instead of
346
returning structure so that FORTRAN can eventually use it
348
void buf_alloc_stats(size_t *total, long* nchunk, size_t * inuse,
349
size_t * maxuse, long* nfrags, long* nmcalls,long* nfcalls)
351
*total = usage.total * sizeof(Header);
352
*nchunk = usage.nchunk;
353
*inuse = (size_t)usage.inuse * sizeof(Header);
354
*maxuse = (size_t)usage.maxuse* sizeof(Header);
355
*nfrags = usage.nfrags;
356
*nmcalls= usage.nmcalls;
357
*nfcalls= usage.nfcalls;
361
Print to standard output the usage statistics.
363
void buf_alloc_print_stats()
365
size_t total, inuse, maxuse;
366
long nchunk, nfrags, nmcalls, nfcalls;
368
buf_alloc_stats(&total, &nchunk, &inuse, &maxuse, &nfrags,
372
printf("\nbuf_alloc statistics\n-------------------\n\n");
373
printf("Total memory from system ... %ld bytes\n", (long)total);
374
printf("Current memory usage ....... %ld bytes\n", (long)inuse);
375
printf("Maximum memory usage ....... %ld bytes\n", (long)maxuse);
376
printf("No. chunks from system ..... %ld\n", nchunk);
377
printf("No. of fragments ........... %ld\n", nfrags);
378
printf("No. of calls to buf_alloc ... %ld\n", nmcalls);
379
printf("No. of calls to buf_free ..... %ld\n", nfcalls);
387
void armci_die(char *str, int c)
389
fprintf(stderr,"%s %d\n",str,c);
394
#define LEN (16*1024)
397
main (int argc, char **argv)
399
int i,k,total=0,size=1024;
401
armci_init_buf_alloc(LEN, buf);
403
for(i=0; i<100; i++)ar[i]=(char*)0;
405
for(i=0; i<100; i++){
406
ar[i] =armci_buf_alloc(size);
408
printf("i =%d total=%d\n", i, total);
409
buf_alloc_print_stats();
415
for(i=0; i<k/2; i++){
416
armci_buf_free(ar[i]);
420
printf("relased %d blocks\n",k/2);
421
buf_alloc_print_stats();
423
for(i=k; i<100; i++){
424
ar[i] =armci_buf_alloc(size);
426
printf("i =%d total=%d\n", i, total);
427
buf_alloc_print_stats();
431
for(i=0; i<100; i++) if(ar[i])armci_buf_free(ar[i]);
432
printf("relased all blocks\n");
433
buf_alloc_print_stats();