Mercurial > hg > graal-compiler
view graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java @ 10643:8060a20be76b
Fix visitor in OptimizedCallTarget class.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sun, 07 Jul 2013 21:00:29 +0200 |
parents | 175a4900c230 |
children | d71c56c67921 |
line wrap: on
line source
/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.graal.truffle; import static com.oracle.graal.truffle.TruffleCompilerOptions.*; import java.io.*; import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, FrameFactory { private static final PrintStream OUT = TTY.out().out(); private final int inliningReprofileCount; private final int invalidationReprofileCount; protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold, int inliningReprofileCount, int invalidationReprofileCount) { 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; } private InstalledCode compiledMethod; private final TruffleCompiler compiler; private int invokeCounter; private int originalInvokeCounter; private int loopAndInvokeCounter; private boolean disableCompilation; long timeCompilationStarted; long timePartialEvaluationFinished; long timeCompilationFinished; int codeSize; int nodeCountPartialEval; int nodeCountLowered; @Override public Object call(PackedFrame caller, Arguments args) { for (;;) { if (compiledMethod != null) { try { return compiledMethod.execute(this, caller, args); } catch (InvalidInstalledCodeException ex) { compiledMethod = null; invokeCounter = invalidationReprofileCount; if (TruffleFunctionInlining.getValue()) { originalInvokeCounter += invalidationReprofileCount; } if (TraceTruffleCompilation.getValue()) { OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6); } } } else { invokeCounter--; loopAndInvokeCounter--; if (disableCompilation || loopAndInvokeCounter > 0 || invokeCounter > 0) { return executeHelper(caller, args); } else { if (TruffleFunctionInlining.getValue()) { if (inline()) { invokeCounter = 2; loopAndInvokeCounter = inliningReprofileCount; originalInvokeCounter = inliningReprofileCount; continue; } } compile(); } } } } public boolean inline() { return new InliningHelper(this).inline(); } public void compile() { try { compiledMethod = compiler.compile(this); if (compiledMethod == null) { throw new BailoutException(String.format("code installation failed (codeSize=%s)", codeSize)); } else { if (TraceTruffleCompilation.getValue()) { int nodeCountTruffle = new InliningHelper.CallTargetProfile(rootNode).nodeCount; OUT.printf("[truffle] optimized %-50s |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", rootNode, nodeCountTruffle, (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); } } } catch (Throwable e) { disableCompilation = true; if (TraceTruffleCompilation.getValue()) { if (e instanceof BailoutException) { OUT.printf("[truffle] opt bailout %-48s %s\n", rootNode, e.getMessage()); } else { OUT.printf("[truffle] opt failed %-49s %s\n", rootNode, e.toString()); if (TraceTruffleCompilationExceptions.getValue()) { e.printStackTrace(OUT); } if (TruffleCompilationExceptionsAreFatal.getValue()) { System.exit(-1); } } } } } public Object executeHelper(PackedFrame caller, Arguments args) { VirtualFrame frame = createFrame(frameDescriptor, caller, args); return rootNode.execute(frame); } private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return new FrameWithoutBoxing(descriptor, caller, args); } @Override public VirtualFrame create(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return createFrame(descriptor, caller, args); } @Override public String toString() { return "CallTarget " + rootNode; } @Override public void reportLoopCount(int count) { loopAndInvokeCounter -= count; } private static class InliningHelper { private static final int MAX_SIZE = 300; private static final int MAX_INLINE_SIZE = 62; private final OptimizedCallTarget target; public InliningHelper(OptimizedCallTarget target) { this.target = target; } public boolean inline() { CallTargetProfile profile = new CallTargetProfile(target.getRootNode()); if (profile.inlinableCallSites.isEmpty()) { return false; } if (profile.nodeCount > MAX_SIZE) { return false; } double max = 0.0D; ProfiledInlinableCallSite inliningDecision = null; for (Node callNode : profile.inlinableCallSites) { InlinableCallSite callSite = (InlinableCallSite) callNode; Node inlineTree = callSite.getInlineTree(); if (inlineTree == null) { continue; } CallTargetProfile inlineProfile = new CallTargetProfile(inlineTree); if (inlineProfile.nodeCount > MAX_INLINE_SIZE || inlineProfile.nodeCount + profile.nodeCount > MAX_SIZE) { continue; } ProfiledInlinableCallSite inlinable = new ProfiledInlinableCallSite(inlineProfile, callSite); double metric = (inlinable.callCount / inlineProfile.nodeCount) + ((double) inlinable.callCount / (double) target.originalInvokeCounter); if (metric >= max) { inliningDecision = inlinable; max = metric; } } for (Node callSite : profile.inlinableCallSites) { ((InlinableCallSite) callSite).resetCallCount(); } if (inliningDecision != null) { if (inliningDecision.callSite.inline(target)) { if (TraceTruffleCompilation.getValue()) { String calls = String.format("%4s/%4s", inliningDecision.callCount, target.originalInvokeCounter); String nodes = String.format("%3s/%3s", inliningDecision.profile.nodeCount, profile.nodeCount); OUT.printf("[truffle] inlined %-50s |Nodes %6s |Calls %6s |into %s\n", inliningDecision.callSite, nodes, calls, target.getRootNode()); } return true; } } return false; } private static class ProfiledInlinableCallSite { final CallTargetProfile profile; final InlinableCallSite callSite; final int callCount; public ProfiledInlinableCallSite(CallTargetProfile profile, InlinableCallSite callSite) { this.profile = profile; this.callSite = callSite; this.callCount = callSite.getCallCount(); } } private static class CallTargetProfile { final Node root; final int nodeCount; final List<Node> inlinableCallSites = new ArrayList<>(); public CallTargetProfile(Node rootNode) { root = rootNode; VisitorImpl impl = new VisitorImpl(); root.accept(impl); this.nodeCount = impl.visitedCount; } private class VisitorImpl implements NodeVisitor { int visitedCount; @Override public boolean visit(Node node) { if (node instanceof RootNode && visitedCount > 0) { return false; } if (node instanceof InlinableCallSite) { inlinableCallSites.add(node); } visitedCount++; return true; } } } } }