1
0
forked from GitHub/gf-core

speed up booting by implementing realloc+padovan

This commit is contained in:
Krasimir Angelov
2022-02-09 10:36:42 +01:00
parent fdd33b63d9
commit 8960e00e26
7 changed files with 159 additions and 11 deletions

View File

@@ -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 \

View File

@@ -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)
{

View File

@@ -85,6 +85,11 @@ public:
return current_db->malloc_internal(sizeof(A)+extra_bytes);
}
template<class A>
static ref<A> realloc(ref<A> r, size_t extra_bytes) {
return current_db->realloc_internal(r.as_object(), sizeof(A)+extra_bytes);
}
template<class A>
static void free(ref<A> 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();

View File

@@ -316,23 +316,19 @@ ref<PgfSequence> 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<PgfSequenceBackrefs> backrefs =
PgfDB::malloc<PgfSequenceBackrefs>((len+1)*sizeof(PgfSequenceBackref));
vector_resize<PgfSequenceBackrefs,PgfSequenceBackref>(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;

View File

@@ -532,8 +532,9 @@ ref<Vector<ref<PgfSequence>>> PgfReader::read_seq_ids(object container)
ref<PgfSequence> 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;

View File

@@ -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;
}

View File

@@ -19,7 +19,27 @@ template <class C, class A> inline PGF_INTERNAL
ref<C> vector_new(Vector<A> C::* field, size_t len)
{
ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field);
ref<C> res = PgfDB::malloc<Vector<A>>(offset+len*sizeof(A)).as_object()-offset;
ref<C> res = PgfDB::malloc<C>(len*sizeof(A)).as_object();
(res->*field).len = len;
return res;
}
PGF_INTERNAL_DECL size_t
get_next_padovan(size_t min);
template <class A> inline PGF_INTERNAL
ref<Vector<A>> vector_resize(ref<Vector<A>> r, size_t len)
{
ref<Vector<A>> res = PgfDB::realloc<Vector<A>>(r,get_next_padovan(len)*sizeof(A)).as_object();
res->len = len;
return res;
}
template <class C, class A> inline PGF_INTERNAL
ref<C> vector_resize(ref<C> r, Vector<A> C::* field, size_t len)
{
ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field);
ref<C> res = PgfDB::realloc<C>(r,get_next_padovan(len)*sizeof(A)).as_object();
(res->*field).len = len;
return res;
}