/*** * ASM performance test: measures the performances of asm package * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.commons.EmptyVisitor; import org.objectweb.asm.tree.ClassNode; /** * @author Eric Bruneton */ public abstract class ALLPerfTest extends ClassLoader { private static ZipFile zip; private static ZipOutputStream dst; private static int mode; private static int total; private static int totalSize; private static double[][] perfs; static boolean compute; static boolean skipDebug; public static void main(String[] args) throws Exception { ZipFile zip = new ZipFile(System.getProperty("java.home") + "/lib/rt.jar"); List classes = new ArrayList(); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry e = (ZipEntry) entries.nextElement(); String s = e.getName(); if (s.endsWith(".class")) { s = s.substring(0, s.length() - 6).replace('/', '.'); InputStream is = zip.getInputStream(e); classes.add(readClass(is)); } } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); new ClassReader(b).accept(new EmptyVisitor(), false); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize " + classes.size() + " classes = " + t + " ms"); } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); ClassWriter cw = new ClassWriter(false); new ClassReader(b).accept(cw, false); cw.toByteArray(); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize and reserialize " + classes.size() + " classes = " + t + " ms"); } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); ClassReader cr = new ClassReader(b); ClassWriter cw = new ClassWriter(cr, false); cr.accept(cw, false); cw.toByteArray(); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize and reserialize " + classes.size() + " classes (with copyPool) = " + t + " ms"); } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); ClassReader cr = new ClassReader(b); ClassWriter cw = new ClassWriter(true); cr.accept(cw, false); cw.toByteArray(); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize and reserialize " + classes.size() + " classes (with computeMaxs) = " + t + " ms"); } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); new ClassReader(b).accept(new ClassNode(), false); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize " + classes.size() + " classes with tree package = " + t + " ms"); } for (int i = 0; i < 10; ++i) { long t = System.currentTimeMillis(); for (int j = 0; j < classes.size(); ++j) { byte[] b = (byte[]) classes.get(j); ClassWriter cw = new ClassWriter(false); ClassNode cn = new ClassNode(); new ClassReader(b).accept(cn, false); cn.accept(cw); cw.toByteArray(); } t = System.currentTimeMillis() - t; System.out.println("Time to deserialize and reserialize " + classes.size() + " classes with tree package = " + t + " ms"); } classes = null; System.out.println("\nComparing ASM, BCEL, SERP and Javassist performances..."); System.out.println("This may take 20 to 30 minutes\n"); // measures performances System.out.println("ASM PERFORMANCES\n"); new ASMPerfTest().perfs(args); double[][] asmPerfs = perfs; System.out.println("\nBCEL PERFORMANCES\n"); new BCELPerfTest().perfs(args); double[][] bcelPerfs = perfs; System.out.println("\nSERP PERFORMANCES\n"); new SERPPerfTest().perfs(args); double[][] serpPerfs = perfs; System.out.println("\nJavassist PERFORMANCES\n"); new JavassistPerfTest().perfs(args); double[][] javassistPerfs = perfs; // prints results System.out.println("\nGLOBAL RESULTS"); System.out.println("\nWITH DEBUG INFORMATION\n"); for (int step = 0; step < 2; ++step) { for (mode = 0; mode < 4; ++mode) { switch (mode) { case 0: System.out.print("NO ADAPT: "); break; case 1: System.out.print("NULL ADAPT: "); break; case 2: System.out.print("COMPUTE MAXS: "); break; default: System.out.print("ADD COUNTER: "); break; } System.out.print((float) asmPerfs[step][mode] + " ms"); if (mode > 0) { System.out.print(" (*"); System.out.print((float) (asmPerfs[step][mode] / asmPerfs[step][0])); System.out.print(")"); } System.out.print(" "); System.out.print((float) bcelPerfs[step][mode] + " ms"); if (mode > 0) { System.out.print(" (*"); System.out.print((float) (bcelPerfs[step][mode] / bcelPerfs[step][0])); System.out.print(")"); } System.out.print(" "); System.out.print((float) serpPerfs[step][mode] + " ms"); if (mode > 0) { System.out.print(" (*"); System.out.print((float) (serpPerfs[step][mode] / serpPerfs[step][0])); System.out.print(")"); } System.out.print(" "); System.out.print((float) javassistPerfs[step][mode] + " ms"); if (mode > 0) { System.out.print(" (*"); System.out.print((float) (javassistPerfs[step][mode] / javassistPerfs[step][0])); System.out.print(")"); } System.out.println(); } if (step == 0) { System.out.println("\nWITHOUT DEBUG INFORMATION\n"); } } System.out.println("\nRELATIVE RESULTS"); System.out.println("\nWITH DEBUG INFORMATION\n"); for (int step = 0; step < 2; ++step) { System.err.println("[MEASURE ASM BCEL SERP Javassist]"); for (mode = 1; mode < 4; ++mode) { int base; switch (mode) { case 1: System.out.print("NULL ADAPT: "); base = 0; break; case 2: System.out.print("COMPUTE MAXS: "); base = 1; break; default: System.out.print("ADD COUNTER: "); base = 1; break; } double ref = asmPerfs[step][mode] - asmPerfs[step][base]; System.out.print((float) ref + " ms "); double f = bcelPerfs[step][mode] - bcelPerfs[step][base]; System.out.print((float) f + " ms (*"); System.out.print((float) (f / ref)); System.out.print(") "); double g = serpPerfs[step][mode] - serpPerfs[step][base]; System.out.print((float) g + " ms (*"); System.out.print((float) (g / ref)); System.out.print(")"); double h = javassistPerfs[step][mode] - javassistPerfs[step][base]; System.out.print((float) h + " ms (*"); System.out.print((float) (h / ref)); System.out.print(")"); System.out.println(); } if (step == 0) { System.out.println("\nWITHOUT DEBUG INFORMATION\n"); } } } void perfs(final String[] args) throws Exception { // prepares zip files, if necessary if (!(new File(args[0] + "classes1.zip").exists())) { System.out.println("Preparing zip files from " + args[1] + "..."); for (int step = 0; step < 2; ++step) { dst = new ZipOutputStream(new FileOutputStream(args[0] + "classes" + (step + 1) + ".zip")); mode = step == 0 ? 1 : 4; for (int i = 1; i < args.length; ++i) { ALLPerfTest loader = newInstance(); zip = new ZipFile(args[i]); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { String s = ((ZipEntry) entries.nextElement()).getName(); if (s.endsWith(".class")) { s = s.substring(0, s.length() - 6) .replace('/', '.'); loader.loadClass(s); } } } dst.close(); dst = null; } System.out.println(); } // measures performances perfs = new double[2][4]; System.out.println("FIRST STEP: WITH DEBUG INFORMATION"); for (int step = 0; step < 2; ++step) { zip = new ZipFile(args[0] + "classes" + (step + 1) + ".zip"); for (mode = 0; mode < 4; ++mode) { for (int i = 0; i < 4; ++i) { ALLPerfTest loader = newInstance(); total = 0; totalSize = 0; Enumeration entries = zip.entries(); double t = System.currentTimeMillis(); while (entries.hasMoreElements()) { String s = ((ZipEntry) entries.nextElement()).getName(); if (s.endsWith(".class")) { s = s.substring(0, s.length() - 6) .replace('/', '.'); loader.loadClass(s); } } t = System.currentTimeMillis() - t; if (i == 0) { perfs[step][mode] = t; } else { perfs[step][mode] = Math.min(perfs[step][mode], t); } switch (mode) { case 0: System.out.print("NO ADAPT: "); break; case 1: System.out.print("NULL ADAPT: "); break; case 2: System.out.print("COMPUTE MAXS: "); break; default: System.out.print("ADD COUNTER: "); break; } System.out.print((float) t + " ms "); System.out.print("(" + total + " classes"); System.out.println(", " + totalSize + " bytes)"); loader = null; gc(); } } if (step == 0) { System.out.println("SECOND STEP: WITHOUT DEBUG INFORMATION"); } } // prints results System.out.println("\nRESULTS"); System.out.println("\nWITH DEBUG INFORMATION\n"); for (int step = 0; step < 2; ++step) { for (mode = 0; mode < 4; ++mode) { switch (mode) { case 0: System.out.print("NO ADAPT: "); break; case 1: System.out.print("NULL ADAPT: "); break; case 2: System.out.print("COMPUTE MAXS: "); break; default: System.out.print("ADD COUNTER: "); break; } System.out.println((float) perfs[step][mode] + " ms"); } if (step == 0) { System.out.println("\nWITHOUT DEBUG INFORMATION\n"); } } } private static byte[] readClass(final InputStream is) throws IOException { if (is == null) { throw new IOException("Class not found"); } byte[] b = new byte[is.available()]; int len = 0; while (true) { int n = is.read(b, len, b.length - len); if (n == -1) { if (len < b.length) { byte[] c = new byte[len]; System.arraycopy(b, 0, c, 0, len); b = c; } return b; } else { len += n; if (len == b.length) { byte[] c = new byte[b.length + 1000]; System.arraycopy(b, 0, c, 0, len); b = c; } } } } protected Class findClass(final String name) throws ClassNotFoundException { try { byte[] b; String fileName = name.replace('.', '/') + ".class"; InputStream is = zip.getInputStream(zip.getEntry(fileName)); switch (mode) { case 0: b = new byte[is.available()]; int len = 0; while (true) { int n = is.read(b, len, b.length - len); if (n == -1) { if (len < b.length) { byte[] c = new byte[len]; System.arraycopy(b, 0, c, 0, len); b = c; } break; } else { len += n; if (len == b.length) { byte[] c = new byte[b.length + 1000]; System.arraycopy(b, 0, c, 0, len); b = c; } } } break; case 1: compute = false; skipDebug = false; b = nullAdaptClass(is, name); break; case 2: compute = true; skipDebug = false; b = nullAdaptClass(is, name); break; case 3: b = counterAdaptClass(is, name); break; // case 4: default: compute = false; skipDebug = true; b = nullAdaptClass(is, name); break; } if (dst != null) { dst.putNextEntry(new ZipEntry(fileName)); dst.write(b, 0, b.length); dst.closeEntry(); } total += 1; totalSize += b.length; return defineClass(name, b, 0, b.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(name); } } private static void gc() { try { Runtime.getRuntime().gc(); Thread.sleep(50); Runtime.getRuntime().gc(); Thread.sleep(50); Runtime.getRuntime().gc(); Thread.sleep(50); } catch (InterruptedException e) { } } abstract ALLPerfTest newInstance(); abstract byte[] nullAdaptClass(final InputStream is, final String name) throws Exception; abstract byte[] counterAdaptClass(final InputStream is, final String name) throws Exception; }