/* ******************************************************************* * Copyright (c) 2004 IBM Corporation * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * Contributors: * Noel Markham, Matthew Webster initial implementation * ******************************************************************/ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * @author Noel Markham */ public class WeaveTest { private static final String OUTPUT_PACKAGE = "out"; private static final int WEAVE_FAST = 1; private static final int WEAVE_MED = 2; private static final int WEAVE_SLOW = 3; public static final String EXECUTION_SLOW = "execution(void *(..))"; public static final String EXECUTION_MED = "args(" + OUTPUT_PACKAGE + ".C0) && execution(void m0(..))"; public static final String EXECUTION_FAST = "within(" + OUTPUT_PACKAGE + ".C0) && execution(void m0(..))"; public static final String GET_SLOW = "get(int *)"; public static final String GET_MED = "target(" + OUTPUT_PACKAGE + ".C0) && get(int i0)"; public static final String GET_FAST = "get(int " + OUTPUT_PACKAGE + ".C0.i0)"; // Defaults, can be changed with command-line args private static int NUMCLASSES = 5; private static int ITERATIONS = 3; private static int METHODLINES = 20; private static int NUMMETHODS = 100; private static boolean INCLUDE_TEST_CLASSES = false; private static boolean TEST_GET = true; private static boolean TEST_EXECUTION = true; private static boolean ALL_POINTCUT_TESTS = true; private static boolean TEST_ONE = false; private static boolean TEST_ONE_SEARCH_ALL = false; private static boolean TEST_ALL = false; private static boolean ECHO = false; public static long[] compileTimes = new long[ITERATIONS]; public static long[] executionSlowTimes = new long[ITERATIONS]; public static long[] executionMedTimes = new long[ITERATIONS]; public static long[] executionFastTimes = new long[ITERATIONS]; public static long[] getSlowTimes = new long[ITERATIONS]; public static long[] getMedTimes = new long[ITERATIONS]; public static long[] getFastTimes = new long[ITERATIONS]; private static final String NL = System.getProperty("line.separator", "\n"); private static final File outputDir = new File(System.getProperty("user.dir") + File.separatorChar + OUTPUT_PACKAGE); static { outputDir.mkdirs(); } public static void main(String[] args) throws IOException { //if (args.length > 0) parseArgs(args); parseArgs(args); if(ECHO) System.out.println("Weave-time Test"); if(ECHO) System.out.println("---------------"); if(ECHO) System.out.println("Number of classes: " + NUMCLASSES); if(ECHO) System.out.println("Number of methods: " + NUMMETHODS); if(ECHO) System.out.println("Number of method lines: " + METHODLINES); if(ECHO) System.out.println("Number of test iterations: " + ITERATIONS); if(ECHO) if(INCLUDE_TEST_CLASSES) System.out.println("Including advice test classes"); if(ECHO) if(TEST_GET && !TEST_EXECUTION) System.out.println("Weaving only get advice"); if(ECHO) if(TEST_EXECUTION && !TEST_GET) System.out.println("Weaving only execution advice"); if(ECHO) { if(!ALL_POINTCUT_TESTS) { if(TEST_ONE) System.out.println("Weaving one poinctcut"); if(TEST_ONE_SEARCH_ALL) System.out.println("Weaving one pointcut, searching all"); if(TEST_ALL) System.out.println("Weaving all"); } } if(ECHO) System.out.println(); createClasses(); compileClasses(); boolean warm = false; if (TEST_EXECUTION) { String advice = "execution"; createAspects(advice); //Warm up the weaver weaveAllAspects(advice, WEAVE_FAST); warm = true; weaveAspects(advice); } if (TEST_GET) { String advice = "get"; createAspects(advice); if(!warm) weaveAllAspects(advice, WEAVE_FAST); weaveAspects(advice); } } private static void parseArgs(String[] args) { if(args == null || args.length <= 0) return; int i = 0; boolean error = false; while(i < args.length) { String arg = args[i++]; try { if(arg.equals("-c")) { // Number of classes if(i < args.length) NUMCLASSES = Integer.parseInt(args[i++]); else error = true; } else if(arg.equals("-m")) { // Number of methods if(i < args.length) NUMMETHODS = Integer.parseInt(args[i++]); else error = true; } else if(arg.equals("-l")) { // Number of method lines if(i < args.length) METHODLINES = Integer.parseInt(args[i++]); else error = true; } else if(arg.equals("-i")) { // Number of iterations if(i < args.length) ITERATIONS = Integer.parseInt(args[i++]); else error = true; } else if(arg.equals("-include-tests")) { if(i < args.length) { arg = args[i++]; if(arg.equalsIgnoreCase("y")) INCLUDE_TEST_CLASSES = true; else if(arg.equalsIgnoreCase("n")) INCLUDE_TEST_CLASSES = false; else error = true; } } else if(arg.equals("-advice")) { String advice = args[i++]; if(advice.equals("get")){ TEST_GET = true; TEST_EXECUTION = false; } else if(advice.equals("execution")){ TEST_EXECUTION = true; TEST_GET = false; } else error = true; } else if(arg.equals("-pointcut")) { ALL_POINTCUT_TESTS = false; String advice = args[i++]; if(advice.equals("fast")) TEST_ONE = true; else if(advice.equals("meduim")) TEST_ONE_SEARCH_ALL = true; else if(advice.equals("slow")) TEST_ALL = true; else error = true; } else if(arg.equals("-echo")) { ECHO = true; } else if (arg.equals("-help")) { usage(); } else error = true; } catch (NumberFormatException e) { usage(); } if(error) usage(); compileTimes = new long[ITERATIONS]; executionSlowTimes = new long[ITERATIONS]; executionMedTimes = new long[ITERATIONS]; executionFastTimes = new long[ITERATIONS]; getSlowTimes = new long[ITERATIONS]; getMedTimes = new long[ITERATIONS]; getFastTimes = new long[ITERATIONS]; } } private static void usage() { System.err.println("Usage:"); System.err.println("\tjava WeaveTests [-c num_of_classes] [-m num_of_methods] " + "[-l num_of_method_lines] [-i num_of_iterations]" + "\n\t\t[-include-tests y|n] [-advice get|execution] [-pointcut fast|medium|slow] [-echo] [-help]"); System.exit(-1); } /** * Will create a number of classes of the following form: * * public class C0 { * * int i0; * ... * int iN; * * void m0(C0 arg) { * i0++; * ... * iN++; * } * ... * void mN(C0 arg) { * ... * } * */ public static void createClasses() throws IOException { if(ECHO) System.out.println("Creating classes"); for(int classcounter = 0; classcounter < NUMCLASSES; classcounter++) { StringBuilder classfile = new StringBuilder(1000); classfile.append("// Auto-generated" + NL); classfile.append("package " + OUTPUT_PACKAGE + ";" + NL + NL); classfile.append("public class C" + classcounter + " {" + NL + NL); for(int intdeclaration = 0; intdeclaration < METHODLINES; intdeclaration++) { classfile.append("\tint i" + intdeclaration + ";" + NL); } classfile.append("\tint getter;" + NL); classfile.append(NL); for(int methodcounter = 0; methodcounter < NUMMETHODS; methodcounter++) { classfile.append("\tvoid m" + methodcounter + "(C" + classcounter + " arg) {" + NL); for(int methodbody = 0; methodbody < METHODLINES; methodbody++) { classfile.append("\t\ti" + methodbody + "++;" + NL); } classfile.append("\t}" + NL + NL); } classfile.append("}" + NL); try { File f = new File(outputDir, ("C" + classcounter + ".java")); FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(new String(classfile).getBytes()); bos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } } if (INCLUDE_TEST_CLASSES) { StringBuilder testFiles = new StringBuilder(1000); try { testFiles.append("// Auto generated" + NL); testFiles.append("package " + OUTPUT_PACKAGE + ";" + NL + NL); testFiles.append("public class TestGet {" + NL + NL); testFiles.append( "\tpublic static void main(String args[]) {" + NL); testFiles.append("\t\tC0 tester = new C0();" + NL); testFiles.append("\t\tint i = tester.i0;" + NL); testFiles.append("\t}" + NL); testFiles.append("}" + NL); File f = new File(outputDir, "TestGet.java"); FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(new String(testFiles).getBytes()); bos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } testFiles = new StringBuilder(1000); try { testFiles.append("// Auto generated" + NL); testFiles.append("package " + OUTPUT_PACKAGE + ";" + NL + NL); testFiles.append("public class TestExecution {" + NL + NL); testFiles.append( "\tpublic static void main(String args[]) {" + NL); testFiles.append("\t\tC0 tester = new C0();" + NL); testFiles.append("\t\ttester.m0(tester);" + NL); testFiles.append("\t}" + NL); testFiles.append("}" + NL); File f = new File(outputDir, "TestExecution.java"); FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(new String(testFiles).getBytes()); bos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } } StringBuilder buildList = new StringBuilder(100); for(int i = 0; i < NUMCLASSES; i++) buildList.append("C" + i + ".java" + NL); if (INCLUDE_TEST_CLASSES) { buildList.append("TestGet.java" + NL); buildList.append("TestExecution.java" + NL); } try { File f = new File(outputDir, "build.lst"); FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(new String(buildList).getBytes()); bos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } } /** * @param adviceType Either "get" or "execution" depending on which test. * * Will create an aspect such as the following: * * public aspect GetAdviceWeaveOne { * * before() : get(int output.C0.getter) { * System.out.println("In the aspect"); * } * } */ public static void createAspects(String adviceType) { adviceType = adviceType.toLowerCase(); if((!adviceType.equals("get")) && (!adviceType.equals("execution"))) { System.err.println("Only get and execution advice is supported"); System.exit(-1); } if(ECHO) System.out.println("Creating aspects"); if(ALL_POINTCUT_TESTS || TEST_ONE) createAllAspects(adviceType, WEAVE_FAST); if(ALL_POINTCUT_TESTS || TEST_ONE_SEARCH_ALL) createAllAspects(adviceType, WEAVE_MED); if(ALL_POINTCUT_TESTS || TEST_ALL) createAllAspects(adviceType, WEAVE_SLOW); } private static void createAllAspects(String adviceType, int pointcut) { StringBuilder aspectFile = new StringBuilder(1000); // Capitalises the first char in the adviceType String, and then adds "Advice" to it. String adviceName = (char)(adviceType.charAt(0) - 32) + adviceType.substring(1) + "Advice"; switch(pointcut) { case WEAVE_FAST: adviceName += "WeaveFast"; break; case WEAVE_MED: adviceName += "WeaveMedium"; break; case WEAVE_SLOW: adviceName += "WeaveSlow"; break; } aspectFile.append("// Auto-generated" + NL + NL); aspectFile.append("public aspect " + adviceName + " {" + NL + NL); aspectFile.append("\tbefore() : "); if(adviceType.equals("execution")) { switch(pointcut) { case WEAVE_FAST: aspectFile.append(EXECUTION_FAST); break; case WEAVE_MED: aspectFile.append(EXECUTION_MED); break; case WEAVE_SLOW: aspectFile.append(EXECUTION_SLOW); break; } } else { switch(pointcut) { case WEAVE_FAST: aspectFile.append(GET_FAST); break; case WEAVE_MED: aspectFile.append(GET_MED); break; case WEAVE_SLOW: aspectFile.append(GET_SLOW); break; } } aspectFile.append(" {" + NL); aspectFile.append("\t\tSystem.out.println(\"In the aspect\");" + NL); aspectFile.append("\t}" + NL); aspectFile.append("}" + NL); // Create the file try { File f = new File(outputDir, (adviceName + ".aj")); FileOutputStream fos = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(new String(aspectFile).getBytes()); bos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } } public static void compileClasses() throws IOException { if(ECHO) System.out.print("Compiling: "); long average = 0; for (int i = 0; i < ITERATIONS; i++) { long time = performCompile(); compileTimes[i] = time; average += time; } if(ECHO) System.out.println((average / ITERATIONS) + " millis"); } private static long performCompile() throws IOException { String ajcargs = "-noExit -outjar " + OUTPUT_PACKAGE + File.separatorChar + "classes.jar " + "-argfile " + OUTPUT_PACKAGE + File.separatorChar + "build.lst"; // split method creates a String array delimited on a space String[] parsedArgs = RunWeaveTests.split(ajcargs); long start = System.currentTimeMillis(); org.aspectj.tools.ajc.Main.main(parsedArgs); long stop = System.currentTimeMillis(); return stop - start; } public static void weaveAspects(String adviceType) throws IOException { adviceType = adviceType.toLowerCase(); if((!adviceType.equals("get")) && (!adviceType.equals("execution"))) { System.err.println("Only get and execution advice is supported"); System.exit(-1); } long average = 0; if(ECHO) System.out.println((char)(adviceType.charAt(0) - 32) + adviceType.substring(1)); if (ALL_POINTCUT_TESTS || TEST_ONE) { if(ECHO) System.out.print("Weave Fast:"); for (int i = 0; i < ITERATIONS; i++) { long time = weaveAllAspects(adviceType, WEAVE_FAST); if(adviceType.equals("execution")) executionFastTimes[i] = time; else getFastTimes[i] = time; average += time; if(ECHO) System.out.print("."); } if(ECHO) System.out.println(" " + (average / ITERATIONS) + " millis"); } average = 0; if (ALL_POINTCUT_TESTS || TEST_ONE_SEARCH_ALL) { if(ECHO) System.out.print("Weave Medium:"); for (int i = 0; i < ITERATIONS; i++) { long time = weaveAllAspects(adviceType, WEAVE_MED); if(adviceType.equals("execution")) executionMedTimes[i] = time; else getMedTimes[i] = time; average += time; if(ECHO) System.out.print("."); } if(ECHO) System.out.println(" " + (average / ITERATIONS) + " millis"); } average = 0; if (ALL_POINTCUT_TESTS || TEST_ALL) { if(ECHO) System.out.print("Weave Slow:"); for (int i = 0; i < ITERATIONS; i++) { long time = weaveAllAspects(adviceType, WEAVE_SLOW); if(adviceType.equals("execution")) executionSlowTimes[i] = time; else getSlowTimes[i] = time; average += time; if(ECHO) System.out.print("."); } if(ECHO) System.out.println(" " + (average / ITERATIONS) + " millis"); } if(ECHO) System.out.println(); } private static long weaveAllAspects(String adviceType, int pointcut) throws IOException { // Capitalises the first char in the adviceType String, to keep to Java naming convention String adviceName = (char)(adviceType.charAt(0) - 32) + adviceType.substring(1) + "Advice"; switch(pointcut) { case WEAVE_FAST: adviceName += "WeaveFast"; break; case WEAVE_MED: adviceName += "WeaveMedium"; break; case WEAVE_SLOW: adviceName += "WeaveSlow"; break; } String ajcargs = "-noExit -injars " + OUTPUT_PACKAGE + File.separatorChar + "classes.jar " + "-outjar " + OUTPUT_PACKAGE + File.separatorChar + adviceName + ".jar " + OUTPUT_PACKAGE + File.separatorChar + adviceName + ".aj"; String[] parsedArgs = RunWeaveTests.split(ajcargs); long start = System.currentTimeMillis(); org.aspectj.tools.ajc.Main.main(parsedArgs); long stop = System.currentTimeMillis(); return stop - start; } }