Optimization: use a shared reference counter instead of a per-object counter in Object::Ref/Unref
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri Nov 06 17:47:44 2009 +0100 (3 months ago)
changeset 55369bf34ba759a3
parent 5535 1739c7bafd29
child 5537 9485bee6b7eb
Optimization: use a shared reference counter instead of a per-object counter in Object::Ref/Unref
src/core/object-ref-count.h
src/core/object.cc
src/core/object.h
src/core/wscript
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/core/object-ref-count.h	Fri Nov 06 17:47:44 2009 +0100
     1.3 @@ -0,0 +1,121 @@
     1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     1.5 +/*
     1.6 + * Copyright (c) 2009 Mathieu Lacage
     1.7 + *
     1.8 + * This program is free software; you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License version 2 as
    1.10 + * published by the Free Software Foundation;
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program; if not, write to the Free Software
    1.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.20 + *
    1.21 + * Author: Mathieu Lacage <mathieu.lacage@gmail.com>
    1.22 + */
    1.23 +#ifndef OBJECT_REF_COUNT_H
    1.24 +#define OBJECT_REF_COUNT_H
    1.25 +
    1.26 +#include "empty.h"
    1.27 +
    1.28 +namespace ns3 {
    1.29 +
    1.30 +/**
    1.31 + * This templated class provides the refcounting implementation
    1.32 + * for the ns3::Object class.
    1.33 + *
    1.34 + * The tricky aspect of the implementation of this class is that
    1.35 + * instead of storing a count directly, it keeps track of a pointer
    1.36 + * to a count to allow multiple instances of the class to share the
    1.37 + * same pointer/count. This is mainly used by the aggregation support
    1.38 + * of the ns3::Object class
    1.39 + */
    1.40 +template <typename T, typename PARENT = empty>
    1.41 +class ObjectRefCount : public PARENT
    1.42 +{
    1.43 +public:
    1.44 +  ObjectRefCount ()
    1.45 +    : m_count (new int (1))
    1.46 +  {}
    1.47 +  ObjectRefCount (const ObjectRefCount &o)
    1.48 +    : m_count (new int (1))
    1.49 +  {}
    1.50 +  ObjectRefCount & operator = (const ObjectRefCount &o)
    1.51 +  {
    1.52 +    *m_count = *o.m_count;
    1.53 +    return *this;
    1.54 +  }
    1.55 +  ~ObjectRefCount () 
    1.56 +  {
    1.57 +    m_count = 0;
    1.58 +  }
    1.59 +
    1.60 +  /**
    1.61 +   * Get the reference count of the object.  Normally not needed; for language bindings.
    1.62 +   */
    1.63 +  int GetReferenceCount (void) const {
    1.64 +    return *m_count;
    1.65 +  }
    1.66 +  /**
    1.67 +   * Increment the reference count. This method should not be called
    1.68 +   * by user code. Object instances are expected to be used in conjunction
    1.69 +   * of the Ptr template which would make calling Ref unecessary and 
    1.70 +   * dangerous.
    1.71 +   */
    1.72 +  inline void Ref (void) const
    1.73 +    {
    1.74 +      (*m_count)++;
    1.75 +    }
    1.76 +  /**
    1.77 +   * Decrement the reference count. This method should not be called
    1.78 +   * by user code. Object instances are expected to be used in conjunction
    1.79 +   * of the Ptr template which would make calling Ref unecessary and 
    1.80 +   * dangerous.
    1.81 +   */
    1.82 +  inline void Unref (void) const
    1.83 +    {
    1.84 +      (*m_count)--;
    1.85 +      if ((*m_count) == 0)
    1.86 +        {
    1.87 +	  const_cast<ObjectRefCount<T,PARENT>*>(this)->DoDelete ();
    1.88 +        }
    1.89 +    }
    1.90 +protected:
    1.91 +  /**
    1.92 +   * \param other another object
    1.93 +   *
    1.94 +   * This method makes this object and the input other object
    1.95 +   * share the same reference count.
    1.96 +   */
    1.97 +  void ShareCount (ObjectRefCount *other)
    1.98 +    {
    1.99 +      (*m_count) += (*other->m_count);
   1.100 +      delete other->m_count;
   1.101 +      other->m_count = m_count;
   1.102 +    }
   1.103 +  /**
   1.104 +   * Called just before deleting this object: when two
   1.105 +   * objects share the same reference count, the user
   1.106 +   * who is deleting them must be careful to delete the
   1.107 +   * associated count only once and this is done by calling 
   1.108 +   * this method to get a reference to the count and, then,
   1.109 +   * calling delete on the count.
   1.110 +   *
   1.111 +   * \sa ns3::Object::DoDelete
   1.112 +   */
   1.113 +  int *PeekCountPtr (void) const
   1.114 +    {
   1.115 +      return m_count;
   1.116 +    }
   1.117 +private:
   1.118 +  virtual void DoDelete (void) = 0;
   1.119 +  mutable int *m_count;
   1.120 +};
   1.121 +
   1.122 +} // namespace ns3
   1.123 +
   1.124 +#endif /* OBJECT_REF_COUNT_H */
     2.1 --- a/src/core/object.cc	Fri Nov 06 11:27:17 2009 +0100
     2.2 +++ b/src/core/object.cc	Fri Nov 06 17:47:44 2009 +0100
     2.3 @@ -79,8 +79,7 @@
     2.4  
     2.5  
     2.6  Object::Object ()
     2.7 -  : m_count (1),
     2.8 -    m_tid (Object::GetTypeId ()),
     2.9 +  : m_tid (Object::GetTypeId ()),
    2.10      m_disposed (false),
    2.11      m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
    2.12      m_getObjectCount (0)
    2.13 @@ -112,8 +111,7 @@
    2.14    m_aggregates = 0;
    2.15  }
    2.16  Object::Object (const Object &o)
    2.17 -  : m_count (1),
    2.18 -    m_tid (o.m_tid),
    2.19 +  : m_tid (o.m_tid),
    2.20      m_disposed (false),
    2.21      m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
    2.22      m_getObjectCount (0)
    2.23 @@ -121,11 +119,6 @@
    2.24    m_aggregates->n = 1;
    2.25    m_aggregates->buffer[0] = this;
    2.26  }
    2.27 -uint32_t
    2.28 -Object::GetReferenceCount (void) const
    2.29 -{
    2.30 -  return m_count;
    2.31 -}
    2.32  void
    2.33  Object::Construct (const AttributeList &attributes)
    2.34  {
    2.35 @@ -231,6 +224,10 @@
    2.36        Object *current = aggregates->buffer[i];
    2.37        current->m_aggregates = aggregates;
    2.38      }
    2.39 +
    2.40 +  // share the counts
    2.41 +  ShareCount (other);
    2.42 +
    2.43    // Finally, call NotifyNewAggregate in the listed chain
    2.44    for (uint32_t i = 0; i < n; i++)
    2.45      {
    2.46 @@ -271,7 +268,7 @@
    2.47  bool 
    2.48  Object::Check (void) const
    2.49  {
    2.50 -  return (m_count > 0);
    2.51 +  return (GetReferenceCount () > 0);
    2.52  }
    2.53  
    2.54  /* In some cases, when an event is scheduled against a subclass of
    2.55 @@ -289,13 +286,12 @@
    2.56    for (uint32_t i = 0; i < n; i++)
    2.57      {
    2.58        Object *current = m_aggregates->buffer[i];
    2.59 -      refcount += current->m_count;
    2.60 +      refcount += current->GetReferenceCount ();
    2.61      }
    2.62    return (refcount > 0);
    2.63  }
    2.64 -
    2.65  void
    2.66 -Object::MaybeDelete (void) const
    2.67 +Object::DoDelete (void)
    2.68  {
    2.69    // First, check if any of the attached
    2.70    // Object has a non-zero count.
    2.71 @@ -303,7 +299,7 @@
    2.72    for (uint32_t i = 0; i < n; i++)
    2.73      {
    2.74        Object *current = m_aggregates->buffer[i];
    2.75 -      if (current->m_count != 0)
    2.76 +      if (current->GetReferenceCount () != 0)
    2.77          {
    2.78            return;
    2.79          }
    2.80 @@ -319,6 +315,8 @@
    2.81          }
    2.82      }
    2.83  
    2.84 +  int *count = PeekCountPtr ();
    2.85 +
    2.86    // all attached objects have a zero count so, 
    2.87    // we can delete them all.
    2.88    struct Aggregates *aggregates = m_aggregates;
    2.89 @@ -331,6 +329,8 @@
    2.90        Object *current = aggregates->buffer[0];
    2.91        delete current;
    2.92      }
    2.93 +
    2.94 +  delete count;
    2.95  }
    2.96  } // namespace ns3
    2.97  
     3.1 --- a/src/core/object.h	Fri Nov 06 11:27:17 2009 +0100
     3.2 +++ b/src/core/object.h	Fri Nov 06 17:47:44 2009 +0100
     3.3 @@ -28,6 +28,7 @@
     3.4  #include "attribute.h"
     3.5  #include "object-base.h"
     3.6  #include "attribute-list.h"
     3.7 +#include "object-ref-count.h"
     3.8  
     3.9  
    3.10  namespace ns3 {
    3.11 @@ -55,7 +56,7 @@
    3.12   * invoked from the Object::Unref method before destroying the object, even if the user 
    3.13   * did not call Object::Dispose directly.
    3.14   */
    3.15 -class Object : public ObjectBase
    3.16 +class Object : public ObjectRefCount<Object,ObjectBase>
    3.17  {
    3.18  public:
    3.19    static TypeId GetTypeId (void);
    3.20 @@ -99,26 +100,6 @@
    3.21    virtual TypeId GetInstanceTypeId (void) const;
    3.22  
    3.23    /**
    3.24 -   * Increment the reference count. This method should not be called
    3.25 -   * by user code. Object instances are expected to be used in conjunction
    3.26 -   * of the Ptr template which would make calling Ref unecessary and 
    3.27 -   * dangerous.
    3.28 -   */
    3.29 -  inline void Ref (void) const;
    3.30 -  /**
    3.31 -   * Decrement the reference count. This method should not be called
    3.32 -   * by user code. Object instances are expected to be used in conjunction
    3.33 -   * of the Ptr template which would make calling Ref unecessary and 
    3.34 -   * dangerous.
    3.35 -   */
    3.36 -  inline void Unref (void) const;
    3.37 -
    3.38 -  /**
    3.39 -   * Get the reference count of the object.  Normally not needed; for language bindings.
    3.40 -   */
    3.41 -  uint32_t GetReferenceCount (void) const;
    3.42 -
    3.43 -  /**
    3.44     * \returns a pointer to the requested interface or zero if it could not be found.
    3.45     */
    3.46    template <typename T>
    3.47 @@ -234,13 +215,6 @@
    3.48    bool Check (void) const;
    3.49    bool CheckLoose (void) const;
    3.50    /**
    3.51 -   * Attempt to delete this object. This method iterates
    3.52 -   * over all aggregated objects to check if they all 
    3.53 -   * have a zero refcount. If yes, the object and all
    3.54 -   * its aggregates are deleted. If not, nothing is done.
    3.55 -   */
    3.56 -  void MaybeDelete (void) const;
    3.57 -  /**
    3.58     * \param tid an TypeId
    3.59     *
    3.60     * Invoked from ns3::CreateObject only.
    3.61 @@ -259,16 +233,15 @@
    3.62    void Construct (const AttributeList &attributes);
    3.63  
    3.64    void UpdateSortedArray (struct Aggregates *aggregates, uint32_t i) const;
    3.65 +  /**
    3.66 +   * Attempt to delete this object. This method iterates
    3.67 +   * over all aggregated objects to check if they all 
    3.68 +   * have a zero refcount. If yes, the object and all
    3.69 +   * its aggregates are deleted. If not, nothing is done.
    3.70 +   */
    3.71 +  virtual void DoDelete (void);
    3.72  
    3.73    /**
    3.74 -   * The reference count for this object. Each aggregate
    3.75 -   * has an individual reference count. When the global
    3.76 -   * reference count (the sum of all reference counts) 
    3.77 -   * reaches zero, the object and all its aggregates is 
    3.78 -   * deleted.
    3.79 -   */
    3.80 -  mutable uint32_t m_count;
    3.81 -  /**
    3.82     * Identifies the type of this object instance.
    3.83     */
    3.84    TypeId m_tid;
    3.85 @@ -363,22 +336,6 @@
    3.86   *   The Object implementation which depends on templates
    3.87   *************************************************************************/
    3.88  
    3.89 -void
    3.90 -Object::Ref (void) const
    3.91 -{
    3.92 -  m_count++;
    3.93 -}
    3.94 -void
    3.95 -Object::Unref (void) const
    3.96 -{
    3.97 -  NS_ASSERT (Check ());
    3.98 -  m_count--;
    3.99 -  if (m_count == 0)
   3.100 -    {
   3.101 -      MaybeDelete ();
   3.102 -    }
   3.103 -}
   3.104 -
   3.105  template <typename T>
   3.106  Ptr<T> 
   3.107  Object::GetObject () const
     4.1 --- a/src/core/wscript	Fri Nov 06 11:27:17 2009 +0100
     4.2 +++ b/src/core/wscript	Fri Nov 06 17:47:44 2009 +0100
     4.3 @@ -126,6 +126,7 @@
     4.4          'abort.h',
     4.5          'names.h',
     4.6          'vector.h',
     4.7 +        'object-ref-count.h',
     4.8          ]
     4.9  
    4.10      if sys.platform == 'win32':