Hi Jeremy, The attached patch does the following: 1. Use a StringBuffer in toString() methods, instead of concatenating strings directly. 2. Use the faster ByteBuffer operations to fill in arrays, instead of looping over the arrays and manually setting the values. 3. Use List instead of Vector and HashMap instead of HashTable. This is to lose the extra unneeded synchronization point that exists in these old and deprecated (as of Java 1.2) classes. Since ByteBuffer assumes at least JDK 1.4, no need to use older API. 4. Use Iterator instead of Enumeration - same reason as item 3. 5. Changed the implementation of Queue.removeAllElements() to a more efficient implementation. 6. Modified the ThreadPool to use a ThreadGroup and provide thread names - this makes the class more profiler friendly. Regards, Lior
diff -Nur /tmp/muscle/java/com/lcs/muscle/message/Message.java com/lcs/muscle/message/Message.java --- /tmp/muscle/java/com/lcs/muscle/message/Message.java 2006-02-10 05:16:59.000000000 +0200 +++ com/lcs/muscle/message/Message.java 2006-12-28 19:48:06.000000000 +0200 @@ -9,10 +9,10 @@ import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.Vector; +import java.util.Map; import com.lcs.muscle.support.Flattenable; import com.lcs.muscle.support.LEDataInputStream; @@ -43,7 +43,7 @@ /** Default Constructor. */ public Message() { - if (_empty == null) _empty = new Hashtable(); // IE5 is lame + if (_empty == null) _empty = new HashMap(); // IE5 is lame } /** Constructor. @@ -81,11 +81,11 @@ clear(); Message copyMe = (Message)c; what = copyMe.what; - Enumeration fields = copyMe.fieldNames(); - while(fields.hasMoreElements()) + Iterator fields = copyMe.fieldNames(); + while(fields.hasNext()) { try { - copyMe.copyField((String)fields.nextElement(), this); + copyMe.copyField((String)fields.next(), this); } catch(FieldNotFoundException ex) { ex.printStackTrace(); // should never happen @@ -93,12 +93,12 @@ } } - /** Returns an Enumeration of Strings that are the + /** Returns an Iterator of Strings that are the * field names present in this Message */ - public Enumeration fieldNames() + public Iterator fieldNames() { - return (_fieldTable != null) ? _fieldTable.keys() : _empty.keys(); + return (_fieldTable != null) ? _fieldTable.keySet().iterator() : _empty.keySet().iterator(); } /** Returns the given 'what' constant as a human readable 4-byte string, e.g. "BOOL", "BYTE", etc. @@ -124,10 +124,10 @@ if (type == B_ANY_TYPE) return _fieldTable.size(); int count = 0; - Enumeration e = _fieldTable.elements(); - while(e.hasMoreElements()) + Iterator e = _fieldTable.values().iterator(); + while(e.hasNext()) { - MessageField field = (MessageField) e.nextElement(); + MessageField field = (MessageField) e.next(); if (field.typeCode() == type) count++; } return count; @@ -142,15 +142,16 @@ /** Returns a string that is a summary of the contents of this Message. Good for debugging. */ public String toString() { - String ret = "Message: what='" + whatString(what) + "' ("+what+"), countFields=" + countFields() + ", flattenedSize=" + flattenedSize() + "\n"; - // Better to not use the keyword "enum" - it is reserved in JDK 1.5 - Enumeration enumeration = fieldNames(); - while(enumeration.hasMoreElements()) + StringBuffer ret = new StringBuffer(); + ret.append("Message: what='").append(whatString(what)).append("' (").append(what).append("), countFields=") + .append(countFields()).append(", flattenedSize=").append(flattenedSize()).append('\n'); + Iterator iterator = fieldNames(); + while(iterator.hasNext()) { - String fieldName = (String) enumeration.nextElement(); - ret += " " + fieldName + ": " + _fieldTable.get(fieldName).toString() + "\n"; + String fieldName = (String) iterator.next(); + ret.append(" ").append(fieldName).append(": ").append(_fieldTable.get(fieldName)).append('\n'); } - return ret; + return ret.toString(); } /** Renames a field. @@ -177,10 +178,10 @@ int sum = 4 + 4 + 4; // 4 bytes for the protocol revision #, 4 bytes for the number-of-entries field, 4 bytes for what code if (_fieldTable != null) { - Enumeration e = fieldNames(); - while(e.hasMoreElements()) + Iterator e = fieldNames(); + while(e.hasNext()) { - String fieldName = (String) e.nextElement(); + String fieldName = (String) e.next(); MessageField field = (MessageField) _fieldTable.get(fieldName); // 4 bytes for the name length, name data, 4 bytes for entry type code, 4 bytes for entry data length, entry data @@ -213,10 +214,10 @@ out.writeInt(CURRENT_PROTOCOL_VERSION); out.writeInt(what); out.writeInt(countFields()); - Enumeration e = fieldNames(); - while(e.hasMoreElements()) + Iterator e = fieldNames(); + while(e.hasNext()) { - String name = (String) e.nextElement(); + String name = (String) e.next(); MessageField field = (MessageField) _fieldTable.get(name); out.writeInt(name.length()+1); out.writeBytes(name); @@ -241,10 +242,10 @@ out.putInt(CURRENT_PROTOCOL_VERSION); out.putInt(what); out.putInt(countFields()); - Enumeration e = fieldNames(); - while(e.hasMoreElements()) + Iterator e = fieldNames(); + while(e.hasNext()) { - String name = (String) e.nextElement(); + String name = (String) e.next(); MessageField field = (MessageField) _fieldTable.get(name); byte[] nameBytes = name.getBytes(); out.putInt(nameBytes.length+1); @@ -1229,7 +1230,7 @@ /** Convenience method: when it returns, _fieldTable is guaranteed to be non-null. */ private void ensureFieldTableAllocated() { - if (_fieldTable == null) _fieldTable = new Hashtable(); + if (_fieldTable == null) _fieldTable = new HashMap(); } /** Sets the contents of a field */ @@ -1509,35 +1510,40 @@ case B_INT16_TYPE: { short [] array = (short[]) _payload; - for (int i=0; i<_numItems; i++) out.putShort(array[i]); + out.asShortBuffer().put(array, 0, _numItems); + out.position(out.position()+array.length*2); } break; case B_FLOAT_TYPE: { float [] array = (float[]) _payload; - for (int i=0; i<_numItems; i++) out.putFloat(array[i]); + out.asFloatBuffer().put(array, 0, _numItems); + out.position(out.position()+array.length*4); } break; case B_INT32_TYPE: { int [] array = (int[]) _payload; - for (int i=0; i<_numItems; i++) out.putInt(array[i]); + out.asIntBuffer().put(array, 0, _numItems); + out.position(out.position()+array.length*4); } break; case B_INT64_TYPE: { long [] array = (long[]) _payload; - for (int i=0; i<_numItems; i++) out.putLong(array[i]); + out.asLongBuffer().put(array, 0, _numItems); + out.position(out.position()+array.length*8); } break; case B_DOUBLE_TYPE: { double [] array = (double[]) _payload; - for (int i=0; i<_numItems; i++) out.putDouble(array[i]); + out.asDoubleBuffer().put(array, 0, _numItems); + out.position(out.position()+array.length*8); } break; @@ -1629,7 +1635,8 @@ case B_INT16_TYPE: { short [] array = new short[_numItems]; - for (int i=0; i<_numItems; i++) array[i] = in.getShort(); + in.asShortBuffer().get(array); + in.position(in.position()+array.length*2); _payload = array; } break; @@ -1637,7 +1644,8 @@ case B_FLOAT_TYPE: { float [] array = new float[_numItems]; - for (int i=0; i<_numItems; i++) array[i] = in.getFloat(); + in.asFloatBuffer().get(array); + in.position(in.position()+array.length*4); _payload = array; } break; @@ -1645,7 +1653,8 @@ case B_INT32_TYPE: { int [] array = new int[_numItems]; - for (int i=0; i<_numItems; i++) array[i] = in.getInt(); + in.asIntBuffer().get(array); + in.position(in.position()+array.length*4); _payload = array; } break; @@ -1653,7 +1662,8 @@ case B_INT64_TYPE: { long [] array = new long[_numItems]; - for (int i=0; i<_numItems; i++) array[i] = in.getLong(); + in.asLongBuffer().get(array); + in.position(in.position()+array.length*8); _payload = array; } break; @@ -1661,7 +1671,8 @@ case B_DOUBLE_TYPE: { double [] array = new double[_numItems]; - for (int i=0; i<_numItems; i++) array[i] = in.getDouble(); + in.asDoubleBuffer().get(array); + in.position(in.position()+array.length*8); _payload = array; } break; @@ -1702,8 +1713,6 @@ numBytes -= (subMessageSize + 4); // 4 for the size int } _numItems = temp.size(); -// Message array[] = new Message[_numItems]; -// for (int j=0; j<_numItems; j++) array[j] = (Message) temp.get(j); Message[] array = (Message[]) temp.toArray(new Message[_numItems]); _payload = array; } @@ -1837,18 +1846,18 @@ case B_MESSAGE_TYPE: { - Vector temp = new Vector(); + List temp = new ArrayList(); while(numBytes > 0) { Message subMessage = new Message(); int subMessageSize = in.readInt(); subMessage.unflatten(in, subMessageSize); - temp.addElement(subMessage); + temp.add(subMessage); numBytes -= (subMessageSize + 4); // 4 for the size int } _numItems = temp.size(); Message array[] = new Message[_numItems]; - for (int j=0; j<_numItems; j++) array[j] = (Message) temp.elementAt(j); + for (int j=0; j<_numItems; j++) array[j] = (Message) temp.get(j); _payload = array; } break; @@ -1891,95 +1900,97 @@ /** Prints some debug info about our state to (out) */ public String toString() { - String ret = " Type='"+whatString(_type)+"', " + _numItems + " items: "; + StringBuffer ret = new StringBuffer(" Type='"); + ret.append(whatString(_type)).append("', ").append(_numItems).append(" items: "); int pitems = (_numItems < 10) ? _numItems : 10; switch(_type) { case B_BOOL_TYPE: { boolean [] array = (boolean[]) _payload; - for (int i=0; i<pitems; i++) ret += ((array[i]) ? "true " : "false "); + for (int i=0; i<pitems; i++) ret.append((array[i]) ? "true " : "false "); } break; case B_INT8_TYPE: { byte [] array = (byte[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_INT16_TYPE: { short [] array = (short[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_FLOAT_TYPE: { float [] array = (float[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_INT32_TYPE: { int [] array = (int[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_INT64_TYPE: { long [] array = (long[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_DOUBLE_TYPE: { double [] array = (double[]) _payload; - for (int i=0; i<pitems; i++) ret += (array[i] + " "); + for (int i=0; i<pitems; i++) ret.append(array[i]).append(' '); } break; case B_POINT_TYPE: { Point [] array = (Point[]) _payload; - for (int i=0; i<pitems; i++) ret += array[i]; + for (int i=0; i<pitems; i++) ret.append(array[i]); } break; case B_RECT_TYPE: { Rect [] array = (Rect[]) _payload; - for (int i=0; i<pitems; i++) ret += array[i]; + for (int i=0; i<pitems; i++) ret.append(array[i]); } break; case B_MESSAGE_TYPE: { Message [] array = (Message[]) _payload; - for (int i=0; i<pitems; i++) ret += ("["+whatString(array[i].what)+", "+array[i].countFields()+" fields] "); + for (int i=0; i<pitems; i++) + ret.append('[').append(whatString(array[i].what)).append(", ").append(array[i].countFields()).append(" fields] "); } break; case B_STRING_TYPE: { String [] array = (String[]) _payload; - for (int i=0; i<pitems; i++) ret += ("[" + array[i] + "] "); + for (int i=0; i<pitems; i++) ret.append('[').append(array[i]).append("] "); } break; default: { byte [][] array = (byte[][]) _payload; - for (int i=0; i<pitems; i++) ret += ("["+array[i].length+" bytes] "); + for (int i=0; i<pitems; i++) ret.append('[').append(array[i].length).append(" bytes] "); } break; } - return ret; + return ret.toString(); } /** Makes an independent clone of this field object (a bit expensive) */ @@ -2153,7 +2164,7 @@ private LEDataInputStream _lepais = null; private LEDataOutputStream _lepaos = null; - private Hashtable _fieldTable = null; // our name -> MessageField table - private static Hashtable _empty; // = new Hashtable(0); // had to change this to be done on-demand in the ctor, as IE was throwing fits :^( + private Map _fieldTable = null; // our name -> MessageField table + private static Map _empty; // = new Hashtable(0); // had to change this to be done on-demand in the ctor, as IE was throwing fits :^( } diff -Nur /tmp/muscle/java/com/lcs/muscle/queue/Queue.java com/lcs/muscle/queue/Queue.java --- /tmp/muscle/java/com/lcs/muscle/queue/Queue.java 2006-01-31 03:47:36.000000000 +0200 +++ com/lcs/muscle/queue/Queue.java 2006-12-28 18:27:15.000000000 +0200 @@ -160,7 +160,12 @@ } /** Removes all elements from the queue. */ - public void removeAllElements() {while(_elementCount > 0) removeLastElement();} + public void removeAllElements() { + _queue = null; // demand-allocated object array + _elementCount = 0; // number of valid elements in the array + _headIndex = -1; // index of the first filled slot, or -1 + _tailIndex = -1; + } /** Returns the number of elements in the queue. (This number does not include pre-allocated space) */ public int size() {return _elementCount;} diff -Nur /tmp/muscle/java/com/lcs/muscle/test/TestClient.java com/lcs/muscle/test/TestClient.java --- /tmp/muscle/java/com/lcs/muscle/test/TestClient.java 2006-12-28 19:12:03.000000000 +0200 +++ com/lcs/muscle/test/TestClient.java 2006-12-28 19:46:12.000000000 +0200 @@ -48,6 +48,7 @@ try { String command = st.nextToken(); Message msg = new Message(); + msg.what = PR_COMMAND_PING; if (command.equalsIgnoreCase("q")) break; else if (command.equalsIgnoreCase("t")) { diff -Nur /tmp/muscle/java/com/lcs/muscle/thread/ThreadPool.java com/lcs/muscle/thread/ThreadPool.java --- /tmp/muscle/java/com/lcs/muscle/thread/ThreadPool.java 2005-08-19 03:17:03.000000000 +0300 +++ com/lcs/muscle/thread/ThreadPool.java 2006-12-28 18:21:06.000000000 +0200 @@ -34,7 +34,7 @@ if ((_idleThreadCount <= 0)&&(_threadCount < _highMark)) { _threadCount++; // note that the new thread exists - Thread t = new Thread(this); + Thread t = new Thread(_threadGroup, this, "MUSCLE worker thread-"+_threadCount); t.setDaemon(true); t.start(); // and off he goes } @@ -105,7 +105,8 @@ } private static ThreadPool _defaultThreadPool = new ThreadPool(); // singleton - + + private ThreadGroup _threadGroup = new ThreadGroup("Muscle Threads"); private Queue _tasks = new Queue(); // Runnables that need to be run private int _idleThreadCount = 0; // how many threads are idle private int _threadCount = 0; // how many threads are in the pool