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.
This commit is contained in:
Stephen Williams 2009-12-10 13:24:27 -08:00
parent 534207bb83
commit 7311047f80
3 changed files with 65 additions and 37 deletions

View File

@ -1606,8 +1606,9 @@ extern "C" int ivl_scope_children(ivl_scope_t net,
ivl_scope_f func, ivl_scope_f func,
void*cd) void*cd)
{ {
for (ivl_scope_t cur = net->child_; cur; cur = cur->sibling_) { for (map<hname_t,ivl_scope_t>::iterator cur = net->children.begin()
int rc = func(cur, cd); ; cur != net->children.end() ; cur ++) {
int rc = func(cur->second, cd);
if (rc != 0) if (rc != 0)
return rc; return rc;
} }

View File

@ -110,23 +110,29 @@ inline const char*dlerror(void)
* permanently allocated, and allocating them in blocks reduces the * permanently allocated, and allocating them in blocks reduces the
* allocation overhead. * allocation overhead.
*/ */
static struct ivl_nexus_s * nexus_pool_ptr = 0;
static int nexus_pool_remaining = 0; template <class TYPE> void* pool_permalloc(size_t s)
static const size_t NEXUS_POOL_SIZE = 4096; {
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) void* ivl_nexus_s::operator new(size_t s)
{ {
assert(s == sizeof(struct ivl_nexus_s)); return pool_permalloc<struct ivl_nexus_s>(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;
} }
void ivl_nexus_s::operator delete(void*, size_t) void ivl_nexus_s::operator delete(void*, size_t)
@ -134,6 +140,18 @@ void ivl_nexus_s::operator delete(void*, size_t)
assert(0); assert(0);
} }
void* ivl_net_const_s::operator new(size_t s)
{
return pool_permalloc<struct ivl_net_const_s>(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) inline static const char *basename(ivl_scope_t scope, const char *inst)
{ {
inst += strlen(ivl_scope_name(scope)); 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) 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()) { 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) if (parent == 0)
return 0; return 0;
for (tmp = parent->child_ ; tmp ; tmp = tmp->sibling_) map<hname_t,ivl_scope_t>::iterator idx = parent->children.find(cur->fullname());
if (strcmp(tmp->name_, cur_name) == 0) if (idx == parent->children.end())
return tmp; return 0;
else
return idx->second;
} else { } else {
perm_string cur_name = make_scope_name(cur->fullname());
if (strcmp(root->name_, cur_name) == 0) if (strcmp(root->name_, cur_name) == 0)
return root; return root;
} }
@ -559,8 +577,6 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s)
perm_string name = s->basename(); perm_string name = s->basename();
root_->name_ = name; root_->name_ = name;
FILE_NAME(root_, s); FILE_NAME(root_, s);
root_->child_ = 0;
root_->sibling_ = 0;
root_->parent = 0; root_->parent = 0;
root_->nsigs_ = 0; root_->nsigs_ = 0;
root_->sigs_ = 0; root_->sigs_ = 0;
@ -2267,6 +2283,8 @@ bool dll_target::net_const(const NetConst*net)
{ {
unsigned idx; unsigned idx;
char*bits; 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; 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_; bits = obj->b.bit_;
} else { } else {
obj->b.bits_ = (char*)malloc(obj->width_); if (obj->width_+1 > bits_cnt) {
bits = obj->b.bits_; 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) for (idx = 0 ; idx < obj->width_ ; idx += 1)
@ -2305,6 +2326,11 @@ bool dll_target::net_const(const NetConst*net)
break; 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 /* Connect to all the nexus objects. Note that the one-bit
case can be handled more efficiently without allocating case can be handled more efficiently without allocating
array space. */ array space. */
@ -2375,8 +2401,6 @@ void dll_target::scope(const NetScope*net)
scop = new struct ivl_scope_s; scop = new struct ivl_scope_s;
scop->name_ = sname; scop->name_ = sname;
FILE_NAME(scop, net); FILE_NAME(scop, net);
scop->child_ = 0;
scop->sibling_ = 0;
scop->parent = find_scope(des_, net->parent()); scop->parent = find_scope(des_, net->parent());
assert(scop->parent); assert(scop->parent);
scop->nsigs_ = 0; scop->nsigs_ = 0;
@ -2433,8 +2457,7 @@ void dll_target::scope(const NetScope*net)
assert(scop->parent != 0); assert(scop->parent != 0);
scop->sibling_= scop->parent->child_; scop->parent->children[net->fullname()] = scop;
scop->parent->child_ = scop;
} }
} }

16
t-dll.h
View File

@ -25,6 +25,7 @@
# include "StringHeap.h" # include "StringHeap.h"
# include "netlist.h" # include "netlist.h"
# include <vector> # include <vector>
# include <map>
#if defined(__MINGW32__) #if defined(__MINGW32__)
#include <windows.h> #include <windows.h>
@ -426,19 +427,21 @@ struct ivl_lval_s {
* structural context. * structural context.
*/ */
struct ivl_net_const_s { struct ivl_net_const_s {
ivl_variable_type_t type; ivl_variable_type_t type : 3;
unsigned width_; unsigned width_ : 24;
unsigned signed_ : 1; unsigned signed_ : 1;
union { union {
double real_value; double real_value;
char bit_[sizeof(char*)]; char bit_[sizeof(char*)];
char *bits_; const char* bits_;
} b; } b;
ivl_nexus_t pin_; ivl_nexus_t pin_;
ivl_expr_t delay[3]; 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. * there.
*/ */
struct ivl_scope_s { struct ivl_scope_s {
ivl_scope_t child_, sibling_, parent; ivl_scope_t parent;
std::map<hname_t,ivl_scope_t> children;
perm_string name_; perm_string name_;
perm_string tname_; perm_string tname_;