On 23/09/2012 20:03, Konstantin Kolinko wrote:
> 2012/9/23  <ma...@apache.org>:
>> Author: markt
>> Date: Sun Sep 23 15:20:38 2012
>> New Revision: 1389076
>>
>> URL: http://svn.apache.org/viewvc?rev=1389076&view=rev
>> Log:
>> ConcurrentLinkedQueue is currently the biggest contributor to garbage in the 
>> load test so this is intended as a replacement.
>>
>> Added:
>>     
>> tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java   
>> (with props)
>>     tomcat/trunk/test/org/apache/tomcat/util/collections/
>>     
>> tomcat/trunk/test/org/apache/tomcat/util/collections/TestConcurrentStack.java
>>    (with props)
>>     
>> tomcat/trunk/test/org/apache/tomcat/util/collections/TesterPerformanceConcurrentStack.java
>>    (with props)
>>
>> Added: 
>> tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java
>> URL: 
>> http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/collections/ConcurrentStack.java?rev=1389076&view=auto
> 
>> +package org.apache.tomcat.util.collections;
>> +
>> +/**
>> + * This is intended as a (mostly) GC-free alternative to
>> + * {@link java.util.concurrent.LinkedBlockingDeque} where the requirement 
>> is to
>> + * create a pool of re-usable objects with no requirement to shrink the 
>> pool.
>> + * The aim is to provide the bare minimum of required functionality as 
>> quickly
>> + * as possible with minimum garbage.
>> + */
>> +public class ConcurrentStack<T> {
>> +
>> +    private int size = 128;
>> +    /*
>> +     * Points to the next available object in the stack
>> +     */
>> +    private int index = -1;
>> +
>> +    private Object[] stack = new Object[size];
>> +
>> +    public synchronized void push(T obj) {
>> +        index++;
>> +        if (index == size) {
>> +            expand();
>> +        }
>> +        stack[index] = obj;
>> +    }
>> +
>> +    @SuppressWarnings("unchecked")
>> +    public synchronized T pop() {
>> +        if (index == -1) {
>> +            return null;
>> +        }
>> +        return (T) stack[index--];
>> +    }
>> +
>> +    private void expand() {
>> +        int newSize = size * 2;
>> +        Object[] newStack = new Object[newSize];
>> +        System.arraycopy(stack, 0, newStack, 0, size);
>> +        // This is the only point where garbage is created by throwing away 
>> the
>> +        // old array. Note it is only the array, not the contents, that 
>> becomes
>> +        // garbage.
>> +        stack = newStack;
>> +        size = newSize;
>> +    }
>> +}
>>
> 
> 
> Mismatching name. It is rather a "SynchronizedStack".

Fair enough. I'll rename.

> Wouldn't its synchronized methods be a bottleneck? (That is what
> ConcurrentLinkedQueue is designed to avoid).

You'd think so but I am running the performance unit tests on an 8-core
machine and SynchronizedStack beats ConcurrentLinkedQueue every time by
a clear margin.

ConcurrentLinkedQueue still uses synchronisation, just a lot less of it.
SynchronizedStack beats it by only implementing exactly what is required
and trading complexity for simplicity and synchronization.

Also, the unit test is a worst case test in terms of contention. Real
life performance will be better. There may be a switch over point with
very large numbers of cores but I don't have access to a free machine
with a large number of cores to test on.

Hmm. people.a.o has 48 cores. There are plenty of other users but I can
do some testing on there to see what the behaviour is like with a large
number of threads. It is *very* slow at the minute so I may have to wait
a while.

I'm also keeping an eye on the overall throughput in my load test and
that has remained pretty much unaffected by these changes at around 18k
requests per second.

> The pop() method should assign null value to the slot that it freed.

Already implemented in a later commit.

> (It is not important if the object is going to be re-added to the
> cache.  It would be noticeable if the object would be discarded, e.g.
> a CharBuffer that grew too big so that we do not want to reuse it. It
> would not be GC'd before the slot value is overwritten).

I was prepared to live with that but not for the NIO stuff hence why it
has already been fixed.

Thanks for the review.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to