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/db.h \
|
||||||
pgf/text.cxx \
|
pgf/text.cxx \
|
||||||
pgf/text.h \
|
pgf/text.h \
|
||||||
|
pgf/vector.cxx \
|
||||||
|
pgf/vector.h \
|
||||||
pgf/pgf.cxx \
|
pgf/pgf.cxx \
|
||||||
pgf/reader.cxx \
|
pgf/reader.cxx \
|
||||||
pgf/reader.h \
|
pgf/reader.h \
|
||||||
|
|||||||
@@ -378,6 +378,10 @@ typedef struct mchunk mbin;
|
|||||||
/* Treat space at ptr + offset as a chunk */
|
/* Treat space at ptr + offset as a chunk */
|
||||||
#define chunk_at_offset(p, s) ((mchunk*) (((char *) (p)) + (s)))
|
#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 */
|
/* check/set/clear inuse bits in known places */
|
||||||
#define inuse_bit_at_offset(p, s) \
|
#define inuse_bit_at_offset(p, s) \
|
||||||
(((mchunk*) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
|
(((mchunk*) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
|
||||||
@@ -388,8 +392,13 @@ typedef struct mchunk mbin;
|
|||||||
#define clear_inuse_bit_at_offset(p, s) \
|
#define clear_inuse_bit_at_offset(p, s) \
|
||||||
(((mchunk*) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
|
(((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 */
|
/* Set size/use field */
|
||||||
#define set_head(p, s) ((p)->mchunk_size = (s))
|
#define set_head(p, s) ((p)->mchunk_size = (s))
|
||||||
|
|
||||||
/* Set size at footer (only when chunk is not in use) */
|
/* Set size at footer (only when chunk is not in use) */
|
||||||
#define set_foot(p, s) (((mchunk*) ((char *) (p) + (s)))->mchunk_prev_size = (s))
|
#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
|
PGF_INTERNAL
|
||||||
void PgfDB::free_internal(object o)
|
void PgfDB::free_internal(object o)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ public:
|
|||||||
return current_db->malloc_internal(sizeof(A)+extra_bytes);
|
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>
|
template<class A>
|
||||||
static void free(ref<A> o) {
|
static void free(ref<A> o) {
|
||||||
current_db->free_internal(o.as_object());
|
current_db->free_internal(o.as_object());
|
||||||
@@ -111,6 +116,8 @@ private:
|
|||||||
PGF_INTERNAL_DECL void init_state(size_t size);
|
PGF_INTERNAL_DECL void init_state(size_t size);
|
||||||
|
|
||||||
PGF_INTERNAL_DECL object malloc_internal(size_t bytes);
|
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 free_internal(object o);
|
||||||
|
|
||||||
PGF_INTERNAL_DECL void register_process();
|
PGF_INTERNAL_DECL void register_process();
|
||||||
|
|||||||
@@ -316,23 +316,19 @@ ref<PgfSequence> phrasetable_relink(PgfPhrasetable table,
|
|||||||
size_t seq_id)
|
size_t seq_id)
|
||||||
{
|
{
|
||||||
while (table != 0) {
|
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)
|
if (seq_id < left_sz)
|
||||||
table = table->left;
|
table = table->left;
|
||||||
else if (seq_id == left_sz) {
|
else if (seq_id == left_sz) {
|
||||||
size_t len = (table->value.backrefs)
|
size_t len = (table->value.backrefs == 0)
|
||||||
? table->value.backrefs->list.len
|
? 0
|
||||||
: 0;
|
: table->value.backrefs->list.len;
|
||||||
|
|
||||||
ref<PgfSequenceBackrefs> backrefs =
|
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->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].container = container;
|
||||||
backrefs->list.data[len].seq_index = seq_index;
|
backrefs->list.data[len].seq_index = seq_index;
|
||||||
if (table->value.backrefs != 0)
|
|
||||||
PgfSequenceBackrefs::release(table->value.backrefs);
|
|
||||||
table->value.backrefs = backrefs;
|
table->value.backrefs = backrefs;
|
||||||
|
|
||||||
return table->value.seq;
|
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,
|
ref<PgfSequence> seq = phrasetable_relink(concrete->phrasetable,
|
||||||
container, i,
|
container, i,
|
||||||
seq_id);
|
seq_id);
|
||||||
if (seq == 0)
|
if (seq == 0) {
|
||||||
throw pgf_error("Invalid sequence id");
|
throw pgf_error("Invalid sequence id");
|
||||||
|
}
|
||||||
*vector_elem(vec,i) = seq;
|
*vector_elem(vec,i) = seq;
|
||||||
}
|
}
|
||||||
return vec;
|
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)
|
ref<C> vector_new(Vector<A> C::* field, size_t len)
|
||||||
{
|
{
|
||||||
ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field);
|
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;
|
(res->*field).len = len;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user