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");
|
||||
|
||||
// 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
|
||||
// because of the enum representative classes and enum constants are important)
|
||||
std::vector <RubyConstDescriptor> constants;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,131 @@
|
|||
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);
|
||||
}
|
||||
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 (cls->is_managed () && m_self != Qnil) {
|
||||
rb_gc_unregister_address (&m_self);
|
||||
gc_unlock_object (m_self);
|
||||
}
|
||||
m_owned = true;
|
||||
}
|
||||
|
|
@ -475,7 +600,7 @@ Proxy::keep_internal ()
|
|||
m_owned = false;
|
||||
tl_assert (m_self != Qnil);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ public:
|
|||
RubyBasedStringAdaptor (VALUE value)
|
||||
{
|
||||
m_string = rba_safe_string_value (value);
|
||||
rb_gc_register_address (&m_string);
|
||||
gc_lock_object (m_string);
|
||||
}
|
||||
|
||||
~RubyBasedStringAdaptor ()
|
||||
{
|
||||
rb_gc_unregister_address (&m_string);
|
||||
gc_unlock_object (m_string);
|
||||
}
|
||||
|
||||
virtual const char *c_str () const
|
||||
|
|
@ -691,12 +691,12 @@ struct reader<gsi::VoidType>
|
|||
RubyBasedVariantAdaptor::RubyBasedVariantAdaptor (VALUE var)
|
||||
: m_var (var)
|
||||
{
|
||||
rb_gc_register_address (&m_var);
|
||||
gc_lock_object (m_var);
|
||||
}
|
||||
|
||||
RubyBasedVariantAdaptor::~RubyBasedVariantAdaptor ()
|
||||
{
|
||||
rb_gc_unregister_address (&m_var);
|
||||
gc_unlock_object (m_var);
|
||||
}
|
||||
|
||||
tl::Variant RubyBasedVariantAdaptor::var () const
|
||||
|
|
@ -739,12 +739,12 @@ void RubyBasedVectorAdaptorIterator::inc ()
|
|||
RubyBasedVectorAdaptor::RubyBasedVectorAdaptor (VALUE array, const gsi::ArgType *ainner)
|
||||
: mp_ainner (ainner), m_array (array)
|
||||
{
|
||||
rb_gc_register_address (&m_array);
|
||||
gc_lock_object (m_array);
|
||||
}
|
||||
|
||||
RubyBasedVectorAdaptor::~RubyBasedVectorAdaptor ()
|
||||
{
|
||||
rb_gc_unregister_address (&m_array);
|
||||
gc_unlock_object (m_array);
|
||||
}
|
||||
|
||||
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)
|
||||
: mp_ainner (ainner), mp_ainner_k (ainner_k), m_hash (hash)
|
||||
{
|
||||
rb_gc_register_address (&m_hash);
|
||||
gc_lock_object (m_hash);
|
||||
}
|
||||
|
||||
RubyBasedMapAdaptor::~RubyBasedMapAdaptor()
|
||||
{
|
||||
rb_gc_unregister_address (&m_hash);
|
||||
gc_unlock_object (m_hash);
|
||||
}
|
||||
|
||||
gsi::MapAdaptorIterator *RubyBasedMapAdaptor::create_iterator () const
|
||||
|
|
|
|||
|
|
@ -1075,6 +1075,33 @@ class DBLayout_TestClass < TestBase
|
|||
|
||||
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
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue