mirror of https://github.com/KLayout/klayout.git
WIP: fast replacement for rb_gc_register_address/rb_gc_unregister_address.
This commit is contained in:
parent
1bc0243c0a
commit
a5d9bbb3d1
|
|
@ -1356,6 +1356,9 @@ rba_init (RubyInterpreterPrivateData *d)
|
||||||
{
|
{
|
||||||
VALUE module = rb_define_module ("RBA");
|
VALUE module = rb_define_module ("RBA");
|
||||||
|
|
||||||
|
// initialize the locked object vault as a fast replacement for rb_gc_register_address/rb_gc_unregister_address.
|
||||||
|
rba::make_locked_object_vault (module);
|
||||||
|
|
||||||
// save all constants for later (we cannot declare them while we are still producing classes
|
// save all constants for later (we cannot declare them while we are still producing classes
|
||||||
// because of the enum representative classes and enum constants are important)
|
// because of the enum representative classes and enum constants are important)
|
||||||
std::vector <RubyConstDescriptor> constants;
|
std::vector <RubyConstDescriptor> constants;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,131 @@
|
||||||
namespace rba
|
namespace rba
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Implementation of the locked object vault
|
||||||
|
|
||||||
|
class LockedObjectVault
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void init (VALUE module, const char *name);
|
||||||
|
|
||||||
|
LockedObjectVault ();
|
||||||
|
~LockedObjectVault ();
|
||||||
|
|
||||||
|
static LockedObjectVault *instance ()
|
||||||
|
{
|
||||||
|
return mp_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add (VALUE object);
|
||||||
|
void remove (VALUE object);
|
||||||
|
void mark_this ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<VALUE> m_objects;
|
||||||
|
|
||||||
|
static VALUE m_klass;
|
||||||
|
static VALUE m_instance;
|
||||||
|
static LockedObjectVault *mp_instance;
|
||||||
|
|
||||||
|
static void free (void *p);
|
||||||
|
static void mark (void *p);
|
||||||
|
static VALUE alloc (VALUE klass);
|
||||||
|
};
|
||||||
|
|
||||||
|
VALUE LockedObjectVault::m_klass = Qnil;
|
||||||
|
VALUE LockedObjectVault::m_instance = Qnil;
|
||||||
|
LockedObjectVault *LockedObjectVault::mp_instance = 0;
|
||||||
|
|
||||||
|
LockedObjectVault::LockedObjectVault ()
|
||||||
|
{
|
||||||
|
mp_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedObjectVault::~LockedObjectVault ()
|
||||||
|
{
|
||||||
|
if (mp_instance == this) {
|
||||||
|
mp_instance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::add (VALUE object)
|
||||||
|
{
|
||||||
|
m_objects.insert (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::remove (VALUE object)
|
||||||
|
{
|
||||||
|
m_objects.erase (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::mark_this ()
|
||||||
|
{
|
||||||
|
for (std::set<VALUE>::iterator o = m_objects.begin (); o != m_objects.end (); ++o) {
|
||||||
|
rb_gc_mark (*o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::mark (void *p)
|
||||||
|
{
|
||||||
|
((LockedObjectVault *) p)->mark_this ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::free (void *p)
|
||||||
|
{
|
||||||
|
delete ((LockedObjectVault *) p);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
LockedObjectVault::alloc (VALUE klass)
|
||||||
|
{
|
||||||
|
tl_assert (TYPE (klass) == T_CLASS);
|
||||||
|
|
||||||
|
LockedObjectVault *vault = new LockedObjectVault ();
|
||||||
|
return Data_Wrap_Struct (klass, &LockedObjectVault::mark, &LockedObjectVault::free, vault);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LockedObjectVault::init (VALUE module, const char *name)
|
||||||
|
{
|
||||||
|
if (m_instance != Qnil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_klass = rb_define_class_under (module, name, rb_cObject);
|
||||||
|
rb_define_alloc_func (m_klass, LockedObjectVault::alloc);
|
||||||
|
|
||||||
|
m_instance = rba_class_new_instance_checked (0, 0, m_klass);
|
||||||
|
rb_gc_register_address (&m_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
make_locked_object_vault (VALUE module)
|
||||||
|
{
|
||||||
|
LockedObjectVault::init (module, "RBALockedObjectVault");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gc_lock_object (VALUE value)
|
||||||
|
{
|
||||||
|
if (LockedObjectVault::instance ()) {
|
||||||
|
LockedObjectVault::instance ()->add (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gc_unlock_object (VALUE value)
|
||||||
|
{
|
||||||
|
if (LockedObjectVault::instance ()) {
|
||||||
|
LockedObjectVault::instance ()->remove (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -260,7 +385,7 @@ Proxy::detach ()
|
||||||
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
|
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
|
||||||
}
|
}
|
||||||
if (!m_owned && m_self != Qnil) {
|
if (!m_owned && m_self != Qnil) {
|
||||||
rb_gc_unregister_address (&m_self);
|
gc_unlock_object (m_self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +567,7 @@ Proxy::release ()
|
||||||
|
|
||||||
if (!m_owned) {
|
if (!m_owned) {
|
||||||
if (cls->is_managed () && m_self != Qnil) {
|
if (cls->is_managed () && m_self != Qnil) {
|
||||||
rb_gc_unregister_address (&m_self);
|
gc_unlock_object (m_self);
|
||||||
}
|
}
|
||||||
m_owned = true;
|
m_owned = true;
|
||||||
}
|
}
|
||||||
|
|
@ -475,7 +600,7 @@ Proxy::keep_internal ()
|
||||||
m_owned = false;
|
m_owned = false;
|
||||||
tl_assert (m_self != Qnil);
|
tl_assert (m_self != Qnil);
|
||||||
if (m_cls_decl->is_managed ()) {
|
if (m_cls_decl->is_managed ()) {
|
||||||
rb_gc_register_address (&m_self);
|
gc_lock_object (m_self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -522,7 +647,7 @@ Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy, VALUE self)
|
||||||
gsi_object->status_changed_event ().add (this, &Proxy::object_status_changed);
|
gsi_object->status_changed_event ().add (this, &Proxy::object_status_changed);
|
||||||
|
|
||||||
if (! m_owned) {
|
if (! m_owned) {
|
||||||
rb_gc_register_address (&m_self);
|
gc_lock_object (m_self);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,31 @@ VALUE ruby_cls (const gsi::ClassBase *cls);
|
||||||
*/
|
*/
|
||||||
bool is_registered (const gsi::ClassBase *gsi_cls);
|
bool is_registered (const gsi::ClassBase *gsi_cls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the Ruby object against destruction by the GC
|
||||||
|
*
|
||||||
|
* After calling this function, the object given by value is no longer
|
||||||
|
* managed by the GC. This is equivalent to rb_gc_register_address, but
|
||||||
|
* faster.
|
||||||
|
*/
|
||||||
|
void gc_lock_object (VALUE value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the Ruby object against destruction by the GC
|
||||||
|
*
|
||||||
|
* After calling this function, the object given by value is no longer
|
||||||
|
* managed by the GC. This is equivalent to rb_gc_unregister_address, but
|
||||||
|
* faster.
|
||||||
|
*/
|
||||||
|
void gc_unlock_object (VALUE value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Makes the locked object vault required for gc_lock_object and gc_unlock_object
|
||||||
|
*
|
||||||
|
* This function needs to be called by the interpreter initially.
|
||||||
|
*/
|
||||||
|
void make_locked_object_vault (VALUE module);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,12 @@ public:
|
||||||
RubyBasedStringAdaptor (VALUE value)
|
RubyBasedStringAdaptor (VALUE value)
|
||||||
{
|
{
|
||||||
m_string = rba_safe_string_value (value);
|
m_string = rba_safe_string_value (value);
|
||||||
rb_gc_register_address (&m_string);
|
gc_lock_object (m_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RubyBasedStringAdaptor ()
|
~RubyBasedStringAdaptor ()
|
||||||
{
|
{
|
||||||
rb_gc_unregister_address (&m_string);
|
gc_unlock_object (m_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const char *c_str () const
|
virtual const char *c_str () const
|
||||||
|
|
@ -691,12 +691,12 @@ struct reader<gsi::VoidType>
|
||||||
RubyBasedVariantAdaptor::RubyBasedVariantAdaptor (VALUE var)
|
RubyBasedVariantAdaptor::RubyBasedVariantAdaptor (VALUE var)
|
||||||
: m_var (var)
|
: m_var (var)
|
||||||
{
|
{
|
||||||
rb_gc_register_address (&m_var);
|
gc_lock_object (m_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
RubyBasedVariantAdaptor::~RubyBasedVariantAdaptor ()
|
RubyBasedVariantAdaptor::~RubyBasedVariantAdaptor ()
|
||||||
{
|
{
|
||||||
rb_gc_unregister_address (&m_var);
|
gc_unlock_object (m_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
tl::Variant RubyBasedVariantAdaptor::var () const
|
tl::Variant RubyBasedVariantAdaptor::var () const
|
||||||
|
|
@ -739,12 +739,12 @@ void RubyBasedVectorAdaptorIterator::inc ()
|
||||||
RubyBasedVectorAdaptor::RubyBasedVectorAdaptor (VALUE array, const gsi::ArgType *ainner)
|
RubyBasedVectorAdaptor::RubyBasedVectorAdaptor (VALUE array, const gsi::ArgType *ainner)
|
||||||
: mp_ainner (ainner), m_array (array)
|
: mp_ainner (ainner), m_array (array)
|
||||||
{
|
{
|
||||||
rb_gc_register_address (&m_array);
|
gc_lock_object (m_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
RubyBasedVectorAdaptor::~RubyBasedVectorAdaptor ()
|
RubyBasedVectorAdaptor::~RubyBasedVectorAdaptor ()
|
||||||
{
|
{
|
||||||
rb_gc_unregister_address (&m_array);
|
gc_unlock_object (m_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
gsi::VectorAdaptorIterator *RubyBasedVectorAdaptor::create_iterator () const
|
gsi::VectorAdaptorIterator *RubyBasedVectorAdaptor::create_iterator () const
|
||||||
|
|
@ -815,12 +815,12 @@ void RubyBasedMapAdaptorIterator::inc ()
|
||||||
RubyBasedMapAdaptor::RubyBasedMapAdaptor (VALUE hash, const gsi::ArgType *ainner, const gsi::ArgType *ainner_k)
|
RubyBasedMapAdaptor::RubyBasedMapAdaptor (VALUE hash, const gsi::ArgType *ainner, const gsi::ArgType *ainner_k)
|
||||||
: mp_ainner (ainner), mp_ainner_k (ainner_k), m_hash (hash)
|
: mp_ainner (ainner), mp_ainner_k (ainner_k), m_hash (hash)
|
||||||
{
|
{
|
||||||
rb_gc_register_address (&m_hash);
|
gc_lock_object (m_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
RubyBasedMapAdaptor::~RubyBasedMapAdaptor()
|
RubyBasedMapAdaptor::~RubyBasedMapAdaptor()
|
||||||
{
|
{
|
||||||
rb_gc_unregister_address (&m_hash);
|
gc_unlock_object (m_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
gsi::MapAdaptorIterator *RubyBasedMapAdaptor::create_iterator () const
|
gsi::MapAdaptorIterator *RubyBasedMapAdaptor::create_iterator () const
|
||||||
|
|
|
||||||
|
|
@ -1075,6 +1075,33 @@ class DBLayout_TestClass < TestBase
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Slow cleanup test
|
||||||
|
def test_13
|
||||||
|
|
||||||
|
n = 1000
|
||||||
|
w = 10000
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
l1 = ly.layer(1, 0)
|
||||||
|
top = ly.create_cell("TOP")
|
||||||
|
|
||||||
|
n.times do |ix|
|
||||||
|
$stdout.puts("#{ix}/#{n}")
|
||||||
|
$stdout.flush
|
||||||
|
n.times do |iy|
|
||||||
|
x = ix * w
|
||||||
|
y = iy * w
|
||||||
|
cell = ly.create_cell("X#{ix}Y#{iy}")
|
||||||
|
cell.shapes(l1).insert(RBA::Box::new(0, 0, w, w))
|
||||||
|
top.insert(RBA::CellInstArray::new(cell.cell_index, RBA::Trans::new(RBA::Point::new(ix * w, iy * w))))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# took forever:
|
||||||
|
ly._destroy
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue