Optimization: use a shared reference counter instead of a per-object counter in Object::Ref/Unref
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-ref-count.h Fri Nov 06 17:47:44 2009 +0100
@@ -0,0 +1,121 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Mathieu Lacage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@gmail.com>
+ */
+#ifndef OBJECT_REF_COUNT_H
+#define OBJECT_REF_COUNT_H
+
+#include "empty.h"
+
+namespace ns3 {
+
+/**
+ * This templated class provides the refcounting implementation
+ * for the ns3::Object class.
+ *
+ * The tricky aspect of the implementation of this class is that
+ * instead of storing a count directly, it keeps track of a pointer
+ * to a count to allow multiple instances of the class to share the
+ * same pointer/count. This is mainly used by the aggregation support
+ * of the ns3::Object class
+ */
+template <typename T, typename PARENT = empty>
+class ObjectRefCount : public PARENT
+{
+public:
+ ObjectRefCount ()
+ : m_count (new int (1))
+ {}
+ ObjectRefCount (const ObjectRefCount &o)
+ : m_count (new int (1))
+ {}
+ ObjectRefCount & operator = (const ObjectRefCount &o)
+ {
+ *m_count = *o.m_count;
+ return *this;
+ }
+ ~ObjectRefCount ()
+ {
+ m_count = 0;
+ }
+
+ /**
+ * Get the reference count of the object. Normally not needed; for language bindings.
+ */
+ int GetReferenceCount (void) const {
+ return *m_count;
+ }
+ /**
+ * Increment the reference count. This method should not be called
+ * by user code. Object instances are expected to be used in conjunction
+ * of the Ptr template which would make calling Ref unecessary and
+ * dangerous.
+ */
+ inline void Ref (void) const
+ {
+ (*m_count)++;
+ }
+ /**
+ * Decrement the reference count. This method should not be called
+ * by user code. Object instances are expected to be used in conjunction
+ * of the Ptr template which would make calling Ref unecessary and
+ * dangerous.
+ */
+ inline void Unref (void) const
+ {
+ (*m_count)--;
+ if ((*m_count) == 0)
+ {
+ const_cast<ObjectRefCount<T,PARENT>*>(this)->DoDelete ();
+ }
+ }
+protected:
+ /**
+ * \param other another object
+ *
+ * This method makes this object and the input other object
+ * share the same reference count.
+ */
+ void ShareCount (ObjectRefCount *other)
+ {
+ (*m_count) += (*other->m_count);
+ delete other->m_count;
+ other->m_count = m_count;
+ }
+ /**
+ * Called just before deleting this object: when two
+ * objects share the same reference count, the user
+ * who is deleting them must be careful to delete the
+ * associated count only once and this is done by calling
+ * this method to get a reference to the count and, then,
+ * calling delete on the count.
+ *
+ * \sa ns3::Object::DoDelete
+ */
+ int *PeekCountPtr (void) const
+ {
+ return m_count;
+ }
+private:
+ virtual void DoDelete (void) = 0;
+ mutable int *m_count;
+};
+
+} // namespace ns3
+
+#endif /* OBJECT_REF_COUNT_H */
--- a/src/core/object.cc Fri Nov 06 11:27:17 2009 +0100
+++ b/src/core/object.cc Fri Nov 06 17:47:44 2009 +0100
@@ -79,8 +79,7 @@
Object::Object ()
- : m_count (1),
- m_tid (Object::GetTypeId ()),
+ : m_tid (Object::GetTypeId ()),
m_disposed (false),
m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
m_getObjectCount (0)
@@ -112,8 +111,7 @@
m_aggregates = 0;
}
Object::Object (const Object &o)
- : m_count (1),
- m_tid (o.m_tid),
+ : m_tid (o.m_tid),
m_disposed (false),
m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
m_getObjectCount (0)
@@ -121,11 +119,6 @@
m_aggregates->n = 1;
m_aggregates->buffer[0] = this;
}
-uint32_t
-Object::GetReferenceCount (void) const
-{
- return m_count;
-}
void
Object::Construct (const AttributeList &attributes)
{
@@ -231,6 +224,10 @@
Object *current = aggregates->buffer[i];
current->m_aggregates = aggregates;
}
+
+ // share the counts
+ ShareCount (other);
+
// Finally, call NotifyNewAggregate in the listed chain
for (uint32_t i = 0; i < n; i++)
{
@@ -271,7 +268,7 @@
bool
Object::Check (void) const
{
- return (m_count > 0);
+ return (GetReferenceCount () > 0);
}
/* In some cases, when an event is scheduled against a subclass of
@@ -289,13 +286,12 @@
for (uint32_t i = 0; i < n; i++)
{
Object *current = m_aggregates->buffer[i];
- refcount += current->m_count;
+ refcount += current->GetReferenceCount ();
}
return (refcount > 0);
}
-
void
-Object::MaybeDelete (void) const
+Object::DoDelete (void)
{
// First, check if any of the attached
// Object has a non-zero count.
@@ -303,7 +299,7 @@
for (uint32_t i = 0; i < n; i++)
{
Object *current = m_aggregates->buffer[i];
- if (current->m_count != 0)
+ if (current->GetReferenceCount () != 0)
{
return;
}
@@ -319,6 +315,8 @@
}
}
+ int *count = PeekCountPtr ();
+
// all attached objects have a zero count so,
// we can delete them all.
struct Aggregates *aggregates = m_aggregates;
@@ -331,6 +329,8 @@
Object *current = aggregates->buffer[0];
delete current;
}
+
+ delete count;
}
} // namespace ns3
--- a/src/core/object.h Fri Nov 06 11:27:17 2009 +0100
+++ b/src/core/object.h Fri Nov 06 17:47:44 2009 +0100
@@ -28,6 +28,7 @@
#include "attribute.h"
#include "object-base.h"
#include "attribute-list.h"
+#include "object-ref-count.h"
namespace ns3 {
@@ -55,7 +56,7 @@
* invoked from the Object::Unref method before destroying the object, even if the user
* did not call Object::Dispose directly.
*/
-class Object : public ObjectBase
+class Object : public ObjectRefCount<Object,ObjectBase>
{
public:
static TypeId GetTypeId (void);
@@ -99,26 +100,6 @@
virtual TypeId GetInstanceTypeId (void) const;
/**
- * Increment the reference count. This method should not be called
- * by user code. Object instances are expected to be used in conjunction
- * of the Ptr template which would make calling Ref unecessary and
- * dangerous.
- */
- inline void Ref (void) const;
- /**
- * Decrement the reference count. This method should not be called
- * by user code. Object instances are expected to be used in conjunction
- * of the Ptr template which would make calling Ref unecessary and
- * dangerous.
- */
- inline void Unref (void) const;
-
- /**
- * Get the reference count of the object. Normally not needed; for language bindings.
- */
- uint32_t GetReferenceCount (void) const;
-
- /**
* \returns a pointer to the requested interface or zero if it could not be found.
*/
template <typename T>
@@ -234,13 +215,6 @@
bool Check (void) const;
bool CheckLoose (void) const;
/**
- * Attempt to delete this object. This method iterates
- * over all aggregated objects to check if they all
- * have a zero refcount. If yes, the object and all
- * its aggregates are deleted. If not, nothing is done.
- */
- void MaybeDelete (void) const;
- /**
* \param tid an TypeId
*
* Invoked from ns3::CreateObject only.
@@ -259,16 +233,15 @@
void Construct (const AttributeList &attributes);
void UpdateSortedArray (struct Aggregates *aggregates, uint32_t i) const;
+ /**
+ * Attempt to delete this object. This method iterates
+ * over all aggregated objects to check if they all
+ * have a zero refcount. If yes, the object and all
+ * its aggregates are deleted. If not, nothing is done.
+ */
+ virtual void DoDelete (void);
/**
- * The reference count for this object. Each aggregate
- * has an individual reference count. When the global
- * reference count (the sum of all reference counts)
- * reaches zero, the object and all its aggregates is
- * deleted.
- */
- mutable uint32_t m_count;
- /**
* Identifies the type of this object instance.
*/
TypeId m_tid;
@@ -363,22 +336,6 @@
* The Object implementation which depends on templates
*************************************************************************/
-void
-Object::Ref (void) const
-{
- m_count++;
-}
-void
-Object::Unref (void) const
-{
- NS_ASSERT (Check ());
- m_count--;
- if (m_count == 0)
- {
- MaybeDelete ();
- }
-}
-
template <typename T>
Ptr<T>
Object::GetObject () const
--- a/src/core/wscript Fri Nov 06 11:27:17 2009 +0100
+++ b/src/core/wscript Fri Nov 06 17:47:44 2009 +0100
@@ -126,6 +126,7 @@
'abort.h',
'names.h',
'vector.h',
+ 'object-ref-count.h',
]
if sys.platform == 'win32':