forked from GitHub/gf-core
speed up booting by implementing realloc+padovan
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
33
src/runtime/c/pgf/vector.cxx
Normal file
33
src/runtime/c/pgf/vector.cxx
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user