# HG changeset patch # User Andreas Woess # Date 1373894941 -7200 # Node ID f4f46b734a4c73f0bb95bcc06344cabe96b50929 # Parent 9f5a4074e36b282a98c16a1d5962f86f0da173dd# Parent 7f6580db1e889403398bea2188830af505647598 Merge diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Jul 15 15:29:01 2013 +0200 @@ -65,8 +65,7 @@ if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue(), TruffleInliningReprofileCount.getValue(), - TruffleInvalidationReprofileCount.getValue()); + return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue()); } @Override diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 15 15:29:01 2013 +0200 @@ -40,19 +40,19 @@ public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, FrameFactory { private static final PrintStream OUT = TTY.out().out(); + private static final int MIN_INVOKES_AFTER_INLINING = 2; - private final int inliningReprofileCount; - private final int invalidationReprofileCount; - - protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold, int inliningReprofileCount, int invalidationReprofileCount) { + protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold) { super(rootNode, descriptor); this.compiler = compiler; this.invokeCounter = compilationThreshold >> 7; this.loopAndInvokeCounter = compilationThreshold; this.originalInvokeCounter = compilationThreshold; this.rootNode.setCallTarget(this); - this.inliningReprofileCount = inliningReprofileCount; - this.invalidationReprofileCount = invalidationReprofileCount; + + if (TruffleProfiling.getValue()) { + registerCallTarget(this); + } } private InstalledCode compiledMethod; @@ -62,6 +62,11 @@ private int loopAndInvokeCounter; private boolean disableCompilation; + // TruffleProfiling + private int callCount; + private int inlinedCallSiteCount; + + // TraceTruffleCompilation long timeCompilationStarted; long timePartialEvaluationFinished; long timeCompilationFinished; @@ -71,6 +76,9 @@ @Override public Object call(PackedFrame caller, Arguments args) { + if (TruffleProfiling.getValue()) { + callCount++; + } if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) { try { return compiledMethod.execute(this, caller, args); @@ -82,8 +90,9 @@ } } - protected Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { compiledMethod = null; + int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); invokeCounter = invalidationReprofileCount; if (TruffleFunctionInlining.getValue()) { originalInvokeCounter += invalidationReprofileCount; @@ -101,7 +110,8 @@ return executeHelper(caller, args); } else { if (TruffleFunctionInlining.getValue() && inline()) { - invokeCounter = 2; + invokeCounter = MIN_INVOKES_AFTER_INLINING; + int inliningReprofileCount = TruffleInliningReprofileCount.getValue(); loopAndInvokeCounter = inliningReprofileCount; originalInvokeCounter = inliningReprofileCount; } else { @@ -112,10 +122,12 @@ } public boolean inline() { + CompilerAsserts.neverPartOfCompilation(); return new InliningHelper(this).inline(); } public void compile() { + CompilerAsserts.neverPartOfCompilation(); try { compiledMethod = compiler.compile(this); if (compiledMethod == null) { @@ -127,6 +139,9 @@ (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); } + if (TruffleProfiling.getValue()) { + resetProfiling(); + } } } catch (Throwable e) { disableCompilation = true; @@ -202,10 +217,14 @@ boolean inlined = false; for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { - if (policy.isWorthInlining(inlinableCallSite) && inlinableCallSite.getCallSite().inline(target)) { + if (!policy.isWorthInlining(inlinableCallSite)) { + break; + } + if (inlinableCallSite.getCallSite().inline(target)) { if (TraceTruffleInlining.getValue()) { printCallSiteInfo(policy, inlinableCallSite, "inlined"); } + target.inlinedCallSiteCount++; inlined = true; break; } @@ -267,7 +286,11 @@ @Override public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { - return Double.compare(metric(cs2), metric(cs1)); + int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); + if (result == 0) { + return Double.compare(metric(cs2), metric(cs1)); + } + return result; } }); } @@ -313,4 +336,65 @@ return inlinableCallSites; } } + + private static void resetProfiling() { + for (OptimizedCallTarget callTarget : OptimizedCallTarget.callTargets.keySet()) { + callTarget.callCount = 0; + } + } + + private static void printProfiling() { + List sortedCallTargets = new ArrayList<>(OptimizedCallTarget.callTargets.keySet()); + Collections.sort(sortedCallTargets, new Comparator() { + + @Override + public int compare(OptimizedCallTarget o1, OptimizedCallTarget o2) { + return o2.callCount - o1.callCount; + } + }); + + int totalCallCount = 0; + int totalInlinedCallSiteCount = 0; + int totalNotInlinedCallSiteCount = 0; + int totalNodeCount = 0; + + PrintStream out = TTY.out().out(); + out.println(); + out.printf("%-50s | %-10s | %s / %s | %s\n", "Call Target", "Call Count", "Calls Sites Inlined", "Not Inlined", "Node Count"); + for (OptimizedCallTarget callTarget : sortedCallTargets) { + if (callTarget.callCount == 0) { + continue; + } + + int notInlinedCallSiteCount = InliningHelper.getInlinableCallSites(callTarget).size(); + int nodeCount = NodeUtil.countNodes(callTarget.rootNode); + String comment = callTarget.compiledMethod == null ? " int" : ""; + out.printf("%-50s | %10s | %15s | %15s | %10s%s\n", callTarget.getRootNode(), callTarget.callCount, callTarget.inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, comment); + + totalCallCount += callTarget.callCount; + totalInlinedCallSiteCount += callTarget.inlinedCallSiteCount; + totalNotInlinedCallSiteCount += notInlinedCallSiteCount; + totalNodeCount += nodeCount; + } + out.printf("%-50s | %10s | %15s | %15s | %10s\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount); + } + + private static void registerCallTarget(OptimizedCallTarget callTarget) { + callTargets.put(callTarget, 0); + } + + private static Map callTargets; + static { + if (TruffleProfiling.getValue()) { + callTargets = new WeakHashMap<>(); + + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + printProfiling(); + } + }); + } + } } diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 15 15:29:01 2013 +0200 @@ -64,7 +64,7 @@ private final HotSpotGraalRuntime graalRuntime; private final TruffleCache truffleCache; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class, InvalidInstalledCodeException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 15 15:29:01 2013 +0200 @@ -81,5 +81,7 @@ public static final OptionValue TraceTruffleInlining = new OptionValue<>(true); @Option(help = "") public static final OptionValue TraceTruffleInliningDetails = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue TruffleProfiling = new StableOptionValue<>(false); // @formatter:on } diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Mon Jul 15 15:29:01 2013 +0200 @@ -81,7 +81,7 @@ class TestRootNode extends RootNode { - @Children private ValueNode[] children; + @Children private final ValueNode[] children; public TestRootNode(ValueNode[] children) { this.children = adoptChildren(children); diff -r 9f5a4074e36b -r f4f46b734a4c graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 13:36:59 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 15:29:01 2013 +0200 @@ -163,9 +163,11 @@ } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { kind = NodeFieldKind.CHILD; childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")"; } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { kind = NodeFieldKind.CHILDREN; childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")"; } else { kind = NodeFieldKind.DATA; } @@ -352,51 +354,52 @@ public static void replaceChild(Node parent, Node oldChild, Node newChild) { NodeClass nodeClass = NodeClass.get(parent.getClass()); - long[] fieldOffsets = nodeClass.childOffsets; - for (int i = 0; i < fieldOffsets.length; i++) { - long fieldOffset = fieldOffsets[i]; + for (long fieldOffset : nodeClass.getChildOffsets()) { if (unsafe.getObject(parent, fieldOffset) == oldChild) { - assert assertAssignable(nodeClass, parent, oldChild, newChild); + assert assertAssignable(nodeClass, fieldOffset, newChild); unsafe.putObject(parent, fieldOffset, newChild); } } - long[] childrenOffsets = nodeClass.childrenOffsets; - for (int i = 0; i < childrenOffsets.length; i++) { - long fieldOffset = childrenOffsets[i]; + for (long fieldOffset : nodeClass.getChildrenOffsets()) { Object arrayObject = unsafe.getObject(parent, fieldOffset); if (arrayObject != null) { - assert arrayObject instanceof Node[] : "Children must be instanceof Node[] "; + assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] "; Node[] array = (Node[]) arrayObject; - for (int j = 0; j < array.length; j++) { - if (array[j] == oldChild) { - assert newChild != null && array.getClass().getComponentType().isAssignableFrom(newChild.getClass()) : "Array type does not match"; - array[j] = newChild; - return; + for (int i = 0; i < array.length; i++) { + if (array[i] == oldChild) { + assert assertAssignable(nodeClass, fieldOffset, newChild); + array[i] = newChild; } } } } } - private static boolean assertAssignable(NodeClass clazz, Node parent, Object oldValue, Object newValue) { + private static boolean assertAssignable(NodeClass clazz, long fieldOffset, Object newValue) { if (newValue == null) { return true; } - for (NodeField field : clazz.fields) { - if (field.kind != NodeFieldKind.CHILD) { - continue; - } - if (unsafe.getObject(parent, field.offset) == oldValue) { - if (!field.type.isAssignableFrom(newValue.getClass())) { - assert false : "Child class " + newValue.getClass() + " is not assignable to field " + field.type.getName() + " at " + field.name + " in "; - return false; - } else { - break; + for (NodeField field : clazz.getFields()) { + if (field.getOffset() == fieldOffset) { + if (field.getKind() == NodeFieldKind.CHILD) { + if (field.getType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } + } else if (field.getKind() == NodeFieldKind.CHILDREN) { + if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } } } } - return true; + throw new IllegalArgumentException(); } /** Returns all declared fields in the class hierarchy. */