xref: /plan9-contrib/sys/src/cmd/spin/tl_mem.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
1 /***** tl_spin: tl_mem.c *****/
2 
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  *
8  * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
9  * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
10  */
11 
12 #include "tl.h"
13 
14 #if 1
15 #define log(e, u, d)	event[e][(int) u] += (long) d;
16 #else
17 #define log(e, u, d)
18 #endif
19 
20 #define A_LARGE		80
21 #define A_USER		0x55000000
22 #define NOTOOBIG	32768
23 
24 #define POOL		0
25 #define ALLOC		1
26 #define FREE		2
27 #define NREVENT		3
28 
29 extern	unsigned long All_Mem;
30 extern	int tl_verbose;
31 
32 union M {
33 	long size;
34 	union M *link;
35 };
36 
37 static union M *freelist[A_LARGE];
38 static long	req[A_LARGE];
39 static long	event[NREVENT][A_LARGE];
40 
41 void *
tl_emalloc(int U)42 tl_emalloc(int U)
43 {	union M *m;
44   	long r, u;
45 	void *rp;
46 
47 	u = (long) ((U-1)/sizeof(union M) + 2);
48 
49 	if (u >= A_LARGE)
50 	{	log(ALLOC, 0, 1);
51 		if (tl_verbose)
52 		{	printf("tl_spin: memalloc %ld bytes\n", u);
53 		}
54 		m = (union M *) emalloc((int) u*sizeof(union M));
55 		All_Mem += (unsigned long) u*sizeof(union M);
56 	} else
57 	{	if (!freelist[u])
58 		{	r = req[u] += req[u] ? req[u] : 1;
59 			if (r >= NOTOOBIG)
60 			{	r = req[u] = NOTOOBIG;
61 			}
62 			log(POOL, u, r);
63 			freelist[u] = (union M *)
64 				emalloc((int) r*u*sizeof(union M));
65 			All_Mem += (unsigned long) r*u*sizeof(union M);
66 			m = freelist[u] + (r-2)*u;
67 			for ( ; m >= freelist[u]; m -= u)
68 			{	m->link = m+u;
69 		}	}
70 		log(ALLOC, u, 1);
71 		m = freelist[u];
72 		freelist[u] = m->link;
73 	}
74 	m->size = (u|A_USER);
75 
76 	for (r = 1; r < u; )
77 	{	(&m->size)[r++] = 0;
78 	}
79 
80 	rp = (void *) (m+1);
81 	memset(rp, 0, U);
82 	return rp;
83 }
84 
85 /* could be more efficient, but not a bottleneck */
86 void*
tl_erealloc(void * v,int U,int old_size)87 tl_erealloc(void *v, int U, int old_size)
88 {	void* tmp = tl_emalloc(U);
89 
90 	if (v)
91 	{	strncpy(tmp, v, old_size);
92 		tfree(v);
93 	}
94 
95 	return tmp;
96 }
97 
98 void
tfree(void * v)99 tfree(void *v)
100 {	union M *m = (union M *) v;
101 	long u;
102 
103 	--m;
104 	if ((m->size&0xFF000000) != A_USER)
105 	{	Fatal("releasing a free block", (char *)0);
106 	}
107 
108 	u = (m->size &= 0xFFFFFF);
109 	if (u >= A_LARGE)
110 	{	log(FREE, 0, 1);
111 		/* free(m); */
112 	} else
113 	{	log(FREE, u, 1);
114 		m->link = freelist[u];
115 		freelist[u] = m;
116 	}
117 }
118 
119 void
a_stats(void)120 a_stats(void)
121 {	long	p, a, f;
122 	int	i;
123 
124 	printf(" size\t  pool\tallocs\t frees\n");
125 	for (i = 0; i < A_LARGE; i++)
126 	{	p = event[POOL][i];
127 		a = event[ALLOC][i];
128 		f = event[FREE][i];
129 
130 		if (p|a|f)
131 		{	printf("%5d\t%6ld\t%6ld\t%6ld\n",
132 				i, p, a, f);
133 	}	}
134 }
135