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
371#define TOK_HASH_SIZE 16384 /* must be a power of two */371#define TOK_HASH_SIZE 16384 /* must be a power of two */
372#define TOK_ALLOC_INCR 512 /* must be a power of two */372#define TOK_ALLOC_INCR 512 /* must be a power of two */
373#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */373#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
374 380
375/* token symbol management */381/* token symbol management */
376typedef struct TokenSym {382typedef struct TokenSym {
@@ -637,6 +643,42 @@ typedef struct ParseArgsState · 260 unmodified lines
637 CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */643 CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
638} ParseArgsState;644} ParseArgsState;
639 645
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
659typedef 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
674typedef 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
640struct TCCState {682struct TCCState {
641 683
642 int verbose; /* if true, display some information during compilation */684 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
38ST_DATA int tok_ident;38ST_DATA int tok_ident;
39ST_DATA TokenSym **table_ident;39ST_DATA TokenSym **table_ident;
40 40
41ST_DATA TinyAlloc *toksym_alloc;
42ST_DATA TinyAlloc *tokstr_alloc;
43ST_DATA TinyAlloc *cstr_alloc;
44
41/* ------------------------------------------------------------------------- */45/* ------------------------------------------------------------------------- */
42 46
43static TokenSym *hash_ident[TOK_HASH_SIZE];47static TokenSym *hash_ident[TOK_HASH_SIZE];
@@ -125,6 +129,159 @@ ST_FUNC void end_macro(void) · 81 unmodified lines
125 }129 }
126}130}
127 131
132/* ------------------------------------------------------------------------- */
133/* Custom allocator for tiny objects */
134
135ST_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
145ST_FUNC void tal_delete(TinyAlloc *al)
146{
147 TinyAlloc *next;
148
149tail_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
179ST_FUNC void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
180{
181 if (!p)
182 return;
183tail_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
206ST_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
214tail_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
128/* ------------------------------------------------------------------------- */285/* ------------------------------------------------------------------------- */
129/* CString handling */286/* CString handling */
130static void cstr_realloc(CString *cstr, int new_size)287static void cstr_realloc(CString *cstr, int new_size)
@@ -137,7 +294,7 @@ static void cstr_realloc(CString *cstr, int new_size) · 6 unmodified lines
137 size = 8; /* no need to allocate a too small first string */294 size = 8; /* no need to allocate a too small first string */
138 while (size < new_size)295 while (size < new_size)
139 size = size * 2;296 size = size * 2;
140 data = tcc_realloc(cstr->data_allocated, size);297 data = tal_realloc(cstr_alloc, cstr->data_allocated, size);
141 cstr->data_allocated = data;298 cstr->data_allocated = data;
142 cstr->size_allocated = size;299 cstr->size_allocated = size;
143 cstr->data = data;300 cstr->data = data;
@@ -185,7 +342,7 @@ ST_FUNC void cstr_new(CString *cstr) · 41 unmodified lines
185/* free string and reset it to NULL */342/* free string and reset it to NULL */
186ST_FUNC void cstr_free(CString *cstr)343ST_FUNC void cstr_free(CString *cstr)
187{344{
188 tcc_free(cstr->data_allocated);345 tal_free(cstr_alloc, cstr->data_allocated);
189 cstr_new(cstr);346 cstr_new(cstr);
190}347}
191 348
@@ -233,7 +390,7 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) · 41 unmodified lines
233 table_ident = ptable;390 table_ident = ptable;
234 }391 }
235 392
236 ts = tcc_realloc(0, sizeof(TokenSym) + len);393 ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len);
237 table_ident[i] = ts;394 table_ident[i] = ts;
238 ts->tok = tok_ident++;395 ts->tok = tok_ident++;
239 ts->sym_define = NULL;396 ts->sym_define = NULL;
@@ -942,14 +1099,14 @@ ST_FUNC int *tok_str_dup(TokenString *s) · 702 unmodified lines
942{1099{
943 int *str;1100 int *str;
944 1101
945 str = tcc_realloc(0, s->len * sizeof(int));1102 str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int));
946 memcpy(str, s->str, s->len * sizeof(int));1103 memcpy(str, s->str, s->len * sizeof(int));
947 return str;1104 return str;
948}1105}
949 1106
950ST_FUNC void tok_str_free(int *str)1107ST_FUNC void tok_str_free(int *str)
951{1108{
952 tcc_free(str);1109 tal_free(tokstr_alloc, str);
953}1110}
954 1111
955ST_FUNC int *tok_str_realloc(TokenString *s, int new_size)1112ST_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
963 size = size * 2;1120 size = size * 2;
964 TCC_ASSERT((size & (size -1)) == 0);1121 TCC_ASSERT((size & (size -1)) == 0);
965 if (size > s->allocated_len) {1122 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));
967 s->allocated_len = size;1124 s->allocated_len = size;
968 s->str = str;1125 s->str = str;
969 }1126 }
@@ -3449,6 +3606,11 @@ ST_FUNC void preprocess_new(void) · 2479 unmodified lines
3449 for(i = 128; i<256; i++)3606 for(i = 128; i<256; i++)
3450 isidnum_table[i - CH_EOF] = IS_ID;3607 isidnum_table[i - CH_EOF] = IS_ID;
3451 3608
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
3452 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));3614 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
3453 cstr_new(&cstr_buf);3615 cstr_new(&cstr_buf);
3454 cstr_realloc(&cstr_buf, STRING_MAX_SIZE);3616 cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
@@ -3484,7 +3646,7 @@ ST_FUNC void preprocess_delete(void) · 29 unmodified lines
3484 /* free tokens */3646 /* free tokens */
3485 n = tok_ident - TOK_IDENT;3647 n = tok_ident - TOK_IDENT;
3486 for(i = 0; i < n; i++)3648 for(i = 0; i < n; i++)
3487 tcc_free(table_ident[i]);3649 tal_free(toksym_alloc, table_ident[i]);
3488 tcc_free(table_ident);3650 tcc_free(table_ident);
3489 table_ident = NULL;3651 table_ident = NULL;
3490 3652
@@ -3492,6 +3654,14 @@ ST_FUNC void preprocess_delete(void) · 1 unmodified line
3492 cstr_free(&tokcstr);3654 cstr_free(&tokcstr);
3493 cstr_free(&cstr_buf);3655 cstr_free(&cstr_buf);
3494 tok_str_free(tokstr_buf.str);3656 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;
3495}3665}
3496 3666
3497/* Preprocess the current file */3667/* 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