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>