001/* 002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot; 024 025import static java.lang.Thread.*; 026 027import java.io.*; 028import java.lang.annotation.*; 029import java.lang.reflect.*; 030import java.util.*; 031import java.util.concurrent.*; 032 033import jdk.internal.jvmci.hotspot.*; 034 035import com.oracle.graal.debug.*; 036import com.sun.management.*; 037 038@SuppressWarnings("unused") 039public final class CompilationStatistics { 040 041 private static final long RESOLUTION = 100000000; 042 private static final boolean ENABLED = Boolean.getBoolean("jvmci.comp.stats"); 043 044 private static final CompilationStatistics DUMMY = new CompilationStatistics(null, false); 045 046 private static ConcurrentLinkedDeque<CompilationStatistics> list = new ConcurrentLinkedDeque<>(); 047 048 private static final ThreadLocal<Deque<CompilationStatistics>> current = new ThreadLocal<Deque<CompilationStatistics>>() { 049 050 @Override 051 protected Deque<CompilationStatistics> initialValue() { 052 return new ArrayDeque<>(); 053 } 054 }; 055 056 @Retention(RetentionPolicy.RUNTIME) 057 @Target(ElementType.FIELD) 058 private static @interface NotReported { 059 } 060 061 @Retention(RetentionPolicy.RUNTIME) 062 @Target(ElementType.FIELD) 063 private static @interface TimeValue { 064 } 065 066 private static long zeroTime = System.nanoTime(); 067 068 private static long getThreadAllocatedBytes() { 069 ThreadMXBean thread = (ThreadMXBean) Management.getThreadMXBean(); 070 return thread.getThreadAllocatedBytes(currentThread().getId()); 071 } 072 073 @NotReported private final long startTime; 074 @NotReported private long threadAllocatedBytesStart; 075 076 private int bytecodeCount; 077 private int codeSize; 078 @TimeValue private long duration; 079 private long memoryUsed; 080 private final boolean osr; 081 private final String holder; 082 private final String name; 083 private final String signature; 084 085 private CompilationStatistics(HotSpotResolvedJavaMethod method, boolean osr) { 086 this.osr = osr; 087 if (method != null) { 088 holder = method.getDeclaringClass().getName(); 089 name = method.getName(); 090 signature = method.getSignature().toMethodDescriptor(); 091 startTime = System.nanoTime(); 092 bytecodeCount = method.getCodeSize(); 093 threadAllocatedBytesStart = getThreadAllocatedBytes(); 094 } else { 095 holder = ""; 096 name = ""; 097 signature = ""; 098 startTime = 0; 099 } 100 } 101 102 public void finish(HotSpotResolvedJavaMethod method, HotSpotInstalledCode code) { 103 if (ENABLED) { 104 duration = System.nanoTime() - startTime; 105 codeSize = (int) code.getCodeSize(); 106 memoryUsed = getThreadAllocatedBytes() - threadAllocatedBytesStart; 107 if (current.get().getLast() != this) { 108 throw new RuntimeException("mismatch in finish()"); 109 } 110 current.get().removeLast(); 111 } 112 } 113 114 public static CompilationStatistics current() { 115 return current.get().isEmpty() ? null : current.get().getLast(); 116 } 117 118 public static CompilationStatistics create(HotSpotResolvedJavaMethod method, boolean isOSR) { 119 if (ENABLED) { 120 CompilationStatistics stats = new CompilationStatistics(method, isOSR); 121 list.add(stats); 122 current.get().addLast(stats); 123 return stats; 124 } else { 125 return DUMMY; 126 } 127 } 128 129 @SuppressWarnings("deprecation") 130 public static void clear(String dumpName) { 131 if (!ENABLED) { 132 return; 133 } 134 try { 135 ConcurrentLinkedDeque<CompilationStatistics> snapshot = list; 136 long snapshotZeroTime = zeroTime; 137 138 list = new ConcurrentLinkedDeque<>(); 139 zeroTime = System.nanoTime(); 140 141 Date now = new Date(); 142 String dateString = (now.getYear() + 1900) + "-" + (now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getHours() + "" + now.getMinutes(); 143 144 dumpCompilations(snapshot, dumpName, dateString); 145 146 try (FileOutputStream fos = new FileOutputStream("timeline_" + dateString + "_" + dumpName + ".csv", true); PrintStream out = new PrintStream(fos)) { 147 148 long[] timeSpent = new long[10000]; 149 int maxTick = 0; 150 for (CompilationStatistics stats : snapshot) { 151 long start = stats.startTime - snapshotZeroTime; 152 long duration = stats.duration; 153 if (start < 0) { 154 duration -= -start; 155 start = 0; 156 } 157 158 int tick = (int) (start / RESOLUTION); 159 long timeLeft = RESOLUTION - (start % RESOLUTION); 160 161 while (tick < timeSpent.length && duration > 0) { 162 if (tick > maxTick) { 163 maxTick = tick; 164 } 165 timeSpent[tick] += Math.min(timeLeft, duration); 166 duration -= timeLeft; 167 tick++; 168 timeLeft = RESOLUTION; 169 } 170 } 171 String timelineName = System.getProperty("stats.timeline.name"); 172 if (timelineName != null && !timelineName.isEmpty()) { 173 out.print(timelineName + "\t"); 174 } 175 for (int i = 0; i <= maxTick; i++) { 176 out.print((timeSpent[i] * 100 / RESOLUTION) + "\t"); 177 } 178 out.println(); 179 } 180 } catch (Exception e) { 181 throw new RuntimeException(e); 182 } 183 } 184 185 protected static void dumpCompilations(ConcurrentLinkedDeque<CompilationStatistics> snapshot, String dumpName, String dateString) throws IllegalAccessException, FileNotFoundException { 186 String fileName = "compilations_" + dateString + "_" + dumpName + ".csv"; 187 try (PrintStream out = new PrintStream(fileName)) { 188 // output the list of all compilations 189 190 Field[] declaredFields = CompilationStatistics.class.getDeclaredFields(); 191 ArrayList<Field> fields = new ArrayList<>(); 192 for (Field field : declaredFields) { 193 if (!Modifier.isStatic(field.getModifiers()) && !field.isAnnotationPresent(NotReported.class)) { 194 fields.add(field); 195 } 196 } 197 for (Field field : fields) { 198 out.print(field.getName() + "\t"); 199 } 200 out.println(); 201 for (CompilationStatistics stats : snapshot) { 202 for (Field field : fields) { 203 if (field.isAnnotationPresent(TimeValue.class)) { 204 double value = field.getLong(stats) / 1000000d; 205 out.print(String.format(Locale.ENGLISH, "%.3f", value) + "\t"); 206 } else { 207 out.print(field.get(stats) + "\t"); 208 } 209 } 210 out.println(); 211 } 212 } 213 } 214}