001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.util;
005:
006: import java.io.ByteArrayOutputStream;
007: import java.io.IOException;
008: import java.io.ObjectOutputStream;
009: import java.io.Serializable;
010: import java.lang.reflect.Array;
011: import java.lang.reflect.Field;
012: import java.lang.reflect.Modifier;
013: import java.util.ArrayList;
014: import java.util.Arrays;
015: import java.util.HashMap;
016: import java.util.IdentityHashMap;
017: import java.util.List;
018: import java.util.Map;
019:
020: /**
021: * This is a nifty little class that lets you 'profile' the serialization speed of a given object: it will serialize the
022: * object in question, and each class underneath that object, printing the speed of each serialization at the end.
023: */
024: public class SerializationSpeedTester {
025:
026: public static class SpeedEntry implements Comparable {
027: private final Class theClass;
028:
029: private final double millisecondsPerSerialization;
030:
031: public SpeedEntry(Class theClass,
032: double millisecondsPerSerialization) {
033: Assert.assertNotNull(theClass);
034:
035: this .theClass = theClass;
036: this .millisecondsPerSerialization = millisecondsPerSerialization;
037: }
038:
039: public String toString() {
040: return "Class " + this .theClass.getName() + ": "
041: + this .millisecondsPerSerialization
042: + " ms per serialization, on average.";
043: }
044:
045: public int compareTo(Object that) {
046: double other = ((SpeedEntry) that).millisecondsPerSerialization;
047: if (this .millisecondsPerSerialization > other)
048: return 1;
049: else if (this .millisecondsPerSerialization == other)
050: return 0;
051: else
052: return -1;
053: }
054: }
055:
056: public SpeedEntry[] testSpeedOf(Serializable rootObject) {
057: return testSpeedOf(rootObject, "com.tc");
058: }
059:
060: public SpeedEntry[] testSpeedOf(Serializable rootObject,
061: String requiredPrefix) {
062: Assert.assertNotNull(rootObject);
063:
064: Map classMap = new HashMap();
065: testSpeedOf(rootObject, classMap, new IdentityHashMap(),
066: requiredPrefix, "root");
067:
068: SpeedEntry[] entries = (SpeedEntry[]) classMap.values()
069: .toArray(new SpeedEntry[classMap.size()]);
070: Arrays.sort(entries);
071: return entries;
072: }
073:
074: private void testSpeedOf(Object object, Map classMap,
075: Map processedObjects, String requiredPrefix,
076: String fromWhere) {
077: Assert.assertNotNull(object);
078:
079: if (object.getClass().isPrimitive())
080: return;
081: // if (object.getClass().getName().equals("sun.reflect.UnsafeStaticObjectFieldAccessorImpl")) return;
082:
083: if (processedObjects.containsKey(object))
084: return;
085: else {
086: processedObjects.put(object, new Integer(1));
087: }
088:
089: Class objectClass = object.getClass();
090:
091: if (objectClass.isArray()) {
092: if (!objectClass.getComponentType().isPrimitive()) {
093: int length = Array.getLength(object);
094: for (int i = 0; i < length; ++i) {
095: Object value = Array.get(object, i);
096: if (value != null
097: && (!value.getClass().isPrimitive())) {
098: testSpeedOf(value, classMap, processedObjects,
099: requiredPrefix, fromWhere + "[" + i
100: + "]");
101: }
102: }
103: }
104: } else {
105: if (Serializable.class.isAssignableFrom(object.getClass())
106: && object.getClass().getName().startsWith(
107: requiredPrefix)
108: && (!classMap.containsKey(object.getClass()))) {
109: classMap.put(objectClass, new SpeedEntry(objectClass,
110: getSpeedOf(object)));
111: }
112:
113: try {
114: Field[] fields = getFields(objectClass);
115: for (int i = 0; i < fields.length; ++i) {
116: if (fields[i].getType().isPrimitive())
117: continue;
118: if (Modifier.isStatic(fields[i].getModifiers()))
119: continue;
120: if (!fields[i].isAccessible())
121: fields[i].setAccessible(true);
122:
123: Object value = fields[i].get(object);
124: if (value != null
125: && (!value.getClass().isPrimitive())) {
126: testSpeedOf(value, classMap, processedObjects,
127: requiredPrefix, fields[i].toString());
128: }
129: }
130: } catch (Exception e) {
131: System.err.println("ERROR ON: " + object + " OF CLASS "
132: + object.getClass());
133: e.printStackTrace();
134: }
135: }
136: }
137:
138: private Field[] getFields(Class objectClass) {
139: List list = new ArrayList();
140: addFields(objectClass, list);
141: return (Field[]) list.toArray(new Field[list.size()]);
142: }
143:
144: private void addFields(Class objectClass, List list) {
145: Field[] fields = objectClass.getDeclaredFields();
146: list.addAll(Arrays.asList(fields));
147: Class super class = objectClass.getSuperclass();
148: if (super class != null)
149: addFields(super class, list);
150: }
151:
152: private static final int SERIALIZATION_COUNT = 1;
153:
154: private double getSpeedOf(Object object) {
155: try {
156: ByteArrayOutputStream baos = new ByteArrayOutputStream();
157:
158: System.err.println("Serializing object of class "
159: + object.getClass() + "...");
160: long startTime = System.currentTimeMillis();
161: for (int i = 0; i < SERIALIZATION_COUNT; ++i) {
162: ObjectOutputStream oos = new ObjectOutputStream(baos);
163: oos.writeObject(object);
164: oos.close();
165: }
166: long endTime = System.currentTimeMillis();
167: baos.reset();
168: System.err.println("Took " + (endTime - startTime)
169: + " ms for " + object.getClass());
170:
171: double out = (((double) (endTime - startTime)) / (double) SERIALIZATION_COUNT);
172: // System.err.println("Class " + object.getClass() + ": " + out);
173: return out;
174: } catch (IOException ioe) {
175: System.err.println("Can't get speed of: "
176: + object.getClass().getName());
177: return -1.0;
178: }
179: }
180:
181: public static void main(String[] args) throws Exception {
182: // needs a good main
183: }
184:
185: }
|