diff --git a/debug/README.md b/debug/README.md index 6ba3a9b906..287bdf098f 100644 --- a/debug/README.md +++ b/debug/README.md @@ -54,6 +54,7 @@ messages of the lower ones. * 103: Show unsubscripted dictionary words and subscripted ones which share the same base word. +* 104: Memory pool statistics. ### 2) -debug=LOCATIONS (-de=LOCATIONS) Show only messages from these LOCATIONS. The LOCATIONS string is a diff --git a/link-grammar/Makefile.am b/link-grammar/Makefile.am index a977026d51..2f4f0c70fa 100644 --- a/link-grammar/Makefile.am +++ b/link-grammar/Makefile.am @@ -98,6 +98,7 @@ liblink_grammar_la_SOURCES = \ linkage/lisjuncts.c \ linkage/sane.c \ linkage/score.c \ + memory-pool.c \ parse/count.c \ parse/extract-links.c \ parse/fast-match.c \ @@ -154,6 +155,7 @@ liblink_grammar_la_SOURCES = \ linkage/lisjuncts.h \ linkage/sane.h \ linkage/score.h \ + memory-pool.h \ parse/count.h \ parse/extract-links.h \ parse/fast-match.h \ diff --git a/link-grammar/api-structures.h b/link-grammar/api-structures.h index 8edc46095a..01d0c20501 100644 --- a/link-grammar/api-structures.h +++ b/link-grammar/api-structures.h @@ -43,6 +43,7 @@ #include "api-types.h" #include "corpus/corpus.h" +#include "memory-pool.h" //#include "error.h" #include "utilities.h" @@ -118,6 +119,8 @@ struct Sentence_s size_t length; /* Number of words */ Word *word; /* Array of words after tokenization */ String_set * string_set; /* Used for assorted strings */ + Pool_desc * fm_Match_node; /* Fast-matcher Match_node memory pool */ + Pool_desc * Table_connector_pool; /* Count memoizing memory pool */ /* Wordgraph stuff. FIXME: create stand-alone struct for these. */ Gword *wordgraph; /* Tokenization wordgraph */ diff --git a/link-grammar/api.c b/link-grammar/api.c index 2d1098364c..540dd636a8 100644 --- a/link-grammar/api.c +++ b/link-grammar/api.c @@ -18,6 +18,7 @@ #include "dict-common/dict-utils.h" // for free_X_nodes #include "disjunct-utils.h" // for free_disjuncts #include "linkage/linkage.h" +#include "memory-pool.h" #include "parse/histogram.h" // for PARSE_NUM_OVERFLOW #include "parse/parse.h" #include "post-process/post-process.h" // for post_process_new() @@ -530,6 +531,8 @@ void sentence_delete(Sentence sent) post_process_free(sent->constituent_pp); global_rand_state = sent->rand_state; + pool_delete(sent->fm_Match_node); + pool_delete(sent->Table_connector_pool); free(sent); } diff --git a/link-grammar/connectors.c b/link-grammar/connectors.c index 0475b5237d..f5fa2a8311 100644 --- a/link-grammar/connectors.c +++ b/link-grammar/connectors.c @@ -424,9 +424,7 @@ void sort_condesc_by_uc_constring(Dictionary dict) void condesc_delete(Dictionary dict) { - for (size_t i = 0; i < dict->contable.size; i++) - free(dict->contable.hdesc[i]); - + pool_delete(dict->contable.mempool); free(dict->contable.hdesc); free(dict->contable.sdesc); } @@ -454,8 +452,7 @@ static void condesc_table_alloc(ConTable *ct, size_t size) static bool condesc_insert(ConTable *ct, condesc_t **h, const char *constring, int hash) { - *h = (condesc_t *)malloc(sizeof(condesc_t)); - memset(*h, 0, sizeof(condesc_t)); + *h = pool_alloc(ct->mempool); (*h)->str_hash = hash; (*h)->string = constring; ct->num_con++; @@ -498,6 +495,9 @@ condesc_t *condesc_add(ConTable *ct, const char *constring) { condesc_table_alloc(ct, ct->num_con); ct->num_con = 0; + ct->mempool = pool_new(__func__, "ConTable", + /*num_elements*/1024, sizeof(condesc_t), + /*zero_out*/true, /*align*/true, /*exact*/false); } int hash = connector_str_hash(constring); diff --git a/link-grammar/connectors.h b/link-grammar/connectors.h index cbf7faefc8..ef8b9a6618 100644 --- a/link-grammar/connectors.h +++ b/link-grammar/connectors.h @@ -21,6 +21,7 @@ #include "api-types.h" #include "lg_assert.h" +#include "memory-pool.h" #include "string-set.h" /* MAX_SENTENCE cannot be more than 254, because word MAX_SENTENCE+1 is @@ -81,6 +82,7 @@ typedef struct size_t size; /* Allocated size */ size_t num_con; /* Number of connector types */ size_t num_uc; /* Number of connector types with different UC part */ + Pool_desc *mempool; length_limit_def_t *length_limit_def; length_limit_def_t **length_limit_def_next; } ConTable; diff --git a/link-grammar/memory-pool.c b/link-grammar/memory-pool.c new file mode 100644 index 0000000000..a6a76767fd --- /dev/null +++ b/link-grammar/memory-pool.c @@ -0,0 +1,272 @@ +/*************************************************************************/ +/* Copyright (c) 2018 Amir Plivatsky */ +/* All rights reserved */ +/* */ +/* Use of the link grammar parsing system is subject to the terms of the */ +/* license set forth in the LICENSE file included with this software. */ +/* This license allows free redistribution and use in source and binary */ +/* forms, with or without modification, subject to certain conditions. */ +/* */ +/*************************************************************************/ + +#include // errno +#include // strerror_r + +#include "error.h" +#include "memory-pool.h" +#include "utilities.h" // MIN, MAX, aligned alloc + +/* TODO: Add valgrind descriptions. See: + * http://valgrind.org/docs/manual/mc-manual.html#mc-manual.mempools */ + +/** + * Align given size to the nearest upper power of 2 + * for sizefunc = func; + mp->name = name; + + if (align) + { + mp->element_size = align_size(element_size); + mp->alignment = MAX(MIN_ALIGNMENT, mp->element_size); + mp->alignment = MIN(MAX_ALIGNMENT, mp->alignment); + mp->data_size = num_elements * mp->element_size; + mp->block_size = ALIGN(mp->data_size + FLDSIZE_NEXT, mp->alignment); + } + else + { + mp->element_size = element_size; + mp->alignment = MIN_ALIGNMENT; + mp->data_size = num_elements * mp->element_size; + mp->block_size = mp->data_size + FLDSIZE_NEXT; + } + + mp->zero_out = zero_out; + mp->exact = exact; + mp->alloc_next = NULL; + mp->chain = NULL; + mp->ring = NULL; + mp->free_list = NULL; + mp->curr_elements = 0; + mp->num_elements = num_elements; + + lgdebug(+D_MEMPOOL, "%sElement size %zu, alignment %zu (pool '%s' created in %s())\n", + POOL_ALLOCATOR?"":"(Fake pool allocator) ", + mp->element_size, mp->alignment, mp->name, mp->func); + return mp; +} + +/** + * Delete the given memory pool. + */ +void pool_delete(Pool_desc *mp) +{ + if (NULL == mp) return; + lgdebug(+D_MEMPOOL, "Used %zu elements (pool '%s' created in %s())\n", + mp->curr_elements, mp->name, mp->func); + + /* Free its chained memory blocks. */ + char *c_next; + size_t alloc_size; +#if POOL_ALLOCATOR + alloc_size = mp->data_size; +#else + alloc_size = mp->element_size; +#endif + for (char *c = mp->chain; c != NULL; c = c_next) + { + c_next = POOL_NEXT_BLOCK(c, alloc_size); +#if POOL_ALLOCATOR + aligned_free(c); +#else + free(c); +#endif + } + free(mp); +} + +#if POOL_ALLOCATOR +/** + * Allocate an element from the requested pool. + * This function uses the feature that pointers to void and char are + * interchangeable. + * 1. If no current block of current block exhausted - obtain another one + * and chain it the block chain. Else reuse an LRU unused block; + * The element pointer is aligned to the required alignment. + * 2. zero the block if required; + * 3. Return element pointer. + */ +void *pool_alloc(Pool_desc *mp) +{ +#ifdef POOL_FREE + if (NULL != mp->free_list) + { + void *alloc_next = mp->free_list; + mp->free_list = *(char **)mp->free_list; + if (mp->zero_out) memset(alloc_next, 0, mp->element_size); + return alloc_next; + } +#endif // POOL_FREE + + mp->curr_elements++; /* For stats. */ + + if ((NULL == mp->alloc_next) || (mp->alloc_next == mp->ring + mp->data_size)) + { + assert(!mp->exact || (NULL == mp->alloc_next), + "Too many elements %zu>%zu (pool '%s' created in %s())", + mp->curr_elements, mp->num_elements, mp->name, mp->func); + + /* No current block or current block exhausted - obtain another one. */ + char *prev = mp->ring; + if (NULL != mp->ring) + mp->ring = POOL_NEXT_BLOCK(mp->ring, mp->data_size); + + if (NULL == mp->ring) + { + /* Allocate a new block and chain it. */ + mp->ring = aligned_alloc(mp->alignment, mp->block_size); + if (NULL == mp->ring) + { + /* aligned_alloc() has strict requirements. */ + char errbuf[64]; + strerror_r(errno, errbuf, sizeof(errbuf)); + assert(NULL == mp->ring, "Block/element sizes %zu/%zu: %s", + mp->block_size, mp->element_size, errbuf); + } + if (NULL == mp->alloc_next) + mp->chain = mp->ring; + else + POOL_NEXT_BLOCK(prev, mp->data_size) = mp->ring; + POOL_NEXT_BLOCK(mp->ring, mp->data_size) = NULL; + //printf("New ring %p next %p\n", mp->ring, + //POOL_NEXT_BLOCK(mp->ring, mp->data_size)); + } /* Else reuse existing block. */ + + if (mp->zero_out) memset(mp->ring, 0, mp->data_size); + mp->alloc_next = mp->ring; + } + + /* Grab a new element. */ + void *alloc_next = mp->alloc_next; + mp->alloc_next += mp->element_size; + return alloc_next; +} + +/** + * Reuse the given memory pool. + * Reset the pool pointers without freeing its memory. + * pool_alloc() will then reuse the existing pool blocks before allocating + * new blocks. + */ +void pool_reuse(Pool_desc *mp) +{ + lgdebug(+D_MEMPOOL, "Used %zu elements (pool '%s' created in %s())\n", + mp->curr_elements, mp->name, mp->func); + mp->ring = mp->chain; + mp->alloc_next = NULL; +} + +#ifdef POOL_FREE +/** + * Free elements. They are added to a free list that is used by + * pool_alloc() before it allocates from memory blocks. + * XXX Unchecked. + */ +void pool_free(Pool_desc *mp, void *e) +{ + assert(mp->element_size >= FLDSIZE_NEXT); + if (NULL == e) return; + + char *next = mp->free_list; + mp->free_list = e; + *(char **)e = next; +} +#endif // POOL_FREE + +#else // !POOL_ALLOCATOR + +/* A dummy pool allocator - for debugging (see the comment in memory-pool.h). + * Note: No Doxygen headers because these function replace functions with + * the same name defined above. */ + +/* + * Allocate an element by using malloc() directly. + */ +void *pool_alloc(Pool_desc *mp) +{ + mp->curr_elements++; + assert(!mp->exact || mp->curr_elements <= mp->num_elements, + "Too many elements (%zu>%zu) (pool '%s' created in %s())", + mp->curr_elements, mp->num_elements, mp->name, mp->func); + + /* Allocate a new element and chain it. */ + char *next = mp->chain; + mp->chain = malloc(mp->element_size + FLDSIZE_NEXT); + POOL_NEXT_BLOCK(mp->chain, mp->element_size) = next; + + void *alloc_next = mp->chain; + if (mp->zero_out) memset(alloc_next, 0, mp->element_size); + + return alloc_next; +} + +/* + * Reuse the given fake memory pool by freeing its memory. + */ +void pool_reuse(Pool_desc *mp) +{ + if (NULL == mp) return; + lgdebug(+D_MEMPOOL, "Used %zu elements (pool '%s' created in %s())\n", + mp->curr_elements, mp->name, mp->func); + + /* Free its chained memory blocks. */ + char *c_next; + for (char *c = mp->chain; c != NULL; c = c_next) + { + c_next = POOL_NEXT_BLOCK(c, mp->element_size); + free(c); + } + + mp->chain = NULL; +} + +#ifdef POOL_FREE +void pool_free(Pool_desc *mp, void *e) +{ + free(e); +} +#endif // POOL_FREE +#endif // POOL_ALLOCATOR diff --git a/link-grammar/memory-pool.h b/link-grammar/memory-pool.h new file mode 100644 index 0000000000..983a278c27 --- /dev/null +++ b/link-grammar/memory-pool.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* Copyright (c) 2018 Amir Plivatsky */ +/* All rights reserved */ +/* */ +/* Use of the link grammar parsing system is subject to the terms of the */ +/* license set forth in the LICENSE file included with this software. */ +/* This license allows free redistribution and use in source and binary */ +/* forms, with or without modification, subject to certain conditions. */ +/* */ +/*************************************************************************/ + +#ifndef _MEMORY_POOL_H +#define _MEMORY_POOL_H + +#include "link-grammar/link-includes.h" +#include "link-grammar/utilities.h" // GNUC_MALLOC (XXX separate include?) + +#define D_MEMPOOL (D_SPEC+4) +#define MIN_ALIGNMENT sizeof(void *) // Minimum element alignment. +#define MAX_ALIGNMENT 64 // Maximum element alignment. + +typedef struct Pool_desc_s Pool_desc; + +/* See below the definition of pool_new(). */ +Pool_desc *pool_new(const char *, const char *, size_t, size_t, bool, bool, bool); +void *pool_alloc(Pool_desc *) GNUC_MALLOC; +void pool_reuse(Pool_desc *); +void pool_delete(Pool_desc *); +void pool_free(Pool_desc *, void *e); + +/* Pool allocator debug facility: + * If configured with "CFLAGS=-DPOOL_ALLOCATOR=0", a fake pool allocator + * that uses malloc() for each allocation is defined, in order that ASAN + * or valgrind can be used to find memory usage bugs. + */ + +#ifndef POOL_ALLOCATOR +#define POOL_ALLOCATOR 1 +#endif + +#define FLDSIZE_NEXT sizeof(char *) // "next block" field size +#define POOL_NEXT_BLOCK(blk, offset_next) (*(char **)((blk)+(offset_next))) + +struct Pool_desc_s +{ + /* Used only by the real pool allocator. */ + char *chain; // Allocated blocks. */ + char *ring; // Current area for allocation. + char *alloc_next; // Next element to be allocated. + char *free_list; // Allocations that got freed. + size_t block_size; // Block size for pool extension. + size_t data_size; // Size of data inside block_size. + size_t alignment; // Alignment of element allocation. + + /* Common to the real and fake pool allocators. */ + size_t element_size; // Allocated memory per element. + const char *name; // Pool name. + const char *func; // Invoker of pool_new(). + + /* For debug and stats. */ + size_t num_elements; + size_t curr_elements; + + /* Flags that are used by pool_alloc(). */ + bool zero_out; // Zero out allocated elements. + bool exact; // Abort if more than num_elements are needed. +}; +#endif // _MEMORY_POOL_H diff --git a/link-grammar/parse/count.c b/link-grammar/parse/count.c index 9757f67e1d..26b8a18f20 100644 --- a/link-grammar/parse/count.c +++ b/link-grammar/parse/count.c @@ -37,7 +37,7 @@ struct Table_connector_s struct count_context_s { fast_matcher_t *mchxt; - Word * local_sent; + Sentence sent; /* int null_block; */ /* not used, always 1 */ bool islands_ok; bool null_links; @@ -51,17 +51,6 @@ struct count_context_s static void free_table(count_context_t *ctxt) { - int i; - Table_connector *t, *x; - - for (i=0; itable_size; i++) - { - for(t = ctxt->table[i]; t!= NULL; t=x) - { - x = t->next; - xfree((void *) t, sizeof(Table_connector)); - } - } xfree(ctxt->table, ctxt->table_size * sizeof(Table_connector*)); ctxt->table = NULL; ctxt->table_size = 0; @@ -93,6 +82,8 @@ static void init_table(count_context_t *ctxt, size_t sent_len) ctxt->table = (Table_connector**) xalloc(ctxt->table_size * sizeof(Table_connector*)); memset(ctxt->table, 0, ctxt->table_size*sizeof(Table_connector*)); + + } #ifdef DEBUG @@ -154,7 +145,7 @@ static Table_connector * table_store(count_context_t *ctxt, Table_connector *t, *n; unsigned int h; - n = (Table_connector *) xalloc(sizeof(Table_connector)); + n = pool_alloc(ctxt->sent->Table_connector_pool); n->lw = lw; n->rw = rw; n->le = le; n->re = re; n->null_count = null_count; h = pair_hash(ctxt->table_size, lw, rw, le, re, null_count); t = ctxt->table[h]; @@ -250,7 +241,7 @@ static int num_optional_words(count_context_t *ctxt, int w1, int w2) int n = 0; for (int w = w1+1; w < w2; w++) - if (ctxt->local_sent[w].optional) n++; + if (ctxt->sent->word[w].optional) n++; return n; } @@ -381,10 +372,10 @@ static Count_bin do_count( * of null words. */ t->count = zero; w = lw + 1; - for (int opt = 0; opt <= !!ctxt->local_sent[w].optional; opt++) + for (int opt = 0; opt <= !!ctxt->sent->word[w].optional; opt++) { null_count += opt; - for (Disjunct *d = ctxt->local_sent[w].d; d != NULL; d = d->next) + for (Disjunct *d = ctxt->sent->word[w].d; d != NULL; d = d->next) { if (d->left == NULL) { @@ -664,7 +655,7 @@ Count_bin do_parse(Sentence sent, ctxt->current_resources = opts->resources; ctxt->exhausted = false; ctxt->checktimer = 0; - ctxt->local_sent = sent->word; + ctxt->sent = sent; /* consecutive blocks of this many words are considered as * one null link. */ @@ -678,12 +669,24 @@ Count_bin do_parse(Sentence sent, } /* sent_length is used only as a hint for the hash table size ... */ -count_context_t * alloc_count_context(size_t sent_length) +count_context_t * alloc_count_context(Sentence sent) { count_context_t *ctxt = (count_context_t *) xalloc (sizeof(count_context_t)); memset(ctxt, 0, sizeof(count_context_t)); - init_table(ctxt, sent_length); + if (NULL != sent->Table_connector_pool) + { + pool_reuse(sent->Table_connector_pool); + } + else + { + sent->Table_connector_pool = + pool_new(__func__, "Table_connector", + /*num_elements*/10240, sizeof(Table_connector), + /*zero_out*/false, /*align*/false, /*exact*/false); + } + + init_table(ctxt, sent->length); return ctxt; } diff --git a/link-grammar/parse/count.h b/link-grammar/parse/count.h index 2394158a2a..db97c4a223 100644 --- a/link-grammar/parse/count.h +++ b/link-grammar/parse/count.h @@ -21,6 +21,6 @@ typedef struct count_context_s count_context_t; Count_bin* table_lookup(count_context_t *, int, int, Connector *, Connector *, unsigned int); Count_bin do_parse(Sentence, fast_matcher_t*, count_context_t*, int null_count, Parse_Options); -count_context_t* alloc_count_context(size_t); +count_context_t* alloc_count_context(Sentence); void free_count_context(count_context_t*, Sentence); #endif /* _COUNT_H */ diff --git a/link-grammar/parse/fast-match.c b/link-grammar/parse/fast-match.c index 48fa4c9226..03aaa2be75 100644 --- a/link-grammar/parse/fast-match.c +++ b/link-grammar/parse/fast-match.c @@ -83,35 +83,16 @@ static void push_match_list_element(fast_matcher_t *ctxt, Disjunct *d) ctxt->match_list[ctxt->match_list_end++] = d; } -static void free_match_list(Match_node * t) -{ - Match_node *xt; - for (; t!=NULL; t=xt) { - xt = t->next; - xfree((char *)t, sizeof(Match_node)); - } -} - /** * Free all of the hash tables and Match_nodes */ -void free_fast_matcher(fast_matcher_t *mchxt) +void free_fast_matcher(Sentence sent, fast_matcher_t *mchxt) { - size_t w; - unsigned int i; - if (NULL == mchxt) return; - for (w = 0; w < mchxt->size; w++) + + for (WordIdx w = 0; w < mchxt->size; w++) { - for (i = 0; i < mchxt->l_table_size[w]; i++) - { - free_match_list(mchxt->l_table[w][i]); - } xfree((char *)mchxt->l_table[w], mchxt->l_table_size[w] * sizeof (Match_node *)); - for (i = 0; i < mchxt->r_table_size[w]; i++) - { - free_match_list(mchxt->r_table[w][i]); - } xfree((char *)mchxt->r_table[w], mchxt->r_table_size[w] * sizeof (Match_node *)); } @@ -242,12 +223,13 @@ static Match_node **get_match_table_entry(unsigned int size, Match_node **t, * dir = 1, we're putting this into a right table. * dir = -1, we're putting this into a left table. */ -static void put_into_match_table(unsigned int size, Match_node ** t, - Disjunct * d, Connector * c, int dir ) +static void put_into_match_table(Sentence sent, unsigned int size, + Match_node ** t, Disjunct * d, + Connector * c, int dir) { Match_node *m, **xl; - m = (Match_node *) xalloc (sizeof(Match_node)); + m = pool_alloc(sent->fm_Match_node); m->next = NULL; m->d = d; @@ -283,6 +265,18 @@ fast_matcher_t* alloc_fast_matcher(const Sentence sent) ctxt->match_list = xalloc(ctxt->match_list_size * sizeof(*ctxt->match_list)); ctxt->match_list_end = 0; + if (NULL != sent->fm_Match_node) + { + pool_reuse(sent->fm_Match_node); + } + else + { + sent->fm_Match_node = + pool_new(__func__, "Match_node", + /*num_elements*/2048, sizeof(Match_node), + /*zero_out*/false, /*align*/true, /*exact*/false); + } + for (w=0; wlength; w++) { len = left_disjunct_list_length(sent->word[w].d); @@ -297,7 +291,7 @@ fast_matcher_t* alloc_fast_matcher(const Sentence sent) if (d->left != NULL) { //printf("%s %d\n", connector_string(d->left), d->left->length_limit); - put_into_match_table(size, t, d, d->left, -1); + put_into_match_table(sent, size, t, d, d->left, -1); } } @@ -313,7 +307,7 @@ fast_matcher_t* alloc_fast_matcher(const Sentence sent) if (d->right != NULL) { //printf("%s %d\n", connector_string(d->right), d->right->length_limit); - put_into_match_table(size, t, d, d->right, 1); + put_into_match_table(sent, size, t, d, d->right, 1); } } } diff --git a/link-grammar/parse/fast-match.h b/link-grammar/parse/fast-match.h index 279eaaa2fa..9e22ea935e 100644 --- a/link-grammar/parse/fast-match.h +++ b/link-grammar/parse/fast-match.h @@ -16,6 +16,7 @@ #include // for size_t #include "api-types.h" #include "link-includes.h" // for Sentence +#include "memory-pool.h" typedef struct Match_node_struct Match_node; struct Match_node_struct @@ -43,7 +44,7 @@ struct fast_matcher_s /* See the source file for documentation. */ fast_matcher_t* alloc_fast_matcher(const Sentence); -void free_fast_matcher(fast_matcher_t*); +void free_fast_matcher(Sentence sent, fast_matcher_t*); size_t form_match_list(fast_matcher_t *, int, Connector *, int, Connector *, int); diff --git a/link-grammar/parse/parse.c b/link-grammar/parse/parse.c index d7fbe8b3e7..b1e5adea5e 100644 --- a/link-grammar/parse/parse.c +++ b/link-grammar/parse/parse.c @@ -380,9 +380,9 @@ void classic_parse(Sentence sent, Parse_Options opts) if (resources_exhausted(opts->resources)) break; free_count_context(ctxt, sent); - free_fast_matcher(mchxt); + free_fast_matcher(sent, mchxt); pack_sentence(sent); - ctxt = alloc_count_context(sent->length); + ctxt = alloc_count_context(sent); mchxt = alloc_fast_matcher(sent); print_time(opts, "Initialized fast matcher"); } @@ -428,5 +428,5 @@ void classic_parse(Sentence sent, Parse_Options opts) free_disjuncts(disjuncts_copy[i]); } free_count_context(ctxt, sent); - free_fast_matcher(mchxt); + free_fast_matcher(sent, mchxt); } diff --git a/link-grammar/parse/prune.c b/link-grammar/parse/prune.c index faba158620..6e8647bd18 100644 --- a/link-grammar/parse/prune.c +++ b/link-grammar/parse/prune.c @@ -56,6 +56,7 @@ struct power_table_s unsigned int *r_table_size; C_list *** l_table; C_list *** r_table; + Pool_desc *memory_pool; }; typedef struct cms_struct Cms; @@ -180,35 +181,15 @@ struct prune_context_s deletable, this is equivalent to RUTHLESS. --DS, 7/97 */ -static void free_C_list(C_list * t) -{ - C_list *xt; - for (; t!=NULL; t=xt) { - xt = t->next; - xfree((char *)t, sizeof(C_list)); - } -} - /** * free all of the hash tables and C_lists */ static void power_table_delete(power_table *pt) { - unsigned int w; - unsigned int i; - - for (w = 0; w < pt->power_table_size; w++) + pool_delete(pt->memory_pool); + for (WordIdx w = 0; w < pt->power_table_size; w++) { - for (i = 0; i < pt->l_table_size[w]; i++) - { - free_C_list(pt->l_table[w][i]); - } xfree((char *)pt->l_table[w], pt->l_table_size[w] * sizeof (C_list *)); - - for (i = 0; i < pt->r_table_size[w]; i++) - { - free_C_list(pt->r_table[w][i]); - } xfree((char *)pt->r_table[w], pt->r_table_size[w] * sizeof (C_list *)); } xfree(pt->l_table_size, 2 * pt->power_table_size * sizeof(unsigned int)); @@ -220,12 +201,11 @@ static void power_table_delete(power_table *pt) * The disjunct d (whose left or right pointer points to c) is put * into the appropriate hash table */ -static void put_into_power_table(unsigned int size, C_list ** t, Connector * c, bool shal) +static void put_into_power_table(C_list * m, unsigned int size, C_list ** t, + Connector * c, bool shal) { unsigned int h; - C_list * m; h = connector_uc_num(c) & (size-1); - m = (C_list *) xalloc (sizeof(C_list)); m->next = t[h]; t[h] = m; m->c = c; @@ -253,6 +233,10 @@ static power_table * power_table_new(Sentence sent) pt->l_table = xalloc (2 * sent->length * sizeof(C_list **)); pt->r_table = pt->l_table + sent->length; + Pool_desc *mp = pt->memory_pool = pool_new(__func__, "C_list", + /*num_elements*/2048, sizeof(C_list), + /*zero_out*/false, /*align*/false, /*exact*/false); + for (w=0; wlength; w++) { /* The below uses variable-sized hash tables. This seems to @@ -279,9 +263,9 @@ static power_table * power_table_new(Sentence sent) for (d=sent->word[w].d; d!=NULL; d=d->next) { c = d->left; if (c != NULL) { - put_into_power_table(size, t, c, true); + put_into_power_table(pool_alloc(mp), size, t, c, true); for (c=c->next; c!=NULL; c=c->next) { - put_into_power_table(size, t, c, false); + put_into_power_table(pool_alloc(mp), size, t, c, false); } } } @@ -295,9 +279,9 @@ static power_table * power_table_new(Sentence sent) for (d=sent->word[w].d; d!=NULL; d=d->next) { c = d->right; if (c != NULL) { - put_into_power_table(size, t, c, true); + put_into_power_table(pool_alloc(mp), size, t, c, true); for (c=c->next; c!=NULL; c=c->next){ - put_into_power_table(size, t, c, false); + put_into_power_table(pool_alloc(mp), size, t, c, false); } } } @@ -322,8 +306,6 @@ static void clean_table(unsigned int size, C_list ** t) if (m->c->nearest_word != BAD_WORD) { m->next = head; head = m; - } else { - xfree((char *) m, sizeof(C_list)); } } t[i] = head; diff --git a/link-grammar/utilities.c b/link-grammar/utilities.c index c37e1f95a5..acf4314498 100644 --- a/link-grammar/utilities.c +++ b/link-grammar/utilities.c @@ -12,6 +12,9 @@ /*************************************************************************/ #include +#ifdef HAVE_POSIX_MEMALIGN +#include +#endif #include #ifdef _WIN32 #define _CRT_RAND_S @@ -281,6 +284,21 @@ void upcase_utf8_str(char *to, const char * from, size_t usize, locale_t locale) } #endif +#ifdef NO_ALIGNED_MALLOC +#if __GNUC__ +#warning No aligned alloc found (using malloc() instead). +#endif +#endif /* NO_ALIGNED_MALLOC */ + +#ifdef HAVE_POSIX_MEMALIGN +void *aligned_alloc(size_t alignment, size_t size) +{ + void *ptr; + errno = posix_memalign(&ptr, alignment, size); + return ptr; +} +#endif /* HAVE_POSIX_MEMALIGN */ + /* ============================================================= */ /* Memory alloc routines below. These routines attempt to keep * track of how much space is getting used during a parse. diff --git a/link-grammar/utilities.h b/link-grammar/utilities.h index 470b65cf52..267db7513e 100644 --- a/link-grammar/utilities.h +++ b/link-grammar/utilities.h @@ -81,6 +81,8 @@ void *alloca (size_t); #define vsnprintf _vsnprintf #endif +#define HAVE__ALIGNED_MALLOC 1 + /* Avoid plenty of: warning C4090: 'function': different 'const' qualifiers. * This happens, for example, when the argument is "const void **". */ #define free(x) free((void *)x) @@ -171,6 +173,26 @@ typedef int locale_t; #define freelocale(l) #endif /* HAVE_LOCALE_T */ +#if HAVE__ALIGNED_MALLOC +#define aligned_alloc(alignment, size) _aligned_malloc (size, alignment) +#define aligned_free(p) _aligned_free(p) +#undef HAVE_POSIX_MEMALIGN + +#elif HAVE_ALIGNED_ALLOC +#define aligned_free(p) free(p) +#undef HAVE_POSIX_MEMALIGN + +#elif HAVE_POSIX_MEMALIGN +/* aligned_alloc() emulation will be defined in utilities.c. */ +void *aligned_alloc(size_t alignment, size_t size); +#define aligned_free(p) free(p) + +#else +/* Fallback to just malloc(), as alignment is not critical here. */ +#define NO_ALIGNED_MALLOC /* For generating a warning in utilities.c. */ +#define aligned_alloc(alignment, size) malloc(size) +#define aligned_free(p) free(p) +#endif /* HAVE__ALIGNED_MALLOC */ #define ALIGN(size, alignment) (((size)+(alignment-1))&~(alignment-1)) diff --git a/msvc14/LinkGrammar.vcxproj b/msvc14/LinkGrammar.vcxproj index caba462fcc..9e7673a00a 100644 --- a/msvc14/LinkGrammar.vcxproj +++ b/msvc14/LinkGrammar.vcxproj @@ -261,6 +261,7 @@ + @@ -312,6 +313,7 @@ + diff --git a/msvc14/LinkGrammar.vcxproj.filters b/msvc14/LinkGrammar.vcxproj.filters index e7f4d7a613..d5e3093e35 100644 --- a/msvc14/LinkGrammar.vcxproj.filters +++ b/msvc14/LinkGrammar.vcxproj.filters @@ -162,6 +162,9 @@ Source Files + + Source Files + @@ -335,6 +338,9 @@ Header Files + + Header Files + @@ -344,4 +350,4 @@ Source Files - \ No newline at end of file +