From 7311047f805cbb6b1c7b47a527c2186316419a2a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 10 Dec 2009 13:24:27 -0800 Subject: [PATCH] Optimize code generator scope access / tweak ivl_net_const performance Child scopes need to be accessed quickly, so use O(LogN) maps for the children instead of O(N) lists. Also, ivl_net_const_s objects exist in huge abundance for some kinds of designs, so put some effort into reducing their memory footprint. --- t-dll-api.cc | 5 ++-- t-dll.cc | 81 +++++++++++++++++++++++++++++++++------------------- t-dll.h | 16 +++++++---- 3 files changed, 65 insertions(+), 37 deletions(-) diff --git a/t-dll-api.cc b/t-dll-api.cc index b10b3fb1b..02e7ab46e 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1606,8 +1606,9 @@ extern "C" int ivl_scope_children(ivl_scope_t net, ivl_scope_f func, void*cd) { - for (ivl_scope_t cur = net->child_; cur; cur = cur->sibling_) { - int rc = func(cur, cd); + for (map::iterator cur = net->children.begin() + ; cur != net->children.end() ; cur ++) { + int rc = func(cur->second, cd); if (rc != 0) return rc; } diff --git a/t-dll.cc b/t-dll.cc index d89bc58d0..769fa1fd6 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -110,23 +110,29 @@ inline const char*dlerror(void) * permanently allocated, and allocating them in blocks reduces the * allocation overhead. */ -static struct ivl_nexus_s * nexus_pool_ptr = 0; -static int nexus_pool_remaining = 0; -static const size_t NEXUS_POOL_SIZE = 4096; + +template void* pool_permalloc(size_t s) +{ + static TYPE * pool_ptr = 0; + static int pool_remaining = 0; + static const size_t POOL_SIZE = 4096; + + assert(s == sizeof(TYPE)); + if (pool_remaining <= 0) { + pool_ptr = new TYPE[POOL_SIZE]; + pool_remaining = POOL_SIZE; + } + + TYPE*tmp = pool_ptr; + pool_ptr += 1; + pool_remaining -= 1; + + return tmp; +} void* ivl_nexus_s::operator new(size_t s) { - assert(s == sizeof(struct ivl_nexus_s)); - if (nexus_pool_remaining <= 0) { - nexus_pool_ptr = new struct ivl_nexus_s[NEXUS_POOL_SIZE]; - nexus_pool_remaining = NEXUS_POOL_SIZE; - } - - struct ivl_nexus_s*tmp = nexus_pool_ptr; - nexus_pool_ptr += 1; - nexus_pool_remaining -= 1; - - return tmp; + return pool_permalloc(s); } void ivl_nexus_s::operator delete(void*, size_t) @@ -134,6 +140,18 @@ void ivl_nexus_s::operator delete(void*, size_t) assert(0); } +void* ivl_net_const_s::operator new(size_t s) +{ + return pool_permalloc(s); +} + +void ivl_net_const_s::operator delete(void*, size_t) +{ + assert(0); +} + +static StringHeapLex net_const_strings; + inline static const char *basename(ivl_scope_t scope, const char *inst) { inst += strlen(ivl_scope_name(scope)); @@ -227,19 +245,19 @@ ivl_attribute_s* dll_target::fill_in_attributes(const Attrib*net) */ static ivl_scope_t find_scope_from_root(ivl_scope_t root, const NetScope*cur) { - ivl_scope_t parent, tmp; - perm_string cur_name = make_scope_name(cur->fullname()); - if (const NetScope*par = cur->parent()) { - parent = find_scope_from_root(root, par); + ivl_scope_t parent = find_scope_from_root(root, par); if (parent == 0) return 0; - for (tmp = parent->child_ ; tmp ; tmp = tmp->sibling_) - if (strcmp(tmp->name_, cur_name) == 0) - return tmp; + map::iterator idx = parent->children.find(cur->fullname()); + if (idx == parent->children.end()) + return 0; + else + return idx->second; } else { + perm_string cur_name = make_scope_name(cur->fullname()); if (strcmp(root->name_, cur_name) == 0) return root; } @@ -559,8 +577,6 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s) perm_string name = s->basename(); root_->name_ = name; FILE_NAME(root_, s); - root_->child_ = 0; - root_->sibling_ = 0; root_->parent = 0; root_->nsigs_ = 0; root_->sigs_ = 0; @@ -2267,6 +2283,8 @@ bool dll_target::net_const(const NetConst*net) { unsigned idx; char*bits; + static char*bits_tmp = 0; + static size_t bits_cnt = 0; struct ivl_net_const_s *obj = new struct ivl_net_const_s; @@ -2281,8 +2299,11 @@ bool dll_target::net_const(const NetConst*net) bits = obj->b.bit_; } else { - obj->b.bits_ = (char*)malloc(obj->width_); - bits = obj->b.bits_; + if (obj->width_+1 > bits_cnt) { + bits_tmp = (char*)realloc(bits_tmp, obj->width_+1); + bits_cnt = obj->width_+1; + } + bits = bits_tmp; } for (idx = 0 ; idx < obj->width_ ; idx += 1) @@ -2305,6 +2326,11 @@ bool dll_target::net_const(const NetConst*net) break; } + if (obj->width_ > sizeof(obj->b.bit_)) { + bits[obj->width_] = 0; + obj->b.bits_ = net_const_strings.make(bits); + } + /* Connect to all the nexus objects. Note that the one-bit case can be handled more efficiently without allocating array space. */ @@ -2375,8 +2401,6 @@ void dll_target::scope(const NetScope*net) scop = new struct ivl_scope_s; scop->name_ = sname; FILE_NAME(scop, net); - scop->child_ = 0; - scop->sibling_ = 0; scop->parent = find_scope(des_, net->parent()); assert(scop->parent); scop->nsigs_ = 0; @@ -2433,8 +2457,7 @@ void dll_target::scope(const NetScope*net) assert(scop->parent != 0); - scop->sibling_= scop->parent->child_; - scop->parent->child_ = scop; + scop->parent->children[net->fullname()] = scop; } } diff --git a/t-dll.h b/t-dll.h index 5006a6ab4..d6e256f7a 100644 --- a/t-dll.h +++ b/t-dll.h @@ -25,6 +25,7 @@ # include "StringHeap.h" # include "netlist.h" # include +# include #if defined(__MINGW32__) #include @@ -426,19 +427,21 @@ struct ivl_lval_s { * structural context. */ struct ivl_net_const_s { - ivl_variable_type_t type; - unsigned width_; - unsigned signed_ : 1; + ivl_variable_type_t type : 3; + unsigned width_ : 24; + unsigned signed_ : 1; union { double real_value; char bit_[sizeof(char*)]; - char *bits_; + const char* bits_; } b; ivl_nexus_t pin_; - ivl_expr_t delay[3]; + + void* operator new (size_t s); + void operator delete(void*obj, size_t s); // Not implemented }; /* @@ -577,7 +580,8 @@ struct ivl_process_s { * there. */ struct ivl_scope_s { - ivl_scope_t child_, sibling_, parent; + ivl_scope_t parent; + std::map children; perm_string name_; perm_string tname_;