Mercurial > hg > truffle
changeset 5308:820fce52a244
moved GraphCache to platform specific part, solved class unloading problem
(see comments in HotSpotGraphCache.java)
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Thu, 26 Apr 2012 14:18:17 +0200 |
parents | 2558ff0945f8 |
children | 19ed2e2391a0 |
files | graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/GraphCache.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/Compiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotGraphCache.java |
diffstat | 6 files changed, 175 insertions(+), 182 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/GraphCache.java Wed Apr 25 14:57:40 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2012, 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.compiler.graph; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.cri.*; -import com.oracle.graal.nodes.*; -import com.oracle.max.cri.ri.*; - -public class GraphCache implements RiGraphCache { - - private static final PrintStream out = System.out; - private final boolean dump; - private boolean enabled = true; - - private final AtomicLong hitCounter = new AtomicLong(); - private final AtomicLong missCounter = new AtomicLong(); - private final AtomicLong removeHitCounter = new AtomicLong(); - private final AtomicLong removeMissCounter = new AtomicLong(); - private final AtomicLong putCounter = new AtomicLong(); - - private class LRUCache extends LinkedHashMap<RiResolvedMethod, Long> { - private static final long serialVersionUID = -3973307040793397840L; - - public LRUCache(int initialCapacity) { - super(initialCapacity * 2, 0.75f, false); - } - @Override - protected boolean removeEldestEntry(Entry<RiResolvedMethod, Long> eldest) { - if (size() > GraalOptions.GraphCacheSize) { - graphs.remove(eldest.getValue()); - cachedGraphIds.remove(eldest.getKey()); - return true; - } else { - return false; - } - } - - } - - private final Map<RiResolvedMethod, Long> currentGraphIds = Collections.synchronizedMap(new LRUCache(GraalOptions.GraphCacheSize)); - - private final ConcurrentHashMap<Long, StructuredGraph> graphs = new ConcurrentHashMap<>(); - private final ConcurrentHashMap<Long, RiResolvedMethod> cachedGraphIds = new ConcurrentHashMap<>(); - - - public GraphCache(boolean dump) { - this.dump = dump; - - if (dump) { - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - out.println("put: " + putCounter.get()); - out.println("get hit: " + hitCounter.get()); - out.println("get miss: " + missCounter.get()); - out.println("remove hit: " + removeHitCounter.get()); - out.println("remove miss: " + removeMissCounter.get()); - } - }); - } - } - - public void enable() { - enabled = true; - } - - @Override - public StructuredGraph get(RiResolvedMethod method) { - if (!enabled) { - return null; - } - Long currentId = currentGraphIds.get(method); - StructuredGraph result = null; - if (currentId != null) { - result = graphs.get(currentId); - } - - if (dump) { - if (result == null) { - missCounter.incrementAndGet(); - } else { - hitCounter.incrementAndGet(); - } -// if (result == null) { -// out.println("miss: " + missCounter.incrementAndGet() + " " + method); -// } else { -// out.println("hit: " + hitCounter.incrementAndGet() + " " + method); -// } - } - return result; - } - - @Override - public void put(StructuredGraph graph) { - if (!enabled) { - return; - } - assert graph.method() != null; - Long currentId = currentGraphIds.get(graph.method()); - if (currentId != null) { - graphs.remove(currentId); - cachedGraphIds.remove(currentId); - } - currentGraphIds.put(graph.method(), graph.graphId()); - cachedGraphIds.put(graph.graphId(), graph.method()); - graphs.put(graph.graphId(), graph); - - if (dump) { - putCounter.incrementAndGet(); -// out.println("put: " + putCounter.incrementAndGet() + " (size: " + graphs.size() + ")"); - } - } - - public void clear() { - graphs.clear(); - currentGraphIds.clear(); - cachedGraphIds.clear(); - hitCounter.set(0); - missCounter.set(0); - removeHitCounter.set(0); - removeMissCounter.set(0); - putCounter.set(0); - } - - public void removeGraphs(long[] deoptedGraphs) { - for (long graphId : deoptedGraphs) { - graphs.remove(graphId); - RiResolvedMethod method = cachedGraphIds.get(graphId); - if (method != null) { - cachedGraphIds.remove(graphId); - currentGraphIds.remove(method); - } - if (dump) { - if (method != null) { - removeHitCounter.incrementAndGet(); - } else { - removeMissCounter.incrementAndGet(); - } -// if (method != null) { -// out.println("remove hit: " + removeHitCounter.incrementAndGet() + " (" + graphId + " " + method + ")"); -// } else { -// out.println("remove miss: " + removeMissCounter.incrementAndGet() + " (" + graphId + ")"); -// } - } - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Apr 25 14:57:40 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Apr 26 14:18:17 2012 +0200 @@ -26,7 +26,6 @@ import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.ri.*; import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/Compiler.java Wed Apr 25 14:57:40 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/Compiler.java Thu Apr 26 14:18:17 2012 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.graph.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.ri.*; import com.oracle.max.cri.ci.*; @@ -38,7 +37,7 @@ HotSpotVMConfig getConfig(); HotSpotRuntime getRuntime(); CiTarget getTarget(); - GraphCache getCache(); + HotSpotGraphCache getCache(); void evictDeoptedGraphs(); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Wed Apr 25 14:57:40 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Thu Apr 26 14:18:17 2012 +0200 @@ -27,7 +27,6 @@ import java.net.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.graph.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.cri.*; import com.oracle.graal.hotspot.bridge.*; @@ -93,7 +92,7 @@ private HotSpotRuntime runtime; private GraalCompiler compiler; private CiTarget target; - private volatile GraphCache cache; + private volatile HotSpotGraphCache cache; private final HotSpotVMConfig config; @@ -180,14 +179,14 @@ compiler = new GraalCompiler(getRuntime(), getTarget(), backend, generator); if (GraalOptions.CacheGraphs) { - cache = new GraphCache(GraalOptions.PrintGraphCache); + cache = new HotSpotGraphCache(); } } return compiler; } @Override - public GraphCache getCache() { + public HotSpotGraphCache getCache() { return cache; }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Apr 25 14:57:40 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Apr 26 14:18:17 2012 +0200 @@ -208,7 +208,6 @@ TTY.println(" in %d ms", System.currentTimeMillis() - startTime); if (compiler.getCache() != null) { compiler.getCache().clear(); - compiler.getCache().enable(); } System.gc(); CiCompilationStatistics.clear("bootstrap2");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotGraphCache.java Thu Apr 26 14:18:17 2012 +0200 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2012, 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.hotspot.ri; + +import java.io.*; +import java.lang.ref.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ri.*; + +/** + * This class implements the graph caching system for the HotSpot platform. + * + * This implementation does not use a map to store the actual cached graphs. The problem is that such maps keep the + * graph, and therefore the RiResolvedMethod referenced from the graph, alive. For some applications and benchmarks this + * is a problem, e.g., the DaCapoScala "scalatest" benchmark will quickly run out of perm gen because of this. + * + * This cannot be solved with a WeakHashMap<RiResolvedMethod, Graph>, since the values within the map will keep the keys + * alive. In order for this to work we would require a weak map in which the "strongness" of the value references + * depends upon the reachability of the keys. + * + * Therefore the graph cache is implemented in such a way that it stores its cache entries within the RiResolvedMethod. + * It uses the {@link RiResolvedMethod#compilerStorage()} map with the HotSpotGraphCache instance as key. + * The cached graph will be kept alive as long as the RiResolvedMethod is alive, but does not prevent the method, and + * therefore the class, from being unloaded. + * + * The {@link #cachedGraphIds} map is used to find the graphs that should be removed because of deoptimization, and to + * enforce the graph cache size restriction. + */ +public class HotSpotGraphCache implements RiGraphCache { + + private static final PrintStream out = System.out; + + private volatile long hitCounter; + private volatile long missCounter; + private volatile long removeHitCounter; + private volatile long removeCounter; + private volatile long putCounter; + + /** + * An ordered hash map for looking up the methods corresponding to a specific graph id. It enforces the maximum + * graph cache size by removing the oldest (in insertion-order) element if the cache gets too big. + */ + private final class LRUCache extends LinkedHashMap<Long, WeakReference<RiResolvedMethod>> { + + private static final long serialVersionUID = -3973307040793397840L; + + public LRUCache() { + super(GraalOptions.GraphCacheSize * 2, 0.75f, false); + } + + @Override + protected boolean removeEldestEntry(Entry<Long, WeakReference<RiResolvedMethod>> eldest) { + if (size() > GraalOptions.GraphCacheSize) { + RiResolvedMethod method = eldest.getValue().get(); + if (method != null) { + StructuredGraph cachedGraph = (StructuredGraph) method.compilerStorage().get(HotSpotGraphCache.this); + if (cachedGraph != null && cachedGraph.graphId() == eldest.getKey()) { + method.compilerStorage().remove(HotSpotGraphCache.this); + } + } + return true; + } else { + return false; + } + } + } + + private final Map<Long, WeakReference<RiResolvedMethod>> cachedGraphIds = Collections.synchronizedMap(new LRUCache()); + + public HotSpotGraphCache() { + if (GraalOptions.PrintGraphCache) { + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + out.println("put: " + putCounter); + out.println("get hit: " + hitCounter); + out.println("get miss: " + missCounter); + out.println("remove hit: " + removeHitCounter); + out.println("remove miss: " + (removeCounter - removeHitCounter)); + } + }); + } + } + + @Override + public StructuredGraph get(RiResolvedMethod method) { + StructuredGraph result = (StructuredGraph) method.compilerStorage().get(this); + + if (GraalOptions.PrintGraphCache) { + if (result == null) { + missCounter++; + } else { + hitCounter++; + } + } + return result; + } + + @Override + public void put(StructuredGraph graph) { + assert graph.method() != null; + cachedGraphIds.put(graph.graphId(), new WeakReference<>(graph.method())); + graph.method().compilerStorage().put(this, graph); + + if (GraalOptions.PrintGraphCache) { + putCounter++; + } + } + + public void clear() { + synchronized (cachedGraphIds) { + for (WeakReference<RiResolvedMethod> ref : cachedGraphIds.values()) { + RiResolvedMethod method = ref.get(); + if (method != null) { + method.compilerStorage().remove(this); + } + } + cachedGraphIds.clear(); + hitCounter = 0; + missCounter = 0; + removeHitCounter = 0; + removeCounter = 0; + putCounter = 0; + } + } + + public void removeGraphs(long[] deoptedGraphs) { + for (long graphId : deoptedGraphs) { + WeakReference<RiResolvedMethod> ref = cachedGraphIds.get(graphId); + RiResolvedMethod method = ref == null ? null : ref.get(); + if (method != null) { + StructuredGraph cachedGraph = (StructuredGraph) method.compilerStorage().get(this); + if (cachedGraph != null && cachedGraph.graphId() == graphId) { + method.compilerStorage().remove(this); + if (GraalOptions.PrintGraphCache) { + removeHitCounter++; + } + } + } + if (GraalOptions.PrintGraphCache) { + removeCounter++; + } + } + } +}