/* * Copyright (c) 2011, 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.sun.max.vm.code; import java.io.*; import java.util.*; import com.sun.cri.ci.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.profile.*; /** * Utility for printing code cache metrics. */ public final class CodeCacheMetricsPrinter { final boolean verbose; public CodeCacheMetricsPrinter(boolean verbose) { this.verbose = verbose; } static class Metrics { int n; int invocations; int bc; int mc; } void add(TreeMap<String, CodeCacheMetricsPrinter.Metrics> metrics, String key, int bc, int mc, int invocations) { CodeCacheMetricsPrinter.Metrics m = metrics.get(key); if (m == null) { m = new Metrics(); metrics.put(key, m); } m.n++; m.invocations += invocations; m.bc += bc; m.mc += mc; } static class Table { final int cols; final ArrayList<Object> cells = new ArrayList<Object>(); public Table(Object... headerCols) { this.cols = headerCols.length; addRow(headerCols); } void addRow(Object... cols) { assert cols.length <= this.cols; int i = 0; while (i < cols.length) { cells.add(cols[i++]); } while (i++ < this.cols) { cells.add(" "); } } } public void printTo(PrintStream out) { final CodeManager codeManager = Code.getCodeManager(); printRegionTo(codeManager.getRuntimeBaselineCodeRegion(), out); printRegionTo(codeManager.getRuntimeOptCodeRegion(), out); } void printRegionTo(CodeRegion cr, PrintStream out) { final String regionName = cr.regionName(); final char[] stars = new char[regionName.length() + 22]; Arrays.fill(stars, '*'); final String line = new String(stars); out.println(line); out.println("********** " + regionName + " **********"); out.println(line); if (verbose) { out.println("Bytecode\tMachineCode\tInvocations\tCodeType\tMethod"); } TreeMap<String, CodeCacheMetricsPrinter.Metrics> metrics = new TreeMap<String, CodeCacheMetricsPrinter.Metrics>(); TreeMap<String, CodeCacheMetricsPrinter.Metrics> metrics2 = new TreeMap<String, CodeCacheMetricsPrinter.Metrics>(); for (TargetMethod targetMethod : cr.copyOfTargetMethods()) { ClassMethodActor methodActor = targetMethod.classMethodActor(); int bcSize = methodActor == null ? 0 : methodActor.codeSize(); int mcSize = targetMethod.codeLength(); MethodProfile profile = targetMethod.profile(); int invocations = 0; if (profile != null) { invocations = MethodInstrumentation.initialEntryCount - profile.entryCount; } String type = targetMethod.getClass().getSimpleName(); add(metrics, type, bcSize, mcSize, invocations); if (invocations > 0 && invocations < 10) { add(metrics2, type + "#" + invocations, bcSize, mcSize, invocations); } else if (invocations >= 10) { add(metrics2, type + "#10+", bcSize, mcSize, invocations); } if (verbose) { out.println(String.format("%d\t%d\t%d\t%s\t%s", bcSize, mcSize, invocations, type, targetMethod)); } } CodeCacheMetricsPrinter.Metrics t = new Metrics(); for (Map.Entry<String, CodeCacheMetricsPrinter.Metrics> e1 : metrics.entrySet()) { CodeCacheMetricsPrinter.Metrics m = e1.getValue(); t.n += m.n; t.invocations += m.invocations; t.bc += m.bc; t.mc += m.mc; } out.println(); out.println("========== Metrics per code type =========="); CodeCacheMetricsPrinter.Table table = new Table("CodeType", "Count", "Bytecode", "MachineCode", "Invocations", "BytecodeToMachineCode"); table.addRow("------"); for (Map.Entry<String, CodeCacheMetricsPrinter.Metrics> e1 : metrics.entrySet()) { CodeCacheMetricsPrinter.Metrics m = e1.getValue(); table.addRow(e1.getKey(), pct(m.n, t.n), pct(m.bc, t.bc), pct(m.mc, t.mc), m.invocations, x(m.bc, m.mc)); } table.addRow("------"); table.addRow("Totals", t.n, t.bc, t.mc); out.println(CiUtil.tabulate(table.cells.toArray(), table.cols, 1, 1)); out.println(); out.println("========== Metrics per code type and invocation count =========="); table = new Table("CodeType#Invocations", "Count", "Bytecode", "MachineCode"); table.addRow("------"); for (Map.Entry<String, CodeCacheMetricsPrinter.Metrics> e : metrics2.entrySet()) { CodeCacheMetricsPrinter.Metrics m = e.getValue(); table.addRow(e.getKey(), pct(m.n, t.n), pct(m.bc, t.bc), pct(m.mc, t.mc)); } out.println(CiUtil.tabulate(table.cells.toArray(), table.cols, 1, 1)); } private static String pct(int a, int b) { return a + "(" + ((a * 100) / b) + "%)"; } private static String x(int a, int b) { if (a == 0 || b == 0) { return ""; } return String.format("%.2fx", (float) b / a); } }