History

Reduce allocations overhead

- uses new `TinyAlloc`-ators for small `TokenSym`, `CString` and `TokenString` instances - conditional `TAL_DEBUG` for mem leaks and double frees detection - on `TAL_DEBUG` collects allocation origin (file + line) - conditional `TAL_INFO` for allocators stats (in release mode too) - chain a new allocator twice current capacity on buffer exhaustion

Vlad Vissoultchev committed 10 years ago

Commit cdc16d41 parent 224236f2 files · +219 −7Browse files

Unified · Split

2 files
  1. tcc.h +42 −0
  2. tccpp.c +177 −7
tcc.h+42−0
@@ -371,6 +371,12 @@ static inline void write64le(unsigned char *p, uint64_t x) · 370 unmodified lines
371371 #define TOK_HASH_SIZE 16384 /* must be a power of two */
372372 #define TOK_ALLOC_INCR 512 /* must be a power of two */
373373 #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */
374+#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */
375+#define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */
376+#define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */
377+#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */
378+#define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */
379+#define CSTR_TAL_LIMIT 1024
374380
375381 /* token symbol management */
376382 typedef struct TokenSym {
@@ -637,6 +643,42 @@ typedef struct ParseArgsState · 260 unmodified lines
637643 CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
638644 } ParseArgsState;
639645
646+#if !defined(MEM_DEBUG)
647+#define tal_free(al, p) tal_free_impl(al, p)
648+#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size)
649+#define TAL_DEBUG_PARAMS
650+#else
651+#define TAL_DEBUG 1
652+#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
653+#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
654+#define TAL_DEBUG_PARAMS , const char *file, int line
655+#define TAL_DEBUG_FILE_LEN 15
656+#endif
657+//#define TAL_INFO 1 /* collect and dump allocators stats */
658+
659+typedef struct TinyAlloc {
660+ size_t limit;
661+ size_t size;
662+ uint8_t *buffer;
663+ uint8_t *p;
664+ size_t nb_allocs;
665+ struct TinyAlloc *next, *top;
666+#ifdef TAL_INFO
667+ size_t nb_peak;
668+ size_t nb_total;
669+ size_t nb_missed;
670+ uint8_t *peak_p;
671+#endif
672+} TinyAlloc;
673+
674+typedef struct tal_header_t {
675+ size_t size;
676+#ifdef TAL_DEBUG
677+ int line_num; /* negative line_num used for double free check */
678+ char file_name[TAL_DEBUG_FILE_LEN + 1];
679+#endif
680+} tal_header_t;
681+
640682 struct TCCState {
641683
642684 int verbose; /* if true, display some information during compilation */
tccpp.c+177−7
@@ -38,6 +38,10 @@ ST_DATA int total_bytes; · 37 unmodified lines
3838 ST_DATA int tok_ident;
3939 ST_DATA TokenSym **table_ident;
4040
41+ST_DATA TinyAlloc *toksym_alloc;
42+ST_DATA TinyAlloc *tokstr_alloc;
43+ST_DATA TinyAlloc *cstr_alloc;
44+
4145 /* ------------------------------------------------------------------------- */
4246
4347 static TokenSym *hash_ident[TOK_HASH_SIZE];
@@ -125,6 +129,159 @@ ST_FUNC void end_macro(void) · 81 unmodified lines
125129 }
126130 }
127131
132+/* ------------------------------------------------------------------------- */
133+/* Custom allocator for tiny objects */
134+
135+ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size)
136+{
137+ TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));
138+ al->p = al->buffer = tcc_malloc(size);
139+ al->limit = limit;
140+ al->size = size;
141+ if (pal) *pal = al;
142+ return al;
143+}
144+
145+ST_FUNC void tal_delete(TinyAlloc *al)
146+{
147+ TinyAlloc *next;
148+
149+tail_call:
150+ if (!al)
151+ return;
152+#ifdef TAL_INFO
153+ fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n",
154+ al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed,
155+ (al->peak_p - al->buffer) * 100.0 / al->size);
156+#endif
157+#ifdef TAL_DEBUG
158+ if (al->nb_allocs > 0) {
159+ fprintf(stderr, "TAL_DEBUG: mem leak %d chunks (limit= %d)\n",
160+ al->nb_allocs, al->limit);
161+ uint8_t *p = al->buffer;
162+ while (p < al->p) {
163+ tal_header_t *header = (tal_header_t *)p;
164+ if (header->line_num > 0) {
165+ fprintf(stderr, " file %s, line %u: %u bytes\n",
166+ header->file_name, header->line_num, header->size);
167+ }
168+ p += header->size + sizeof(tal_header_t);
169+ }
170+ }
171+#endif
172+ next = al->next;
173+ tcc_free(al->buffer);
174+ tcc_free(al);
175+ al = next;
176+ goto tail_call;
177+}
178+
179+ST_FUNC void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
180+{
181+ if (!p)
182+ return;
183+tail_call:
184+ if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) {
185+#ifdef TAL_DEBUG
186+ tal_header_t *header = (((tal_header_t *)p) - 1);
187+ if (header->line_num < 0) {
188+ fprintf(stderr, "TAL_DEBUG: file %s, line %u double frees chunk from\n",
189+ file, line);
190+ fprintf(stderr, " file %s, line %u: %u bytes\n",
191+ header->file_name, -header->line_num, header->size);
192+ } else
193+ header->line_num = -header->line_num;
194+#endif
195+ al->nb_allocs--;
196+ if (!al->nb_allocs)
197+ al->p = al->buffer;
198+ } else if (al->next) {
199+ al = al->next;
200+ goto tail_call;
201+ }
202+ else
203+ tcc_free(p);
204+}
205+
206+ST_FUNC void *tal_realloc_impl(TinyAlloc **pal, void *p, size_t size TAL_DEBUG_PARAMS)
207+{
208+ tal_header_t *header;
209+ void *ret;
210+ int is_own;
211+ size_t adj_size = (size + 3) & -4;
212+ TinyAlloc *al = *pal;
213+
214+tail_call:
215+ is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
216+ if ((!p || is_own) && size <= al->limit) {
217+ if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
218+ header = (tal_header_t *)al->p;
219+ header->size = adj_size;
220+#ifdef TAL_DEBUG
221+ int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;
222+ strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);
223+ header->file_name[TAL_DEBUG_FILE_LEN] = 0;
224+ header->line_num = line;
225+#endif
226+ ret = al->p + sizeof(tal_header_t);
227+ al->p += adj_size + sizeof(tal_header_t);
228+ if (is_own) {
229+ header = (((tal_header_t *)p) - 1);
230+ memcpy(ret, p, header->size);
231+#ifdef TAL_DEBUG
232+ header->line_num = -header->line_num;
233+#endif
234+ } else {
235+ al->nb_allocs++;
236+ }
237+#ifdef TAL_INFO
238+ if (al->nb_peak < al->nb_allocs)
239+ al->nb_peak = al->nb_allocs;
240+ if (al->peak_p < al->p)
241+ al->peak_p = al->p;
242+ al->nb_total++;
243+#endif
244+ return ret;
245+ } else if (al->top && is_own) {
246+ al->nb_allocs--;
247+ ret = tal_realloc(*pal, 0, size);
248+ header = (((tal_header_t *)p) - 1);
249+ memcpy(ret, p, header->size);
250+#ifdef TAL_DEBUG
251+ header->line_num = -header->line_num;
252+#endif
253+ return ret;
254+ }
255+ if (al->next) {
256+ al = al->next;
257+ } else {
258+ TinyAlloc *bottom = al, *next = al->top ? al->top : al;
259+
260+ al = tal_new(pal, next->limit, next->size * 2);
261+ al->next = next;
262+ bottom->top = al;
263+ }
264+ goto tail_call;
265+ }
266+ if (is_own) {
267+ al->nb_allocs--;
268+ ret = tcc_malloc(size);
269+ header = (((tal_header_t *)p) - 1);
270+ memcpy(ret, p, header->size);
271+#ifdef TAL_DEBUG
272+ header->line_num = -header->line_num;
273+#endif
274+ } else if (al->next) {
275+ al = al->next;
276+ goto tail_call;
277+ } else
278+ ret = tcc_realloc(p, size);
279+#ifdef TAL_INFO
280+ al->nb_missed++;
281+#endif
282+ return ret;
283+}
284+
128285 /* ------------------------------------------------------------------------- */
129286 /* CString handling */
130287 static void cstr_realloc(CString *cstr, int new_size)
@@ -137,7 +294,7 @@ static void cstr_realloc(CString *cstr, int new_size) · 6 unmodified lines
137294 size = 8; /* no need to allocate a too small first string */
138295 while (size < new_size)
139296 size = size * 2;
140− data = tcc_realloc(cstr->data_allocated, size);
297+ data = tal_realloc(cstr_alloc, cstr->data_allocated, size);
141298 cstr->data_allocated = data;
142299 cstr->size_allocated = size;
143300 cstr->data = data;
@@ -185,7 +342,7 @@ ST_FUNC void cstr_new(CString *cstr) · 41 unmodified lines
185342 /* free string and reset it to NULL */
186343 ST_FUNC void cstr_free(CString *cstr)
187344 {
188− tcc_free(cstr->data_allocated);
345+ tal_free(cstr_alloc, cstr->data_allocated);
189346 cstr_new(cstr);
190347 }
191348
@@ -233,7 +390,7 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) · 41 unmodified lines
233390 table_ident = ptable;
234391 }
235392
236− ts = tcc_realloc(0, sizeof(TokenSym) + len);
393+ ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len);
237394 table_ident[i] = ts;
238395 ts->tok = tok_ident++;
239396 ts->sym_define = NULL;
@@ -942,14 +1099,14 @@ ST_FUNC int *tok_str_dup(TokenString *s) · 702 unmodified lines
9421099 {
9431100 int *str;
9441101
945− str = tcc_realloc(0, s->len * sizeof(int));
1102+ str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int));
9461103 memcpy(str, s->str, s->len * sizeof(int));
9471104 return str;
9481105 }
9491106
9501107 ST_FUNC void tok_str_free(int *str)
9511108 {
952− tcc_free(str);
1109+ tal_free(tokstr_alloc, str);
9531110 }
9541111
9551112 ST_FUNC int *tok_str_realloc(TokenString *s, int new_size)
@@ -963,7 +1120,7 @@ ST_FUNC int *tok_str_realloc(TokenString *s, int new_size) · 7 unmodified lines
9631120 size = size * 2;
9641121 TCC_ASSERT((size & (size -1)) == 0);
9651122 if (size > s->allocated_len) {
966− str = tcc_realloc(s->str, size * sizeof(int));
1123+ str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int));
9671124 s->allocated_len = size;
9681125 s->str = str;
9691126 }
@@ -3449,6 +3606,11 @@ ST_FUNC void preprocess_new(void) · 2479 unmodified lines
34493606 for(i = 128; i<256; i++)
34503607 isidnum_table[i - CH_EOF] = IS_ID;
34513608
3609+ /* init allocators */
3610+ tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
3611+ tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
3612+ tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
3613+
34523614 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
34533615 cstr_new(&cstr_buf);
34543616 cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
@@ -3484,7 +3646,7 @@ ST_FUNC void preprocess_delete(void) · 29 unmodified lines
34843646 /* free tokens */
34853647 n = tok_ident - TOK_IDENT;
34863648 for(i = 0; i < n; i++)
3487− tcc_free(table_ident[i]);
3649+ tal_free(toksym_alloc, table_ident[i]);
34883650 tcc_free(table_ident);
34893651 table_ident = NULL;
34903652
@@ -3492,6 +3654,14 @@ ST_FUNC void preprocess_delete(void) · 1 unmodified line
34923654 cstr_free(&tokcstr);
34933655 cstr_free(&cstr_buf);
34943656 tok_str_free(tokstr_buf.str);
3657+
3658+ /* free allocators */
3659+ tal_delete(toksym_alloc);
3660+ toksym_alloc = NULL;
3661+ tal_delete(tokstr_alloc);
3662+ tokstr_alloc = NULL;
3663+ tal_delete(cstr_alloc);
3664+ cstr_alloc = NULL;
34953665 }
34963666
34973667 /* Preprocess the current file */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t