1/* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.graalvm.compiler.hotspot; 24 25import java.io.File; 26import java.io.IOException; 27import java.lang.reflect.Field; 28import java.net.URI; 29import java.net.URL; 30import java.net.URLClassLoader; 31import java.nio.file.FileSystem; 32import java.nio.file.FileSystems; 33import java.nio.file.FileVisitResult; 34import java.nio.file.Files; 35import java.nio.file.Path; 36import java.nio.file.SimpleFileVisitor; 37import java.nio.file.attribute.BasicFileAttributes; 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.Collections; 41import java.util.HashSet; 42import java.util.List; 43import java.util.Set; 44import java.util.regex.Pattern; 45import java.util.regex.PatternSyntaxException; 46import java.util.stream.Collectors; 47 48import org.graalvm.compiler.debug.CSVUtil; 49import org.graalvm.compiler.debug.GraalError; 50import org.graalvm.compiler.graph.Node; 51import org.graalvm.compiler.graph.NodeClass; 52import org.graalvm.compiler.graph.spi.Canonicalizable; 53import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 54import org.graalvm.compiler.nodes.spi.Virtualizable; 55 56public class NodeCostDumpUtil { 57 58 private static final String prefix1 = "com.oracle."; 59 private static final String prefix2 = "org.graalvm."; 60 private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s"); 61 62 private static String getArgumentRegex(String arg) { 63 if (arg.length() == 0) { 64 return null; 65 } 66 try { 67 Pattern.compile(arg); 68 return arg; 69 } catch (PatternSyntaxException e) { 70 // silently ignore 71 System.err.println("Invalid regex given, defaulting to \".*\" regex.."); 72 return null; 73 } 74 } 75 76 public static void main(String[] args) { 77 if (args.length != 1) { 78 System.err.println("NodeCostDumpUtil expects exactly one argument, the node name regex to match against."); 79 System.exit(-1); 80 } 81 final String pattern = getArgumentRegex(args[0]); 82 String version = System.getProperty("java.specification.version"); 83 if (version.compareTo("1.9") >= 0) { 84 System.err.printf("NodeCostDumpUtil does not support JDK versions greater than 1.8, current version is %s.\n", version); 85 System.exit(-1); 86 } 87 String[] jvmciCP = System.getProperty("jvmci.class.path.append").split(File.pathSeparator); 88 String[] primarySuiteCP = System.getProperty("primary.suite.cp").split(File.pathSeparator); 89 ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader(); 90 HashSet<Class<?>> classes = new HashSet<>(); 91 try { 92 Set<String> uniquePaths = new HashSet<>(Arrays.asList(primarySuiteCP)); 93 uniquePaths.addAll(Arrays.asList(jvmciCP)); 94 for (String path : uniquePaths) { 95 if (new File(path).exists()) { 96 if (path.endsWith(".jar")) { 97 try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + path), Collections.emptyMap())) { 98 initAllClasses(jarFileSystem.getPath("/"), applicationClassLoader, classes); 99 } 100 } else { 101 initAllClasses(FileSystems.getDefault().getPath(path), applicationClassLoader, classes); 102 } 103 } 104 } 105 } catch (IOException ex) { 106 GraalError.shouldNotReachHere(); 107 } 108 System.err.printf("Loaded %d classes...\n", classes.size()); 109 List<Class<?>> nodeClasses = new ArrayList<>(); 110 for (Class<?> loaded : classes) { 111 if (Node.class.isAssignableFrom(loaded) && !loaded.isArray()) { 112 nodeClasses.add(loaded); 113 } 114 } 115 System.err.printf("Loaded %s node classes...\n", nodeClasses.size()); 116 List<NodeClass<?>> nc = new ArrayList<>(); 117 for (Class<?> nodeClass : nodeClasses) { 118 Field f; 119 try { 120 f = nodeClass.getField("TYPE"); 121 f.setAccessible(true); 122 Object val = f.get(null); 123 NodeClass<?> nodeType = (NodeClass<?>) val; 124 nc.add(nodeType); 125 } catch (Throwable t) { 126 // Silently ignore problems here 127 } 128 } 129 System.err.printf("Read TYPE field from %s node classes...\n", nc.size()); 130 nc = nc.stream().filter(x -> x != null).collect(Collectors.toList()); 131 nc.sort((x, y) -> { 132 String a = x.getJavaClass().getName(); 133 String b = y.getJavaClass().getName(); 134 return a.compareTo(b); 135 }); 136 CSVUtil.Escape.println(System.out, FMT, "NodeName", "Size", "Overrides Size Method", "Cycles", "Overrides Cycles Method", "Canonicalizable", "MemoryCheckPoint", "Virtualizable"); 137 for (NodeClass<?> nodeclass : nc) { 138 String packageStrippedName = null; 139 try { 140 packageStrippedName = nodeclass.getJavaClass().getCanonicalName().replace(prefix1, "").replace(prefix2, ""); 141 } catch (Throwable t) { 142 // do nothing 143 continue; 144 } 145 if (pattern != null && !packageStrippedName.matches(pattern)) { 146 continue; 147 } 148 boolean overridesSizeMethod = false; 149 boolean overridesCyclesMethod = false; 150 Class<?> c = nodeclass.getJavaClass(); 151 try { 152 c.getDeclaredMethod("estimatedNodeSize"); 153 overridesSizeMethod = true; 154 } catch (Throwable t) { 155 // do nothing 156 } 157 try { 158 c.getDeclaredMethod("estimatedNodeCycles"); 159 overridesCyclesMethod = true; 160 } catch (Throwable t) { 161 // do nothing 162 } 163 CSVUtil.Escape.println(System.out, FMT, packageStrippedName, nodeclass.size(), overridesSizeMethod, nodeclass.cycles(), overridesCyclesMethod, canonicalizable(c), memoryCheckPoint(c), 164 virtualizable(c)); 165 } 166 } 167 168 private static boolean canonicalizable(Class<?> c) { 169 return Canonicalizable.class.isAssignableFrom(c); 170 } 171 172 private static boolean virtualizable(Class<?> c) { 173 return Virtualizable.class.isAssignableFrom(c); 174 } 175 176 private static boolean memoryCheckPoint(Class<?> c) { 177 return MemoryCheckpoint.class.isAssignableFrom(c); 178 } 179 180 private static void initAllClasses(final Path root, ClassLoader classLoader, HashSet<Class<?>> classes) { 181 try { 182 Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 183 @Override 184 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 185 String className = root.relativize(file).toString(); 186 ClassLoader c = classLoader; 187 if (className.endsWith(".class")) { 188 String prefix = prefixed(className); 189 if (prefix != null) { 190 String stripped = stripClassName(className); 191 c = new URLClassLoader(new URL[]{new File(constructURLPart(stripped, className, prefix)).toURI().toURL()}, classLoader); 192 className = constructClazzPart(stripped, prefix); 193 } else { 194 String clazzPart = className.replace('/', '.'); 195 className = clazzPart.substring(0, clazzPart.length() - ".class".length()); 196 } 197 try { 198 Class<?> systemClass = Class.forName(className, false, c); 199 if (systemClass.getEnclosingClass() != null) { 200 try { 201 classes.add(systemClass.getEnclosingClass()); 202 } catch (Throwable t) { 203 // do nothing 204 } 205 } 206 classes.add(systemClass); 207 } catch (Throwable ignored) { 208 } 209 } 210 return FileVisitResult.CONTINUE; 211 } 212 }); 213 } catch (IOException ex) { 214 GraalError.shouldNotReachHere(); 215 } 216 } 217 218 private static String prefixed(String className) { 219 if (className.contains(prefix1) && className.indexOf(prefix1) > 0) { 220 return prefix1; 221 } else if (className.contains(prefix2) && className.indexOf(prefix2) > 0) { 222 return prefix2; 223 } 224 return null; 225 } 226 227 private static String stripClassName(String className) { 228 return className.replace('/', '.'); 229 } 230 231 private static String constructClazzPart(String stripped, String prefix) { 232 String clazzPart = stripped.substring(stripped.lastIndexOf(prefix), stripped.length()); 233 return clazzPart.substring(0, clazzPart.length() - ".class".length()); 234 } 235 236 private static String constructURLPart(String stripped, String className, String prefix) { 237 return className.substring(0, stripped.lastIndexOf(prefix)); 238 } 239 240} 241