From 8960e00e264b0f0f17ae9c93fcb19bbcdc6fca0a Mon Sep 17 00:00:00 2001 From: Krasimir Angelov Date: Wed, 9 Feb 2022 10:36:42 +0100 Subject: [PATCH] speed up booting by implementing realloc+padovan --- src/runtime/c/Makefile.am | 2 + src/runtime/c/pgf/db.cxx | 89 +++++++++++++++++++++++++++++++ src/runtime/c/pgf/db.h | 7 +++ src/runtime/c/pgf/phrasetable.cxx | 14 ++--- src/runtime/c/pgf/reader.cxx | 3 +- src/runtime/c/pgf/vector.cxx | 33 ++++++++++++ src/runtime/c/pgf/vector.h | 22 +++++++- 7 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 src/runtime/c/pgf/vector.cxx diff --git a/src/runtime/c/Makefile.am b/src/runtime/c/Makefile.am index 596ae34e5..ce7a94a38 100644 --- a/src/runtime/c/Makefile.am +++ b/src/runtime/c/Makefile.am @@ -12,6 +12,8 @@ libpgf_la_SOURCES = \ pgf/db.h \ pgf/text.cxx \ pgf/text.h \ + pgf/vector.cxx \ + pgf/vector.h \ pgf/pgf.cxx \ pgf/reader.cxx \ pgf/reader.h \ diff --git a/src/runtime/c/pgf/db.cxx b/src/runtime/c/pgf/db.cxx index 5da410cc8..8b97d992d 100644 --- a/src/runtime/c/pgf/db.cxx +++ b/src/runtime/c/pgf/db.cxx @@ -378,6 +378,10 @@ typedef struct mchunk mbin; /* Treat space at ptr + offset as a chunk */ #define chunk_at_offset(p, s) ((mchunk*) (((char *) (p)) + (s))) +/* extract p's inuse bit */ +#define inuse(p) \ + ((((mchunk*) (((char *) (p)) + chunksize(p)))->mchunk_size) & PREV_INUSE) + /* check/set/clear inuse bits in known places */ #define inuse_bit_at_offset(p, s) \ (((mchunk*) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE) @@ -388,8 +392,13 @@ typedef struct mchunk mbin; #define clear_inuse_bit_at_offset(p, s) \ (((mchunk*) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE)) + +/* Set size at head, without disturbing its use bit */ +#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & PREV_INUSE) | (s))) + /* Set size/use field */ #define set_head(p, s) ((p)->mchunk_size = (s)) + /* Set size at footer (only when chunk is not in use) */ #define set_foot(p, s) (((mchunk*) ((char *) (p) + (s)))->mchunk_prev_size = (s)) @@ -1330,6 +1339,86 @@ object PgfDB::malloc_internal(size_t bytes) } } +PGF_INTERNAL +object PgfDB::realloc_internal(object oldo, size_t bytes) +{ + if (oldo == 0) + return malloc_internal(bytes); + + mchunk *newp; /* chunk to return */ + size_t newsize; /* its size */ + mchunk *remainder; /* extra space at end of newp */ + size_t remainder_size; /* its size */ + + size_t nb = request2size(bytes); + + mchunk *oldp = mem2chunk(ptr(ms,oldo)); + size_t oldsize = chunksize(oldp); + mchunk *next = chunk_at_offset(oldp, oldsize); + size_t nextsize = chunksize(next); + + if (oldsize >= nb) { + /* already big enough; split below */ + newp = oldp; + newsize = oldsize; + } else { + /* Try to expand forward into top */ + if (ofs(ms,next) == ms->top && + (unsigned long) (newsize = oldsize + nextsize) >= + (unsigned long) (nb + MINSIZE)) + { + set_head_size(oldp, nb); + remainder = chunk_at_offset(oldp, nb); + ms->top = ofs(ms,remainder); + set_head(remainder, (newsize - nb) | PREV_INUSE); + return oldo; + } + /* Try to expand forward into next chunk; split off remainder below */ + else if (ofs(ms,next) != ms->top && + !inuse(next) && + (unsigned long) (newsize = oldsize + nextsize) >= + (unsigned long) (nb)) + { + newp = oldp; + unlink_chunk(ms, next); + } + /* allocate, copy, free */ + else + { + object newo = malloc_internal(bytes); + newp = mem2chunk(ptr(ms,newo)); + newsize = chunksize(newp); + /* + Avoid copy if newp is next chunk after oldp. + */ + if (newp == next) { + newsize += oldsize; + newp = oldp; + } else { + memcpy(ptr(ms,newo), ptr(ms,oldo), oldsize - sizeof(size_t)); + free_internal(oldo); + return newo; + } + } + } + + /* If possible, free extra space in old or extended chunk */ + assert(newsize >= nb); + remainder_size = newsize - nb; + if (remainder_size < MINSIZE) { /* not enough extra to split off */ + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } else { /* split remainder */ + remainder = chunk_at_offset(newp, nb); + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + /* Mark remainder as inuse so free() won't complain */ + set_inuse_bit_at_offset(remainder, remainder_size); + free_internal(ofs(ms,chunk2mem(remainder))); + } + return ofs(ms,chunk2mem(newp)); +} + PGF_INTERNAL void PgfDB::free_internal(object o) { diff --git a/src/runtime/c/pgf/db.h b/src/runtime/c/pgf/db.h index 6aad89e4a..c7d919e0d 100644 --- a/src/runtime/c/pgf/db.h +++ b/src/runtime/c/pgf/db.h @@ -85,6 +85,11 @@ public: return current_db->malloc_internal(sizeof(A)+extra_bytes); } + template + static ref realloc(ref r, size_t extra_bytes) { + return current_db->realloc_internal(r.as_object(), sizeof(A)+extra_bytes); + } + template static void free(ref o) { current_db->free_internal(o.as_object()); @@ -111,6 +116,8 @@ private: PGF_INTERNAL_DECL void init_state(size_t size); PGF_INTERNAL_DECL object malloc_internal(size_t bytes); + PGF_INTERNAL_DECL object realloc_internal(object oldo, size_t bytes); + PGF_INTERNAL_DECL void free_internal(object o); PGF_INTERNAL_DECL void register_process(); diff --git a/src/runtime/c/pgf/phrasetable.cxx b/src/runtime/c/pgf/phrasetable.cxx index d9aca46e7..fded45661 100644 --- a/src/runtime/c/pgf/phrasetable.cxx +++ b/src/runtime/c/pgf/phrasetable.cxx @@ -316,23 +316,19 @@ ref phrasetable_relink(PgfPhrasetable table, size_t seq_id) { while (table != 0) { - size_t left_sz = table->left->sz; + size_t left_sz = (table->left==0) ? 0 : table->left->sz; if (seq_id < left_sz) table = table->left; else if (seq_id == left_sz) { - size_t len = (table->value.backrefs) - ? table->value.backrefs->list.len - : 0; + size_t len = (table->value.backrefs == 0) + ? 0 + : table->value.backrefs->list.len; ref backrefs = - PgfDB::malloc((len+1)*sizeof(PgfSequenceBackref)); + vector_resize(table->value.backrefs, &PgfSequenceBackrefs::list, len+1); backrefs->ref_count = 1; - backrefs->list.len = len+1; - memcpy(backrefs->list.data, table->value.backrefs->list.data, len*sizeof(PgfSequenceBackref)); backrefs->list.data[len].container = container; backrefs->list.data[len].seq_index = seq_index; - if (table->value.backrefs != 0) - PgfSequenceBackrefs::release(table->value.backrefs); table->value.backrefs = backrefs; return table->value.seq; diff --git a/src/runtime/c/pgf/reader.cxx b/src/runtime/c/pgf/reader.cxx index 1734d4397..ef283c762 100644 --- a/src/runtime/c/pgf/reader.cxx +++ b/src/runtime/c/pgf/reader.cxx @@ -532,8 +532,9 @@ ref>> PgfReader::read_seq_ids(object container) ref seq = phrasetable_relink(concrete->phrasetable, container, i, seq_id); - if (seq == 0) + if (seq == 0) { throw pgf_error("Invalid sequence id"); + } *vector_elem(vec,i) = seq; } return vec; diff --git a/src/runtime/c/pgf/vector.cxx b/src/runtime/c/pgf/vector.cxx new file mode 100644 index 000000000..79fd91eef --- /dev/null +++ b/src/runtime/c/pgf/vector.cxx @@ -0,0 +1,33 @@ +#include "data.h" + +static +uint8_t next_padovan_tbl[] = + {0,1,2,3,4,5 + ,7,7 + ,9,9 + ,12,12,12 + ,16,16,16,16 + ,21,21,21,21,21 + ,28,28,28,28,28,28,28 + ,37,37,37,37,37,37,37,37,37 + }; + +PGF_INTERNAL size_t +get_next_padovan(size_t min) +{ + if (min <= 37) + return next_padovan_tbl[min]; + + size_t a = 49, b = 65, c = 86; + while (min > a) { + if (b < a) { + // overflow + throw pgf_systemerror(ENOMEM); + } + size_t tmp = a + b; + a = b; + b = c; + c = tmp; + } + return a; +} diff --git a/src/runtime/c/pgf/vector.h b/src/runtime/c/pgf/vector.h index 71d2d3235..7bc012923 100644 --- a/src/runtime/c/pgf/vector.h +++ b/src/runtime/c/pgf/vector.h @@ -19,7 +19,27 @@ template inline PGF_INTERNAL ref vector_new(Vector C::* field, size_t len) { ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field); - ref res = PgfDB::malloc>(offset+len*sizeof(A)).as_object()-offset; + ref res = PgfDB::malloc(len*sizeof(A)).as_object(); + (res->*field).len = len; + return res; +} + +PGF_INTERNAL_DECL size_t +get_next_padovan(size_t min); + +template inline PGF_INTERNAL +ref> vector_resize(ref> r, size_t len) +{ + ref> res = PgfDB::realloc>(r,get_next_padovan(len)*sizeof(A)).as_object(); + res->len = len; + return res; +} + +template inline PGF_INTERNAL +ref vector_resize(ref r, Vector C::* field, size_t len) +{ + ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field); + ref res = PgfDB::realloc(r,get_next_padovan(len)*sizeof(A)).as_object(); (res->*field).len = len; return res; }