1 /* 2 * Copyright (c) 2016, 2019, 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 */ 23 24 25 package org.graalvm.compiler.hotspot.test; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.net.URI; 30 import java.net.URL; 31 import java.net.URLClassLoader; 32 import java.nio.file.FileSystem; 33 import java.nio.file.FileSystems; 34 import java.nio.file.FileVisitResult; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.nio.file.SimpleFileVisitor; 38 import java.nio.file.attribute.BasicFileAttributes; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Set; 45 import java.util.regex.Pattern; 46 import java.util.regex.PatternSyntaxException; 47 import java.util.stream.Collectors; 48 49 import org.graalvm.compiler.debug.CSVUtil; 50 import org.graalvm.compiler.debug.GraalError; 51 import org.graalvm.compiler.graph.Node; 52 import org.graalvm.compiler.graph.NodeClass; 53 import org.graalvm.compiler.graph.spi.Canonicalizable; 54 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 55 import org.graalvm.compiler.nodes.spi.Virtualizable; 56 57 public class NodeCostDumpUtil { 58 59 private static final String prefix1 = "com.oracle."; 60 private static final String prefix2 = "org.graalvm."; 61 private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s"); 62 63 private static String getArgumentRegex(String arg) { 64 if (arg.length() == 0) { 65 return null; 66 } 67 try { 68 Pattern.compile(arg); 69 return arg; 70 } catch (PatternSyntaxException e) { 71 // silently ignore 72 System.err.println("Invalid regex given, defaulting to \".*\" regex.."); 73 return null; 74 } 75 } 76 77 public static void main(String[] args) { 78 if (args.length != 1) { 79 System.err.println("NodeCostDumpUtil expects exactly one argument, the node name regex to match against."); 80 System.exit(-1); 81 } 82 final String pattern = getArgumentRegex(args[0]); 83 String version = System.getProperty("java.specification.version"); 84 if (version.compareTo("1.9") >= 0) { 85 System.err.printf("NodeCostDumpUtil does not support JDK versions greater than 1.8, current version is %s.\n", version); 86 System.exit(-1); 87 } 88 String[] jvmciCP = System.getProperty("jvmci.class.path.append").split(File.pathSeparator); 89 String[] primarySuiteCP = System.getProperty("primary.suite.cp").split(File.pathSeparator); 90 ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader(); 91 HashSet<Class<?>> classes = new HashSet<>(); 92 try { 93 Set<String> uniquePaths = new HashSet<>(Arrays.asList(primarySuiteCP)); 94 uniquePaths.addAll(Arrays.asList(jvmciCP)); 95 for (String path : uniquePaths) { 96 if (new File(path).exists()) { 97 if (path.endsWith(".jar")) { 98 try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + path), Collections.emptyMap())) { 99 initAllClasses(jarFileSystem.getPath("/"), applicationClassLoader, classes); 100 } 101 } else { 102 initAllClasses(FileSystems.getDefault().getPath(path), applicationClassLoader, classes); 103 } 104 } 105 } 106 } catch (IOException ex) { 107 GraalError.shouldNotReachHere(); 108 } 109 System.err.printf("Loaded %d classes...\n", classes.size()); 110 List<Class<?>> nodeClasses = new ArrayList<>(); 111 for (Class<?> loaded : classes) { 112 if (Node.class.isAssignableFrom(loaded) && !loaded.isArray()) { 113 nodeClasses.add(loaded); 114 } 115 } 116 System.err.printf("Loaded %s node classes...\n", nodeClasses.size()); 117 List<NodeClass<?>> nc = new ArrayList<>(); 118 for (Class<?> c : nodeClasses) { 119 try { 120 nc.add(NodeClass.get(c)); 121 } catch (Throwable t) { 122 // Silently ignore problems here 123 } 124 } 125 System.err.printf("Read TYPE field from %s node classes...\n", nc.size()); 126 nc = nc.stream().filter(x -> x != null).collect(Collectors.toList()); 127 nc.sort((x, y) -> { 128 String a = x.getJavaClass().getName(); 129 String b = y.getJavaClass().getName(); 130 return a.compareTo(b); 131 }); 132 CSVUtil.Escape.println(System.out, FMT, "NodeName", "Size", "Overrides Size Method", "Cycles", "Overrides Cycles Method", "Canonicalizable", "MemoryCheckPoint", "Virtualizable"); 133 for (NodeClass<?> nodeclass : nc) { 134 String packageStrippedName = null; 135 try { 136 packageStrippedName = nodeclass.getJavaClass().getCanonicalName().replace(prefix1, "").replace(prefix2, ""); 137 } catch (Throwable t) { 138 // do nothing 139 continue; 140 } 141 if (pattern != null && !packageStrippedName.matches(pattern)) { 142 continue; 143 } 144 boolean overridesSizeMethod = false; 145 boolean overridesCyclesMethod = false; 146 Class<?> c = nodeclass.getJavaClass(); 147 try { 148 c.getDeclaredMethod("estimatedNodeSize"); 149 overridesSizeMethod = true; 150 } catch (Throwable t) { 151 // do nothing 152 } 153 try { 154 c.getDeclaredMethod("estimatedNodeCycles"); 155 overridesCyclesMethod = true; 156 } catch (Throwable t) { 157 // do nothing 158 } 159 CSVUtil.Escape.println(System.out, FMT, packageStrippedName, nodeclass.size(), overridesSizeMethod, nodeclass.cycles(), overridesCyclesMethod, canonicalizable(c), memoryCheckPoint(c), 160 virtualizable(c)); 161 } 162 } 163 164 private static boolean canonicalizable(Class<?> c) { 165 return Canonicalizable.class.isAssignableFrom(c); 166 } 167 168 private static boolean virtualizable(Class<?> c) { 169 return Virtualizable.class.isAssignableFrom(c); 170 } 171 172 private static boolean memoryCheckPoint(Class<?> c) { 173 return MemoryCheckpoint.class.isAssignableFrom(c); 174 } 175 176 private static void initAllClasses(final Path root, ClassLoader classLoader, HashSet<Class<?>> classes) { 177 try { 178 Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 179 @Override 180 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 181 String className = root.relativize(file).toString(); 182 ClassLoader c = classLoader; 183 if (className.endsWith(".class")) { 184 String prefix = prefixed(className); 185 if (prefix != null) { 186 String stripped = stripClassName(className); 187 c = new URLClassLoader(new URL[]{new File(constructURLPart(stripped, className, prefix)).toURI().toURL()}, classLoader); 188 className = constructClazzPart(stripped, prefix); 189 } else { 190 String clazzPart = className.replace('/', '.'); 191 className = clazzPart.substring(0, clazzPart.length() - ".class".length()); 192 } 193 try { 194 Class<?> systemClass = Class.forName(className, false, c); 195 if (systemClass.getEnclosingClass() != null) { 196 try { 197 classes.add(systemClass.getEnclosingClass()); 198 } catch (Throwable t) { 199 // do nothing 200 } 201 } 202 classes.add(systemClass); 203 } catch (Throwable ignored) { 204 } 205 } 206 return FileVisitResult.CONTINUE; 207 } 208 }); 209 } catch (IOException ex) { 210 GraalError.shouldNotReachHere(); 211 } 212 } 213 214 private static String prefixed(String className) { 215 if (className.contains(prefix1) && className.indexOf(prefix1) > 0) { 216 return prefix1; 217 } else if (className.contains(prefix2) && className.indexOf(prefix2) > 0) { 218 return prefix2; 219 } 220 return null; 221 } 222 223 private static String stripClassName(String className) { 224 return className.replace('/', '.'); 225 } 226 227 private static String constructClazzPart(String stripped, String prefix) { 228 String clazzPart = stripped.substring(stripped.lastIndexOf(prefix), stripped.length()); 229 return clazzPart.substring(0, clazzPart.length() - ".class".length()); 230 } 231 232 private static String constructURLPart(String stripped, String className, String prefix) { 233 return className.substring(0, stripped.lastIndexOf(prefix)); 234 } 235 236 } 237