You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2002/03/04 04:52:16 UTC

cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler ProfilePointListener.java AbstractProfileSample.java CounterProfilePointListener.java ProfilePointProxy.java ValueProfilePointListener.java

leif        02/03/03 19:52:16

  Modified:    src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler
                        AbstractProfileSample.java
                        CounterProfilePointListener.java
                        ProfilePointProxy.java
                        ValueProfilePointListener.java
  Added:       src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler
                        ProfilePointListener.java
  Log:
  Optimized the way that listeners are managed and fired so that synchronization
  can be completely avoiding when they are fired.
  
  Revision  Changes    Path
  1.2       +84 -24    jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/AbstractProfileSample.java
  
  Index: AbstractProfileSample.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/AbstractProfileSample.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractProfileSample.java	3 Mar 2002 15:59:43 -0000	1.1
  +++ AbstractProfileSample.java	4 Mar 2002 03:52:16 -0000	1.2
  @@ -17,7 +17,7 @@
    *  ProfileSamples.
    *
    * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/03/03 15:59:43 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/03/04 03:52:16 $
    * @since 4.1
    */
   abstract class AbstractProfileSample
  @@ -57,8 +57,8 @@
       /** The New half of the history array. */
       private int[] m_historyNew;
       
  -    /** List of registered ProfileSampleListeners. */
  -    private ArrayList m_listeners;
  +    /** Array of registered ProfileSampleListeners. */
  +    private ProfileSampleListener[] m_listeners;
       
       /*---------------------------------------------------------------
        * Constructors
  @@ -240,11 +240,25 @@
           
           synchronized(this)
           {
  -            if ( m_listeners == null )
  +            // Store the listeners in an array.  This makes it possible to
  +            //  avoid synchronization while propagating events.  Never change
  +            //  the contents of the listener array once it has been set to the
  +            //  m_listeners field.
  +            ProfileSampleListener[] oldListeners = m_listeners;
  +            ProfileSampleListener[] newListeners;
  +            if ( oldListeners == null )
               {
  -                m_listeners = new ArrayList();
  +                newListeners = new ProfileSampleListener[] { listener };
               }
  -            m_listeners.add( listener );
  +            else
  +            {
  +                newListeners = new ProfileSampleListener[ oldListeners.length + 1 ];
  +                System.arraycopy( oldListeners, 0, newListeners, 0, oldListeners.length );
  +                newListeners[ oldListeners.length ] = listener;
  +            }
  +            
  +            // Update the m_listeners field.
  +            m_listeners = newListeners;
           }
       }
       
  @@ -264,11 +278,67 @@
           
           synchronized(this)
           {
  -            m_listeners.remove( listener );
  -            if ( m_listeners.size() == 0 )
  +            // Store the listeners in an array.  This makes it possible to
  +            //  avoid synchronization while propagating events.  Never change
  +            //  the contents of the listener array once it has been set to the
  +            //  m_listeners field.
  +            ProfileSampleListener[] oldListeners = m_listeners;
  +            ProfileSampleListener[] newListeners;
  +            if ( oldListeners == null )
  +            {
  +                // Means that this method should not have been called, but
  +                //  don't throw an error.
  +                newListeners = null;
  +            }
  +            else if ( oldListeners.length == 1 )
  +            {
  +                if ( oldListeners[0] == listener )
  +                {
  +                    newListeners = null;
  +                }
  +                else
  +                {
  +                    // The listener was not in the list.
  +                    newListeners = oldListeners;
  +                }
  +            }
  +            else
               {
  -                m_listeners = null;
  +                // Look for the listener in the array.
  +                int pos = -1;
  +                for ( int i = 0; i < oldListeners.length; i++ )
  +                {
  +                    if ( oldListeners[i] == listener )
  +                    {
  +                        pos = i;
  +                        break;
  +                    }
  +                }
  +                
  +                if ( pos < 0 )
  +                {
  +                    // The listener was not in the list.
  +                    newListeners = oldListeners;
  +                }
  +                else
  +                {
  +                    newListeners = new ProfileSampleListener[ oldListeners.length - 1 ];
  +                    if ( pos > 0 )
  +                    {
  +                        // Copy the head of the array
  +                        System.arraycopy( oldListeners, 0, newListeners, 0, pos );
  +                    }
  +                    if ( pos < oldListeners.length - 1 )
  +                    {
  +                        // Copy the tail of the array
  +                        System.arraycopy( oldListeners, pos + 1, 
  +                            newListeners, pos, oldListeners.length - 1 - pos );
  +                    }
  +                }
               }
  +            
  +            // Update the m_listeners field.
  +            m_listeners = newListeners;
           }
       }
       
  @@ -282,24 +352,14 @@
        */
       protected void updateListeners( int value, long time )
       {
  -        //System.out.println("updateListeners(" + value + ", " + time + ")");
  -        ProfileSampleListener[] listeners;
  -        synchronized(this)
  +        // Get a local reference to the listeners, so that synchronization can be avoided.
  +        ProfileSampleListener[] listeners = m_listeners;
  +        if ( listeners != null )
           {
  -            if ( m_listeners == null )
  +            for ( int i = 0; i < listeners.length; i++ )
               {
  -                // Nobody is listening
  -                return;
  +                listeners[i].setValue( getName(), value, time );
               }
  -            
  -            listeners = new ProfileSampleListener[ m_listeners.size() ];
  -            m_listeners.toArray( listeners );
  -        }
  -    
  -        // Call them outside of the synchronized block.
  -        for ( int i = 0; i < listeners.length; i++ )
  -        {
  -            listeners[i].setValue( getName(), value, time );
           }
       }
       
  
  
  
  1.2       +2 -1      jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/CounterProfilePointListener.java
  
  Index: CounterProfilePointListener.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/CounterProfilePointListener.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CounterProfilePointListener.java	3 Mar 2002 15:59:43 -0000	1.1
  +++ CounterProfilePointListener.java	4 Mar 2002 03:52:16 -0000	1.2
  @@ -13,10 +13,11 @@
    *  it is incremented.
    *
    * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/03/03 15:59:43 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/03/04 03:52:16 $
    * @since 4.1
    */
   public interface CounterProfilePointListener
  +    extends ProfilePointListener
   {
       /**
        * Called by a CounterProfilePoint whenever its value is incremented.
  
  
  
  1.2       +131 -65   jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/ProfilePointProxy.java
  
  Index: ProfilePointProxy.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/ProfilePointProxy.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ProfilePointProxy.java	3 Mar 2002 15:59:43 -0000	1.1
  +++ ProfilePointProxy.java	4 Mar 2002 03:52:16 -0000	1.2
  @@ -28,7 +28,7 @@
    *  It is resolved when the Profilable actually registers the ProfilePoint.
    *
    * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/03/03 15:59:43 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/03/04 03:52:16 $
    * @since 4.1
    */
   public class ProfilePointProxy
  @@ -50,8 +50,8 @@
       /** Type of the ProfilePoint */
       private int m_type;
       
  -    /** List of registered Counter/ValueProfilePointListeners. */
  -    private ArrayList m_listeners;
  +    /** Array of registered Counter/ValueProfilePointListeners. */
  +    private ProfilePointListener[] m_listeners;
       
       /** Map of the maintained ProfileSamples. */
       private HashMap m_samples = new HashMap();
  @@ -291,14 +291,7 @@
                   " : " + listener.getClass().getName() );
           }
           
  -        synchronized(this)
  -        {
  -            if ( m_listeners == null )
  -            {
  -                m_listeners = new ArrayList();
  -            }
  -            m_listeners.add( listener );
  -        }
  +        addProfilePointListener( listener );
       }
       
       /**
  @@ -326,14 +319,7 @@
                   m_name + " : " + listener.getClass().getName() );
           }
           
  -        synchronized(this)
  -        {
  -            m_listeners.remove( listener );
  -            if ( m_listeners.size() == 0 )
  -            {
  -                m_listeners = null;
  -            }
  -        }
  +        removeProfilePointListener( listener );
       }
       
       /*
  @@ -349,28 +335,21 @@
                   "The proxy is not configured to handle CounterProfilePoints." );
           }
           
  -        // Check to see if there are any listeners outside of a synchronization
  -        //  block to see if there is any reason to continue.
  -        if ( m_listeners != null )
  +        // Get a local reference to the listeners, so that synchronization can be avoided.
  +        ProfilePointListener[] listeners = m_listeners;
  +        if ( listeners != null )
           {
               if ( m_valueLogger.isDebugEnabled() )
               {
                   m_valueLogger.debug( "increment() called for ProfilePoint, " + m_name );
               }
               
  -            synchronized(this)
  +            long time = System.currentTimeMillis();
  +            for ( int i = 0; i < listeners.length; i++ )
               {
  -                // Check m_listeners again because it could have been set to null.
  -                if ( m_listeners != null )
  -                {
  -                    long time = System.currentTimeMillis();
  -                    for ( Iterator iter = m_listeners.iterator(); iter.hasNext(); )
  -                    {
  -                        CounterProfilePointListener listener =
  -                            (CounterProfilePointListener)iter.next();
  -                        listener.increment( getName(), time );
  -                    }
  -                }
  +                CounterProfilePointListener listener =
  +                    (CounterProfilePointListener)listeners[i];
  +                listener.increment( getName(), time );
               }
           }
       }
  @@ -400,14 +379,7 @@
                   " : " + listener.getClass().getName() );
           }
           
  -        synchronized(this)
  -        {
  -            if ( m_listeners == null )
  -            {
  -                m_listeners = new ArrayList();
  -            }
  -            m_listeners.add( listener );
  -        }
  +        addProfilePointListener( listener );
       }
       
       /**
  @@ -435,14 +407,7 @@
                   " : " + listener.getClass().getName() );
           }
           
  -        synchronized(this)
  -        {
  -            m_listeners.remove( listener );
  -            if ( m_listeners.size() == 0 )
  -            {
  -                m_listeners = null;
  -            }
  -        }
  +        removeProfilePointListener( listener );
       }
       
       /**
  @@ -461,28 +426,21 @@
                   "The proxy is not configured to handle ValueProfilePoints." );
           }
           
  -        // Check to see if there are any listeners outside of a synchronization
  -        //  block to see if there is any reason to continue.
  -        if ( m_listeners != null )
  +        // Get a local reference to the listeners, so that synchronization can be avoided.
  +        ProfilePointListener[] listeners = m_listeners;
  +        if ( listeners != null )
           {
               if ( m_valueLogger.isDebugEnabled() )
               {
                   m_valueLogger.debug( "setValue( " + value + " ) called for ProfilePoint, " + m_name );
               }
               
  -            synchronized(this)
  +            long time = System.currentTimeMillis();
  +            for ( int i = 0; i < listeners.length; i++ )
               {
  -                // Check m_listeners again because it could have been set to null.
  -                if ( m_listeners != null )
  -                {
  -                    long time = System.currentTimeMillis();
  -                    for ( Iterator iter = m_listeners.iterator(); iter.hasNext(); )
  -                    {
  -                        ValueProfilePointListener listener =
  -                            (ValueProfilePointListener)iter.next();
  -                        listener.setValue( getName(), value, time );
  -                    }
  -                }
  +                ValueProfilePointListener listener =
  +                    (ValueProfilePointListener)listeners[i];
  +                listener.setValue( getName(), value, time );
               }
           }
       }
  @@ -593,6 +551,114 @@
               descriptors = updateProfileSampleDescriptorArray();
           }
           return descriptors;
  +    }
  +    
  +    /**
  +     * Common code to add a listener to the list of listeners which will
  +     *  receive updates of the value of the ProfilePoint.
  +     *
  +     * @param listener ProfilePointListener which will start receiving
  +     *                 profile updates.
  +     */
  +    private void addProfilePointListener( ProfilePointListener listener )
  +    {
  +        synchronized(this)
  +        {
  +            // Store the listeners in an array.  This makes it possible to
  +            //  avoid synchronization while propagating events.  Never change
  +            //  the contents of the listener array once it has been set to the
  +            //  m_listeners field.
  +            ProfilePointListener[] oldListeners = m_listeners;
  +            ProfilePointListener[] newListeners;
  +            if ( oldListeners == null )
  +            {
  +                newListeners = new ProfilePointListener[] { listener };
  +            }
  +            else
  +            {
  +                newListeners = new ProfilePointListener[ oldListeners.length + 1 ];
  +                System.arraycopy( oldListeners, 0, newListeners, 0, oldListeners.length );
  +                newListeners[ oldListeners.length ] = listener;
  +            }
  +            
  +            // Update the m_listeners field.
  +            m_listeners = newListeners;
  +        }
  +    }
  +    
  +    /**
  +     * Common code to remove a listener from the list of listeners which will
  +     *  receive updates of the value of the ProfilePoint.
  +     *
  +     * @param listener ProfilePointListener which will stop receiving
  +     *                 profile updates.
  +     */
  +    private void removeProfilePointListener( ProfilePointListener listener )
  +    {
  +        synchronized(this)
  +        {
  +            // Store the listeners in an array.  This makes it possible to
  +            //  avoid synchronization while propagating events.  Never change
  +            //  the contents of the listener array once it has been set to the
  +            //  m_listeners field.
  +            ProfilePointListener[] oldListeners = m_listeners;
  +            ProfilePointListener[] newListeners;
  +            if ( oldListeners == null )
  +            {
  +                // Means that this method should not have been called, but
  +                //  don't throw an error.
  +                newListeners = null;
  +            }
  +            else if ( oldListeners.length == 1 )
  +            {
  +                if ( oldListeners[0] == listener )
  +                {
  +                    newListeners = null;
  +                }
  +                else
  +                {
  +                    // The listener was not in the list.
  +                    newListeners = oldListeners;
  +                }
  +            }
  +            else
  +            {
  +                // Look for the listener in the array.
  +                int pos = -1;
  +                for ( int i = 0; i < oldListeners.length; i++ )
  +                {
  +                    if ( oldListeners[i] == listener )
  +                    {
  +                        pos = i;
  +                        break;
  +                    }
  +                }
  +                
  +                if ( pos < 0 )
  +                {
  +                    // The listener was not in the list.
  +                    newListeners = oldListeners;
  +                }
  +                else
  +                {
  +                    newListeners = new ProfilePointListener[ oldListeners.length - 1 ];
  +                    if ( pos > 0 )
  +                    {
  +                        // Copy the head of the array
  +                        System.arraycopy( oldListeners, 0, newListeners, 0, pos );
  +                    }
  +                    if ( pos < oldListeners.length - 1 )
  +                    {
  +                        // Copy the tail of the array
  +                        System.arraycopy( oldListeners, pos + 1, 
  +                            newListeners, pos, oldListeners.length - 1 - pos );
  +                    }
  +                }
  +            }
  +            
  +            // Update the m_listeners field.
  +            m_listeners = newListeners;
  +        }
       }
       
       /**
  
  
  
  1.2       +2 -1      jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/ValueProfilePointListener.java
  
  Index: ValueProfilePointListener.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/ValueProfilePointListener.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValueProfilePointListener.java	3 Mar 2002 15:59:43 -0000	1.1
  +++ ValueProfilePointListener.java	4 Mar 2002 03:52:16 -0000	1.2
  @@ -13,10 +13,11 @@
    *  Profile Point's value.
    *
    * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/03/03 15:59:43 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/03/04 03:52:16 $
    * @since 4.1
    */
   public interface ValueProfilePointListener
  +    extends ProfilePointListener
   {
       /**
        * Called by a ValueProfilePoint whenever its value is set.
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/ProfilePointListener.java
  
  Index: ProfilePointListener.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.avalon.excalibur.altprofile.profiler;
  
  /**
   * Root interface for ProfilePointListeners.  This interface should not be
   *  be implemented directly.
   *
   * @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/03/04 03:52:16 $
   * @since 4.1
   */
  interface ProfilePointListener
  {
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>