Log memory usage diagnostics, fix test_not, add ability to compile in debug mode
This commit is contained in:
parent
b6cb84df15
commit
3504bde301
5 changed files with 44 additions and 11 deletions
|
|
@ -3,7 +3,7 @@ LDFLAGS := $(shell pkg-config --libs glib-2.0)
|
||||||
CC := gcc
|
CC := gcc
|
||||||
# Set V=1 for verbose mode...
|
# Set V=1 for verbose mode...
|
||||||
V := 0
|
V := 0
|
||||||
CFLAGS += -DINCLUDE_TESTS
|
CFLAGS += -DINCLUDE_TESTS $(EXTRA_CFLAGS)
|
||||||
HUSH = $(TOPLEVEL)/lib/hush
|
HUSH = $(TOPLEVEL)/lib/hush
|
||||||
|
|
||||||
# Check to make sure variables are properly set
|
# Check to make sure variables are properly set
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,22 @@ struct arena_link {
|
||||||
struct arena {
|
struct arena {
|
||||||
struct arena_link *head;
|
struct arena_link *head;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
|
size_t used;
|
||||||
|
size_t wasted;
|
||||||
};
|
};
|
||||||
|
|
||||||
arena_t new_arena(size_t block_size) {
|
arena_t new_arena(size_t block_size) {
|
||||||
|
if (block_size == 0)
|
||||||
|
block_size = 4096;
|
||||||
struct arena *ret = g_new(struct arena, 1);
|
struct arena *ret = g_new(struct arena, 1);
|
||||||
struct arena_link *link = (struct arena_link*)g_malloc0(sizeof(struct arena_link) + block_size);
|
struct arena_link *link = (struct arena_link*)g_malloc0(sizeof(struct arena_link) + block_size);
|
||||||
link->free = block_size;
|
link->free = block_size;
|
||||||
link->used = 0;
|
link->used = 0;
|
||||||
link->next = NULL;
|
link->next = NULL;
|
||||||
ret->head = link;
|
ret->head = link;
|
||||||
ret->block_size = 0;
|
ret->block_size = block_size;
|
||||||
|
ret->used = 0;
|
||||||
|
ret->wasted = sizeof(struct arena_link) + sizeof(struct arena) + block_size;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,12 +43,16 @@ void* arena_malloc(arena_t arena, size_t size) {
|
||||||
if (size <= arena->head->free) {
|
if (size <= arena->head->free) {
|
||||||
// fast path..
|
// fast path..
|
||||||
void* ret = arena->head->rest + arena->head->used;
|
void* ret = arena->head->rest + arena->head->used;
|
||||||
|
arena->used += size;
|
||||||
|
arena->wasted -= size;
|
||||||
arena->head->used += size;
|
arena->head->used += size;
|
||||||
arena->head->free -= size;
|
arena->head->free -= size;
|
||||||
return ret;
|
return ret;
|
||||||
} else if (size > arena->block_size) {
|
} else if (size > arena->block_size) {
|
||||||
// We need a new, dedicated block for it, because it won't fit in a standard sized one.
|
// We need a new, dedicated block for it, because it won't fit in a standard sized one.
|
||||||
// This involves some annoying casting...
|
// This involves some annoying casting...
|
||||||
|
arena->used += size;
|
||||||
|
arena->wasted += sizeof(struct arena_link*);
|
||||||
void* link = g_malloc(size + sizeof(struct arena_link*));
|
void* link = g_malloc(size + sizeof(struct arena_link*));
|
||||||
*(struct arena_link**)link = arena->head->next;
|
*(struct arena_link**)link = arena->head->next;
|
||||||
arena->head->next = (struct arena_link*)link;
|
arena->head->next = (struct arena_link*)link;
|
||||||
|
|
@ -55,6 +64,8 @@ void* arena_malloc(arena_t arena, size_t size) {
|
||||||
link->used = size;
|
link->used = size;
|
||||||
link->next = arena->head;
|
link->next = arena->head;
|
||||||
arena->head = link;
|
arena->head = link;
|
||||||
|
arena->used += size;
|
||||||
|
arena->wasted += sizeof(struct arena_link) + arena->block_size - size;
|
||||||
return link->rest;
|
return link->rest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,3 +82,8 @@ void delete_arena(arena_t arena) {
|
||||||
}
|
}
|
||||||
g_free(arena);
|
g_free(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void allocator_stats(arena_t arena, arena_stats_t *stats) {
|
||||||
|
stats->used = arena->used;
|
||||||
|
stats->wasted = arena->wasted;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,12 @@ arena_t new_arena(size_t block_size); // pass 0 for default...
|
||||||
void* arena_malloc(arena_t arena, size_t count) __attribute__(( malloc, alloc_size(2) ));
|
void* arena_malloc(arena_t arena, size_t count) __attribute__(( malloc, alloc_size(2) ));
|
||||||
void delete_arena(arena_t arena);
|
void delete_arena(arena_t arena);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t used;
|
||||||
|
size_t wasted;
|
||||||
|
} arena_stats_t;
|
||||||
|
|
||||||
|
void allocator_stats(arena_t arena, arena_stats_t *stats);
|
||||||
|
|
||||||
|
|
||||||
#endif // #ifndef LIB_ALLOCATOR__H__
|
#endif // #ifndef LIB_ALLOCATOR__H__
|
||||||
|
|
|
||||||
18
src/hammer.c
18
src/hammer.c
|
|
@ -37,10 +37,9 @@ guint djbhash(const uint8_t *buf, size_t len) {
|
||||||
|
|
||||||
parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) {
|
parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) {
|
||||||
// TODO(thequux): add caching here.
|
// TODO(thequux): add caching here.
|
||||||
parser_cache_key_t key = {
|
parser_cache_key_t *key = a_new(parser_cache_key_t, 1);
|
||||||
.input_pos = state->input_stream,
|
key->input_pos = state->input_stream;
|
||||||
.parser = parser
|
key->parser = parser;
|
||||||
};
|
|
||||||
|
|
||||||
// check to see if there is already a result for this object...
|
// check to see if there is already a result for this object...
|
||||||
if (g_hash_table_contains(state->cache, &key)) {
|
if (g_hash_table_contains(state->cache, &key)) {
|
||||||
|
|
@ -50,9 +49,11 @@ parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) {
|
||||||
} else {
|
} else {
|
||||||
// It doesn't exist... run the
|
// It doesn't exist... run the
|
||||||
parse_result_t *res;
|
parse_result_t *res;
|
||||||
if (parser)
|
if (parser) {
|
||||||
res = parser->fn(parser->env, state);
|
res = parser->fn(parser->env, state);
|
||||||
else
|
if (res)
|
||||||
|
res->arena = state->arena;
|
||||||
|
} else
|
||||||
res = NULL;
|
res = NULL;
|
||||||
if (state->input_stream.overrun)
|
if (state->input_stream.overrun)
|
||||||
res = NULL; // overrun is always failure.
|
res = NULL; // overrun is always failure.
|
||||||
|
|
@ -766,7 +767,10 @@ static void test_and(void) {
|
||||||
|
|
||||||
static void test_not(void) {
|
static void test_not(void) {
|
||||||
const parser_t *not_1 = sequence(ch('a'), choice(ch('+'), token((const uint8_t*)"++", 2), NULL), ch('b'), NULL);
|
const parser_t *not_1 = sequence(ch('a'), choice(ch('+'), token((const uint8_t*)"++", 2), NULL), ch('b'), NULL);
|
||||||
const parser_t *not_2 = sequence(ch('a'), choice(sequence(ch('+'), not(ch('+')), NULL), token((const uint8_t*)"", 2), NULL), ch('b'), NULL);
|
const parser_t *not_2 = sequence(ch('a'),
|
||||||
|
choice(sequence(ch('+'), not(ch('+')), NULL),
|
||||||
|
token((const uint8_t*)"++", 2),
|
||||||
|
NULL), ch('b'), NULL);
|
||||||
|
|
||||||
g_check_parse_ok(not_1, "a+b", 3, "(s0x61 s0x2B s0x62)");
|
g_check_parse_ok(not_1, "a+b", 3, "(s0x61 s0x2B s0x62)");
|
||||||
g_check_parse_failed(not_1, "a++b", 4);
|
g_check_parse_failed(not_1, "a++b", 4);
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,17 @@
|
||||||
#define g_check_parse_ok(parser, input, inp_len, result) { \
|
#define g_check_parse_ok(parser, input, inp_len, result) { \
|
||||||
parse_result_t *res = parse(parser, (const uint8_t*)input, inp_len); \
|
parse_result_t *res = parse(parser, (const uint8_t*)input, inp_len); \
|
||||||
if (!res) { \
|
if (!res) { \
|
||||||
g_test_message("Parse failed on line %d", __LINE__); \
|
g_test_message("Parse failed on line %d", __LINE__); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} else { \
|
} else { \
|
||||||
char* cres = write_result_unamb(res->ast); \
|
char* cres = write_result_unamb(res->ast); \
|
||||||
g_check_string(cres, ==, result); \
|
g_check_string(cres, ==, result); \
|
||||||
|
arena_stats_t stats; \
|
||||||
|
allocator_stats(res->arena, &stats); \
|
||||||
|
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
|
||||||
|
"Inefficiency: %5f%%", \
|
||||||
|
stats.used, stats.wasted, \
|
||||||
|
stats.wasted * 100. / (stats.used+stats.wasted)); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue