001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.tools;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.benchmark.*;
027: import EDU.purdue.cs.bloat.cfg.*;
028: import EDU.purdue.cs.bloat.codegen.*;
029: import EDU.purdue.cs.bloat.context.*;
030: import EDU.purdue.cs.bloat.editor.*;
031: import EDU.purdue.cs.bloat.file.*;
032: import EDU.purdue.cs.bloat.inline.*;
033: import EDU.purdue.cs.bloat.optimize.*;
034: import EDU.purdue.cs.bloat.reflect.*;
035: import EDU.purdue.cs.bloat.trans.*;
036: import EDU.purdue.cs.bloat.tree.*;
037: import EDU.purdue.cs.bloat.util.*;
038:
039: /**
040: * This program is used to BLOAT Java programs. In particular, we use it to
041: * BLOAT the programs used to benchmark BLOAT. This program is intended to be
042: * run multiple times to generate multiple BLOATed programs.
043: */
044: public class BloatBenchmark {
045: public static boolean TRACE = false;
046:
047: private static boolean INLINE = false;
048:
049: private static boolean INTRA = false;
050:
051: private static boolean PEEPHOLE = false;
052:
053: private static boolean VERIFY = true;
054:
055: private static boolean SPECIALIZE = false;
056:
057: private static boolean SUN = false;
058:
059: private static boolean USE1_1 = false;
060:
061: private static boolean CHECK = true;
062:
063: private static boolean TIMES = false;
064:
065: private static final PrintWriter err = new PrintWriter(System.err,
066: true);
067:
068: private static final Set CLASSES = new HashSet();
069:
070: private static String statsFile = null;
071:
072: private static String timesFile = null;
073:
074: private static int DEPTH = 2; // No. calls deep
075:
076: private static int SIZE = 1000; // Max size of methods
077:
078: private static int MORPH = -1; // Max "morphosity" of virtual calls
079:
080: private static int CALLEE_SIZE = -1;
081:
082: private static final List SKIP = new ArrayList(); // Classes that are
083:
084: // specifically not
085: // optimized
086:
087: private static void tr(final String s) {
088: if (BloatBenchmark.TRACE) {
089: System.out.println(s);
090: }
091: }
092:
093: private static void usage() {
094: BloatBenchmark.err
095: .println("java TestSpecialize [options] classNames outputDir");
096: BloatBenchmark.err.println("where [options] are:");
097: BloatBenchmark.err
098: .println(" -calleeSize size Max method size to inline");
099: BloatBenchmark.err
100: .println(" -classpath path Classpath is always prepended");
101: BloatBenchmark.err
102: .println(" -depth depth Max inline depth");
103: BloatBenchmark.err
104: .println(" -inline Inline calls to static methods");
105: BloatBenchmark.err
106: .println(" -intra Intraprocedural BLOAT");
107: BloatBenchmark.err
108: .println(" -lookIn dir Look for classes here");
109: BloatBenchmark.err
110: .println(" -morph morph Max morphosity of call sites");
111: BloatBenchmark.err
112: .println(" -no-verify Don't verify CFG");
113: BloatBenchmark.err
114: .println(" -no-opt-stack Don't optimize stack usage");
115: BloatBenchmark.err
116: .println(" -no-stack-vars Don't use stack vars in CFG");
117: BloatBenchmark.err
118: .println(" -no-stack-alloc Don't try to push locals onto the operand stack");
119: BloatBenchmark.err
120: .println(" -peel-loops <n|all>"
121: + "\n Peel innermost loops to enable code hoisting"
122: + "\n (n >= 0 is the maximum loop level to peel)");
123: BloatBenchmark.err
124: .println(" -no-pre Don't perform partial redundency elimination");
125: BloatBenchmark.err
126: .println(" -no-dce Don't perform dead code elimination");
127: BloatBenchmark.err
128: .println(" -no-prop Don't perform copy and constant propagation");
129: BloatBenchmark.err
130: .println(" -no-color Don't do graph coloring");
131: BloatBenchmark.err
132: .println(" -peephole Perform peephole after inter");
133: BloatBenchmark.err
134: .println(" -size size Max method size");
135: BloatBenchmark.err
136: .println(" -specialize Specialize virtual method calls");
137: BloatBenchmark.err
138: .println(" -stats statsFile Generate stats");
139: BloatBenchmark.err
140: .println(" -sun Include sun packages");
141: BloatBenchmark.err
142: .println(" -times timesFile Print timings");
143: BloatBenchmark.err
144: .println(" -trace Print trace information");
145: BloatBenchmark.err
146: .println(" -no-check Don't check that my options 'make sense'");
147: BloatBenchmark.err
148: .println(" -skip <class|package.*>"
149: + "\n Skip the given class or package");
150: BloatBenchmark.err
151: .println(" -1.1 BLOAT for JDK1.1");
152: BloatBenchmark.err
153: .println(" -1.2 BLOAT for JDK1.2");
154: BloatBenchmark.err.println("");
155: System.exit(1);
156: }
157:
158: public static void main(final String[] args) {
159: String CLASSPATH = null;
160: String outputDirName = null;
161: String lookIn = null;
162:
163: // Parse the command line
164: for (int i = 0; i < args.length; i++) {
165: if (args[i].equals("-trace")) {
166: BloatBenchmark.TRACE = true;
167: PersistentBloatContext.DB_COMMIT = true;
168:
169: } else if (args[i].equals("-calleeSize")) {
170: if (++i >= args.length) {
171: BloatBenchmark.err
172: .println("** No callee size specified");
173: BloatBenchmark.usage();
174: }
175:
176: try {
177: BloatBenchmark.CALLEE_SIZE = Integer
178: .parseInt(args[i]);
179:
180: } catch (final NumberFormatException ex33) {
181: BloatBenchmark.err.println("** Bad number: "
182: + args[i]);
183: BloatBenchmark.usage();
184: }
185:
186: } else if (args[i].startsWith("-classpath")) {
187: if (++i >= args.length) {
188: BloatBenchmark.err
189: .println("** No classpath specified");
190: BloatBenchmark.usage();
191: }
192:
193: // If there is more than one -classpath append it to the
194: // current one. That way the CLASSPATH reflects the order in
195: // which the options came on the command line.
196: if (CLASSPATH == null) {
197: CLASSPATH = args[i];
198:
199: } else {
200: CLASSPATH += File.pathSeparator + args[i];
201: }
202:
203: } else if (args[i].equals("-no-stack-alloc")) {
204: Main.STACK_ALLOC = false;
205:
206: } else if (args[i].equals("-peel-loops")) {
207: if (++i >= args.length) {
208: BloatBenchmark.usage();
209: }
210:
211: final String n = args[i];
212:
213: if (n.equals("all")) {
214: FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS;
215:
216: } else {
217: try {
218: FlowGraph.PEEL_LOOPS_LEVEL = Integer
219: .parseInt(n);
220:
221: if (FlowGraph.PEEL_LOOPS_LEVEL < 0) {
222: BloatBenchmark.usage();
223: }
224: } catch (final NumberFormatException ex) {
225: BloatBenchmark.usage();
226: }
227: }
228: } else if (args[i].equals("-no-color")) {
229: Liveness.UNIQUE = true;
230:
231: } else if (args[i].equals("-no-dce")) {
232: Main.DCE = false;
233:
234: } else if (args[i].equals("-no-prop")) {
235: Main.PROP = false;
236:
237: } else if (args[i].equals("-no-pre")) {
238: Main.PRE = false;
239:
240: } else if (args[i].equals("-no-check")) {
241: BloatBenchmark.CHECK = false;
242:
243: } else if (args[i].equals("-depth")) {
244: if (++i >= args.length) {
245: BloatBenchmark.err.println("** No depth specified");
246: BloatBenchmark.usage();
247: }
248:
249: try {
250: BloatBenchmark.DEPTH = Integer.parseInt(args[i]);
251:
252: } catch (final NumberFormatException ex33) {
253: BloatBenchmark.err.println("** Bad number: "
254: + args[i]);
255: BloatBenchmark.usage();
256: }
257:
258: } else if (args[i].equals("-inline")) {
259: // Inline calls to static methods
260: BloatBenchmark.INLINE = true;
261:
262: } else if (args[i].equals("-intra")) {
263: BloatBenchmark.INTRA = true;
264:
265: } else if (args[i].equals("-lookIn")) {
266: if (++i >= args.length) {
267: BloatBenchmark.err
268: .println("** No directory specified");
269: BloatBenchmark.usage();
270: }
271:
272: if (lookIn != null) {
273: lookIn += File.pathSeparator + args[i];
274:
275: } else {
276: lookIn = args[i];
277: }
278:
279: } else if (args[i].equals("-morph")) {
280: if (++i >= args.length) {
281: BloatBenchmark.err
282: .println("** No morphosity specified");
283: BloatBenchmark.usage();
284: }
285:
286: try {
287: BloatBenchmark.MORPH = Integer.parseInt(args[i]);
288:
289: } catch (final NumberFormatException ex33) {
290: BloatBenchmark.err.println("** Bad number: "
291: + args[i]);
292: BloatBenchmark.usage();
293: }
294:
295: } else if (args[i].equals("-noinline")) {
296: // Don't perform inlining, just specialize
297: BloatBenchmark.INLINE = false;
298:
299: } else if (args[i].equals("-peephole")) {
300: // Perform peephole optimizations when doing interprocedural
301: // stuff
302: BloatBenchmark.PEEPHOLE = true;
303:
304: } else if (args[i].equals("-size")) {
305: if (++i >= args.length) {
306: BloatBenchmark.err.println("** No size specified");
307: BloatBenchmark.usage();
308: }
309:
310: try {
311: BloatBenchmark.SIZE = Integer.parseInt(args[i]);
312:
313: } catch (final NumberFormatException ex33) {
314: BloatBenchmark.err.println("** Bad number: "
315: + args[i]);
316: BloatBenchmark.usage();
317: }
318:
319: } else if (args[i].equals("-specialize")) {
320: // Specialize virtual method call sites
321: BloatBenchmark.SPECIALIZE = true;
322:
323: } else if (args[i].equals("-stats")) {
324: if (++i >= args.length) {
325: BloatBenchmark.err
326: .println("** No stats file specified");
327: BloatBenchmark.usage();
328: }
329:
330: BloatBenchmark.statsFile = args[i];
331:
332: } else if (args[i].equals("-sun")) {
333: // Optimize sun packages
334: BloatBenchmark.SUN = true;
335:
336: } else if (args[i].equals("-times")) {
337: BloatBenchmark.TIMES = true;
338:
339: if (++i >= args.length) {
340: BloatBenchmark.err
341: .println("** No times file specified");
342: BloatBenchmark.usage();
343: }
344:
345: BloatBenchmark.timesFile = args[i];
346:
347: } else if (args[i].equals("-no-verify")) {
348: BloatBenchmark.VERIFY = false;
349:
350: } else if (args[i].equals("-no-opt-stack")) {
351: CodeGenerator.OPT_STACK = false;
352:
353: } else if (args[i].equals("-no-stack-vars")) {
354: Tree.USE_STACK = false;
355:
356: } else if (args[i].equals("-skip")) {
357: if (++i >= args.length) {
358: BloatBenchmark.usage();
359: }
360:
361: String pkg = args[i];
362:
363: // Account for class file name on command line
364: if (pkg.endsWith(".class")) {
365: pkg = pkg.substring(0, pkg.lastIndexOf('.'));
366: }
367:
368: BloatBenchmark.SKIP.add(pkg.replace('.', '/'));
369:
370: } else if (args[i].equals("-1.1")) {
371: // There are some classes that we don't want to be pre-live.
372: // They don't exist in JDK1.1.
373: BloatBenchmark.USE1_1 = true;
374: CallGraph.USE1_2 = false;
375:
376: } else if (args[i].equals("-1.2")) {
377: CallGraph.USE1_2 = true;
378:
379: if (lookIn != null) {
380: lookIn += File.separator + "1.2";
381: }
382:
383: } else if (args[i].startsWith("-")) {
384: BloatBenchmark.err.println("** Unrecognized option: "
385: + args[i]);
386: BloatBenchmark.usage();
387:
388: } else if (i == args.length - 1) {
389: outputDirName = args[i];
390:
391: } else {
392: BloatBenchmark.CLASSES.add(args[i]);
393: }
394: }
395:
396: if (BloatBenchmark.CLASSES.isEmpty()) {
397: BloatBenchmark.err.println("** No classes specified");
398: BloatBenchmark.usage();
399: }
400:
401: if (outputDirName == null) {
402: BloatBenchmark.err
403: .println("** No output directory specified");
404: BloatBenchmark.usage();
405: }
406:
407: // Make sure the options the user entered make sense
408: if (BloatBenchmark.CHECK) {
409: BloatBenchmark.checkOptions();
410: }
411:
412: if (BloatBenchmark.USE1_1) {
413: // Don't generate stats for 1.1
414: BloatBenchmark.statsFile = null;
415: }
416:
417: if (lookIn != null) {
418: CLASSPATH = lookIn + File.pathSeparator + CLASSPATH;
419: }
420:
421: final StringBuffer sb = new StringBuffer();
422: for (int i = 0; i < args.length; i++) {
423: sb.append(args[i] + " ");
424: }
425: BloatBenchmark.tr("BLOATing with command line: " + sb);
426:
427: BloatContext context = null;
428:
429: float systemStart = 0.0F;
430: float systemDelta = 0.0F;
431: float systemEnd = 0.0F;
432: float systemTotal = 0.0F;
433:
434: float userStart = 0.0F;
435: float userDelta = 0.0F;
436: float userEnd = 0.0F;
437: float userTotal = 0.0F;
438:
439: PrintWriter times = null;
440:
441: if (BloatBenchmark.TIMES) {
442: try {
443: times = new PrintWriter(new FileWriter(
444: BloatBenchmark.timesFile), true);
445:
446: } catch (final IOException ex) {
447: times = new PrintWriter(System.out, true);
448: }
449: }
450:
451: if (BloatBenchmark.INTRA) {
452: BloatBenchmark.tr("Intraprocedural BLOAT");
453:
454: // First compute the roots of the call graph. Figure out which
455: // methods are live.
456: context = BloatBenchmark.makeContext(CLASSPATH, null);
457: final Collection liveMethods = BloatBenchmark.liveMethods(
458: BloatBenchmark.CLASSES, context);
459:
460: // Run intraprocedural BLOAT on the live methods.
461: BloatBenchmark.tr(liveMethods.size() + " live methods");
462: context = BloatBenchmark.makeContext(CLASSPATH,
463: outputDirName);
464: BloatBenchmark.intraBloat(liveMethods, context);
465:
466: } else {
467: BloatBenchmark.tr("Interprocedural BLOAT");
468:
469: if (BloatBenchmark.TIMES) {
470: Times.snapshot();
471: systemStart = Times.systemTime();
472: userStart = Times.userTime();
473: }
474:
475: // Do the interprocedural BLOATing
476: context = BloatBenchmark.makeContext(CLASSPATH,
477: outputDirName);
478: BloatBenchmark.liveMethods(BloatBenchmark.CLASSES, context);
479:
480: if (BloatBenchmark.TIMES) {
481: // Take a measurement
482: Times.snapshot();
483:
484: systemEnd = Times.systemTime();
485: userEnd = Times.userTime();
486:
487: systemDelta = systemEnd - systemStart;
488: userDelta = userEnd - userStart;
489:
490: systemStart = systemEnd;
491: userStart = userEnd;
492:
493: systemTotal += systemDelta;
494: userTotal += userDelta;
495:
496: times.println("Call graph construction");
497: times.println(" User: " + userDelta);
498: times.println(" System: " + systemDelta);
499: }
500:
501: if (BloatBenchmark.SPECIALIZE) {
502: BloatBenchmark.specialize(context);
503: }
504:
505: if (BloatBenchmark.TIMES) {
506: // Take a measurement
507: Times.snapshot();
508:
509: systemEnd = Times.systemTime();
510: userEnd = Times.userTime();
511:
512: systemDelta = systemEnd - systemStart;
513: userDelta = userEnd - userStart;
514:
515: systemStart = systemEnd;
516: userStart = userEnd;
517:
518: systemTotal += systemDelta;
519: userTotal += userDelta;
520:
521: times.println("Call site specialization");
522: times.println(" User: " + userDelta);
523: times.println(" System: " + systemDelta);
524: }
525:
526: if (BloatBenchmark.INLINE) {
527: BloatBenchmark.inline(context);
528: }
529:
530: if (BloatBenchmark.TIMES) {
531: // Take a measurement
532: Times.snapshot();
533:
534: systemEnd = Times.systemTime();
535: userEnd = Times.userTime();
536:
537: systemDelta = systemEnd - systemStart;
538: userDelta = userEnd - userStart;
539:
540: systemStart = systemEnd;
541: userStart = userEnd;
542:
543: systemTotal += systemDelta;
544: userTotal += userDelta;
545:
546: times.println("Method inlining");
547: times.println(" User: " + userDelta);
548: times.println(" System: " + systemDelta);
549: }
550:
551: if (BloatBenchmark.PEEPHOLE) {
552: BloatBenchmark.peephole(context);
553: }
554: }
555:
556: // Commit dirty data
557: BloatBenchmark.tr("Committing dirty methods");
558: context.commitDirty();
559:
560: if (BloatBenchmark.TIMES) {
561: // Take a measurement
562: Times.snapshot();
563:
564: systemEnd = Times.systemTime();
565: userEnd = Times.userTime();
566:
567: systemDelta = systemEnd - systemStart;
568: userDelta = userEnd - userStart;
569:
570: systemStart = systemEnd;
571: userStart = userEnd;
572:
573: systemTotal += systemDelta;
574: userTotal += userDelta;
575:
576: times.println("Committal");
577: times.println(" User: " + userDelta);
578: times.println(" System: " + systemDelta);
579: }
580:
581: if (BloatBenchmark.TIMES) {
582: times.println("Total");
583: times.println(" User: " + userTotal);
584: times.println(" System: " + systemTotal);
585: }
586:
587: if (BloatBenchmark.statsFile != null) {
588: final InlineStats stats = context.getInlineStats();
589: PrintWriter statsOut = null;
590: try {
591: statsOut = new PrintWriter(new FileWriter(
592: BloatBenchmark.statsFile), true);
593:
594: } catch (final IOException ex) {
595: statsOut = new PrintWriter(System.out, true);
596: }
597:
598: stats.printSummary(statsOut);
599: }
600:
601: BloatBenchmark.tr("Finished");
602: }
603:
604: /**
605: * Creates a <tt>BloatContext</tt> that loads classes from a given
606: * CLASSPATH.
607: */
608: static BloatContext makeContext(final String classpath,
609: final String outputDirName) {
610: final ClassFileLoader loader = new ClassFileLoader();
611: if (classpath != null) {
612: loader.prependClassPath(classpath);
613: }
614:
615: // if(TRACE) {
616: // loader.setVerbose(true);
617: // }
618:
619: BloatBenchmark.tr(" Creating a BloatContext for CLASSPATH: "
620: + loader.getClassPath());
621:
622: if (outputDirName != null) {
623: loader.setOutputDir(new File(outputDirName));
624: }
625: final BloatContext context = new CachingBloatContext(loader,
626: BloatBenchmark.CLASSES, true);
627:
628: // Always ignore the sun packages and the opj stuff for
629: // interprocedural stuff
630: if (!BloatBenchmark.SUN) {
631: context.addIgnorePackage("sun");
632: }
633:
634: context.addIgnorePackage("java.lang.ref");
635: context.addIgnorePackage("org.opj.system");
636:
637: if (BloatBenchmark.USE1_1) {
638: // Toba can't deal with java.lang.Character
639: context.addIgnoreClass(Type
640: .getType("Ljava/lang/Character;"));
641: }
642:
643: return (context);
644: }
645:
646: /**
647: * Returns the live methods of a program whose root methods are the
648: * <tt>main</tt> method of a set of classes.
649: *
650: * @param classes
651: * Names of classes containing root methods
652: * @param context
653: * Repository for accessing BLOAT stuff
654: * @return The <tt>MemberRef</tt>s of the live methods
655: */
656: private static Collection liveMethods(final Collection classes,
657: final BloatContext context) {
658:
659: // Determine the roots of the call graph
660: final Set roots = new HashSet();
661: Iterator iter = classes.iterator();
662: while (iter.hasNext()) {
663: final String className = (String) iter.next();
664: try {
665: final ClassEditor ce = context.editClass(className);
666: final MethodInfo[] methods = ce.methods();
667:
668: for (int i = 0; i < methods.length; i++) {
669: final MethodEditor me = context
670: .editMethod(methods[i]);
671:
672: if (!me.name().equals("main")) {
673: continue;
674: }
675:
676: BloatBenchmark.tr(" Root " + ce.name() + "."
677: + me.name() + me.type());
678: roots.add(me.memberRef());
679: }
680:
681: } catch (final ClassNotFoundException ex1) {
682: BloatBenchmark.err.println("** Could not find class: "
683: + ex1.getMessage());
684: System.exit(1);
685: }
686: }
687:
688: if (roots.isEmpty()) {
689: BloatBenchmark.err
690: .print("** No main method found in classes: ");
691: iter = classes.iterator();
692: while (iter.hasNext()) {
693: final String name = (String) iter.next();
694: BloatBenchmark.err.print(name);
695: if (iter.hasNext()) {
696: BloatBenchmark.err.print(", ");
697: }
698: }
699: BloatBenchmark.err.println("");
700: }
701:
702: context.setRootMethods(roots);
703: final CallGraph cg = context.getCallGraph();
704:
705: final Set liveMethods = new TreeSet(new MemberRefComparator());
706: liveMethods.addAll(cg.liveMethods());
707:
708: return (liveMethods);
709: }
710:
711: /**
712: * Specializes the live methods in a program.
713: */
714: private static void specialize(final BloatContext context) {
715:
716: final CallGraph cg = context.getCallGraph();
717:
718: final Set liveMethods = new TreeSet(new MemberRefComparator());
719: liveMethods.addAll(cg.liveMethods());
720:
721: // Specialize all possible methods
722: final InlineStats stats = context.getInlineStats();
723:
724: if (BloatBenchmark.statsFile != null) {
725: Specialize.STATS = true;
726: stats.setConfigName("BloatBenchmark");
727: }
728:
729: if (BloatBenchmark.MORPH != -1) {
730: Specialize.MAX_MORPH = BloatBenchmark.MORPH;
731: }
732: final Specialize spec = new Specialize(context);
733:
734: if (Specialize.STATS) {
735: stats.noteLiveMethods(liveMethods.size());
736: stats.noteLiveClasses(cg.liveClasses().size());
737: }
738:
739: BloatBenchmark.tr("Specializing live methods");
740: final Iterator iter = liveMethods.iterator();
741:
742: for (int count = 0; iter.hasNext(); count++) {
743: try {
744: final MethodEditor live = context
745: .editMethod((MemberRef) iter.next());
746:
747: if (context.ignoreMethod(live.memberRef())) {
748: // Don't display ignored methods, it's misleading.
749: continue;
750: }
751:
752: BloatBenchmark.tr(" " + count + ") "
753: + live.declaringClass().name() + "."
754: + live.name() + live.type());
755:
756: spec.specialize(live);
757:
758: } catch (final NoSuchMethodException ex2) {
759: BloatBenchmark.err.println("** Could not find method "
760: + ex2.getMessage());
761: System.exit(1);
762: }
763: }
764: }
765:
766: /**
767: * Inlines calls to static methods in the live methods of a given program.
768: */
769: private static void inline(final BloatContext context) {
770:
771: final Set liveMethods = new TreeSet(new MemberRefComparator());
772: final CallGraph cg = context.getCallGraph();
773: liveMethods.addAll(cg.liveMethods());
774:
775: BloatBenchmark.tr("Inlining " + liveMethods.size()
776: + " live methods");
777:
778: if (BloatBenchmark.CALLEE_SIZE != -1) {
779: Inline.CALLEE_SIZE = BloatBenchmark.CALLEE_SIZE;
780: }
781:
782: final Iterator iter = liveMethods.iterator();
783: for (int count = 0; BloatBenchmark.INLINE && iter.hasNext(); count++) {
784: try {
785: final MethodEditor live = context
786: .editMethod((MemberRef) iter.next());
787:
788: if (context.ignoreMethod(live.memberRef())) {
789: // Don't display ignored methods, it's misleading.
790: continue;
791: }
792:
793: BloatBenchmark.tr(" " + count + ") "
794: + live.declaringClass().name() + "."
795: + live.name() + live.type());
796:
797: final Inline inline = new Inline(context,
798: BloatBenchmark.SIZE);
799: inline.setMaxCallDepth(BloatBenchmark.DEPTH);
800: inline.inline(live);
801:
802: // Commit here in an attempt to conserve memory
803: context.commit(live.methodInfo());
804: context.release(live.methodInfo());
805:
806: } catch (final NoSuchMethodException ex3) {
807: BloatBenchmark.err.println("** Could not find method "
808: + ex3.getMessage());
809: System.exit(1);
810: }
811: }
812: }
813:
814: /**
815: * Performs peephole optimizations on a program's live methods.
816: */
817: private static void peephole(final BloatContext context) {
818:
819: final Set liveMethods = new TreeSet(new MemberRefComparator());
820: final CallGraph cg = context.getCallGraph();
821: liveMethods.addAll(cg.liveMethods());
822:
823: // Perform peephole optimizations. We do this separately because
824: // some peephole optimizations do things to the stack that
825: // inlining doesn't like. For instance, a peephole optimizations
826: // might make it so that a method has a non-empty stack upon
827: // return. Inlining will barf at the sight of this.
828: BloatBenchmark.tr("Performing peephole optimizations");
829:
830: final Iterator iter = liveMethods.iterator();
831: while (BloatBenchmark.PEEPHOLE && iter.hasNext()) {
832: try {
833: final MethodEditor live = context
834: .editMethod((MemberRef) iter.next());
835: Peephole.transform(live);
836: context.commit(live.methodInfo());
837: context.release(live.methodInfo());
838:
839: } catch (final NoSuchMethodException ex314) {
840: BloatBenchmark.err.println("** Could not find method "
841: + ex314.getMessage());
842: ex314.printStackTrace(System.err);
843: System.exit(1);
844: }
845: }
846: }
847:
848: /**
849: * Performs intraprocedural BLOAT on a program's live methods.
850: *
851: * @param liveMethods
852: * Should be alphabetized. This way we can commit a class once
853: * we've BLOATed all of its methods.
854: */
855: private static void intraBloat(final Collection liveMethods,
856: final BloatContext context) {
857:
858: ClassEditor prevClass = null;
859: final Iterator iter = liveMethods.iterator();
860: for (int count = 0; iter.hasNext(); count++) {
861: MethodEditor live = null;
862: ClassEditor ce = null; // Hack to make sure commit happens
863: try {
864: live = context.editMethod((MemberRef) iter.next());
865: ce = context.editClass(live.declaringClass()
866: .classInfo());
867:
868: } catch (final NoSuchMethodException ex3) {
869: BloatBenchmark.err.println("** Could not find method "
870: + ex3.getMessage());
871: System.exit(1);
872: }
873:
874: /* So we can skip classes or packages */
875: final String name = ce.type().className();
876: final String qual = ce.type().qualifier() + "/*";
877: boolean skip = false;
878: for (int i = 0; i < BloatBenchmark.SKIP.size(); i++) {
879: final String pkg = (String) BloatBenchmark.SKIP.get(i);
880:
881: if (name.equals(pkg) || qual.equals(pkg)) {
882: skip = true;
883: break;
884: }
885: }
886:
887: if (context.ignoreMethod(live.memberRef()) || skip) {
888: // Don't display ignored methods, it's misleading.
889: context.release(live.methodInfo());
890: continue;
891: }
892:
893: final Runtime runtime = Runtime.getRuntime();
894: runtime.gc();
895:
896: final Date start = new Date();
897: BloatBenchmark.tr(" " + count + ") "
898: + live.declaringClass().name() + "." + live.name()
899: + live.type());
900: BloatBenchmark.tr(" Start: " + start);
901:
902: try {
903: EDU.purdue.cs.bloat.optimize.Main.TRACE = BloatBenchmark.TRACE;
904: if (!BloatBenchmark.VERIFY) {
905: EDU.purdue.cs.bloat.optimize.Main.VERIFY = false;
906: }
907: EDU.purdue.cs.bloat.optimize.Main.bloatMethod(live,
908: context);
909:
910: } catch (final Exception oops) {
911: BloatBenchmark.err
912: .println("******************************************");
913: BloatBenchmark.err.println("Exception while BLOATing "
914: + live.declaringClass().name() + "."
915: + live.name() + live.type());
916: BloatBenchmark.err.println(oops.getMessage());
917: oops.printStackTrace(System.err);
918: BloatBenchmark.err
919: .println("******************************************");
920: }
921:
922: // Commit here in an attempt to conserve memory
923: context.commit(live.methodInfo());
924: context.release(live.methodInfo());
925:
926: if (prevClass == null) {
927: prevClass = ce;
928:
929: } else if (!prevClass.equals(ce)) {
930: // We've finished BLOATed the methods for prevClass, commit
931: // prevClass and move on
932: BloatBenchmark
933: .tr(prevClass.type() + " != " + ce.type());
934: context.commit(prevClass.classInfo());
935: context.release(prevClass.classInfo());
936: // context.commitDirty();
937: // tr(context.toString());
938: prevClass = ce;
939:
940: } else {
941: context.release(ce.classInfo());
942: }
943:
944: final Date end = new Date();
945: BloatBenchmark.tr(" Ellapsed time: "
946: + (end.getTime() - start.getTime()) + " ms");
947: }
948:
949: context.commitDirty();
950: }
951:
952: /**
953: * Checks to make sure that the chosen options make sense.
954: */
955: private static void checkOptions() {
956: if (!BloatBenchmark.INTRA && !BloatBenchmark.SPECIALIZE
957: && !BloatBenchmark.INLINE) {
958: BloatBenchmark.err.println("** There is nothing to do!");
959: BloatBenchmark.usage();
960:
961: } else if ((BloatBenchmark.MORPH != -1)
962: && !BloatBenchmark.SPECIALIZE) {
963: BloatBenchmark.err
964: .println("** Must specialize when setting morphosity");
965: BloatBenchmark.usage();
966: }
967: }
968:
969: private static class MemberRefComparator implements Comparator {
970: public int compare(final Object o1, final Object o2) {
971: Assert.isTrue(o1 instanceof MemberRef, o1
972: + " is not a MemberRef!");
973: Assert.isTrue(o2 instanceof MemberRef, o2
974: + " is not a MemberRef!");
975:
976: final MemberRef me1 = (MemberRef) o1;
977: final MemberRef me2 = (MemberRef) o2;
978:
979: final String s1 = me1.declaringClass() + "." + me1.name()
980: + me1.type();
981: final String s2 = me2.declaringClass() + "." + me2.name()
982: + me2.type();
983:
984: return (s1.compareTo(s2));
985: }
986:
987: public boolean equals(final Object other) {
988: return (true);
989: }
990: }
991: }
|