--- /dev/null 2016-05-31 09:42:47.975716356 -0700
+++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValuesPrinter.java 2016-12-09 00:48:18.441188862 -0800
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014, 2015, 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 org.graalvm.compiler.debug.internal;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueFile;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueHumanReadable;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueThreadFilter;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.SuppressZeroDebugValues;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.LogStream;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+
+/**
+ * Facility for printing the {@linkplain KeyRegistry#getDebugValues() values} collected across all
+ * {@link DebugValueMap#getTopLevelMaps() threads}.
+ */
+public class DebugValuesPrinter {
+ private static final String COMPUTER_READABLE_FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s");
+ private static final char SCOPE_DELIMITER = '.';
+ private final MethodMetricsPrinter mmPrinter;
+
+ public DebugValuesPrinter() {
+ this(null);
+ }
+
+ public DebugValuesPrinter(MethodMetricsPrinter mmPrinter) {
+ this.mmPrinter = mmPrinter;
+ }
+
+ public void printDebugValues() throws GraalError {
+ TTY.println();
+ TTY.println("");
+ List topLevelMaps = DebugValueMap.getTopLevelMaps();
+ List debugValues = KeyRegistry.getDebugValues();
+ if (debugValues.size() > 0) {
+ try {
+ ArrayList sortedValues = new ArrayList<>(debugValues);
+ Collections.sort(sortedValues);
+
+ String summary = DebugValueSummary.getValue();
+ if (summary == null) {
+ summary = "Complete";
+ }
+ if (DebugValueThreadFilter.getValue() != null && topLevelMaps.size() != 0) {
+ topLevelMaps = topLevelMaps.stream().filter(map -> Pattern.compile(DebugValueThreadFilter.getValue()).matcher(map.getName()).find()).collect(Collectors.toList());
+ if (topLevelMaps.size() == 0) {
+ TTY.println("Warning: DebugValueThreadFilter=%s eliminated all maps so nothing will be printed", DebugValueThreadFilter.getValue());
+ }
+ }
+ switch (summary) {
+ case "Name": {
+ LogStream log = getLogStream();
+ printSummary(log, topLevelMaps, sortedValues);
+ break;
+ }
+ case "Partial": {
+ DebugValueMap globalMap = new DebugValueMap("Global");
+ for (DebugValueMap map : topLevelMaps) {
+ flattenChildren(map, globalMap);
+ }
+ globalMap.normalize();
+ LogStream log = getLogStream();
+ printMap(log, new DebugValueScope(null, globalMap), sortedValues);
+ break;
+ }
+ case "Complete": {
+ DebugValueMap globalMap = new DebugValueMap("Global");
+ for (DebugValueMap map : topLevelMaps) {
+ globalMap.addChild(map);
+ }
+ globalMap.group();
+ globalMap.normalize();
+ LogStream log = getLogStream();
+ printMap(log, new DebugValueScope(null, globalMap), sortedValues);
+ break;
+ }
+ case "Thread":
+ for (DebugValueMap map : topLevelMaps) {
+ TTY.println("Showing the results for thread: " + map.getName());
+ map.group();
+ map.normalize();
+ LogStream log = getLogStream(map.getName().replace(' ', '_'));
+ printMap(log, new DebugValueScope(null, map), sortedValues);
+ }
+ break;
+ default:
+ throw new GraalError("Unknown summary type: %s", summary);
+ }
+ for (DebugValueMap topLevelMap : topLevelMaps) {
+ topLevelMap.reset();
+ }
+ } catch (Throwable e) {
+ // Don't want this to change the exit status of the VM
+ PrintStream err = System.err;
+ err.println("Error while printing debug values:");
+ e.printStackTrace();
+ }
+ }
+ if (mmPrinter != null) {
+ mmPrinter.printMethodMetrics(MethodMetricsImpl.collectedMetrics());
+ }
+ TTY.println("");
+ }
+
+ private static LogStream getLogStream() {
+ return getLogStream(null);
+ }
+
+ private static LogStream getLogStream(String prefix) {
+ String debugValueFile = DebugValueFile.getValue();
+ if (debugValueFile != null) {
+ try {
+ final String fileName;
+ if (prefix != null) {
+ fileName = prefix + '-' + debugValueFile;
+ } else {
+ fileName = debugValueFile;
+ }
+ LogStream logStream = new LogStream(new FileOutputStream(fileName));
+ TTY.println("Writing debug values to '%s'", fileName);
+ return logStream;
+ } catch (FileNotFoundException e) {
+ TTY.println("Warning: Could not open debug value log file: %s (defaulting to TTY)", e.getMessage());
+ }
+ }
+ return TTY.out();
+ }
+
+ private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
+ globalMap.addChild(map);
+ for (DebugValueMap child : map.getChildren()) {
+ flattenChildren(child, globalMap);
+ }
+ map.clearChildren();
+ }
+
+ private void printSummary(LogStream log, List topLevelMaps, List debugValues) {
+ DebugValueMap result = new DebugValueMap("Summary");
+ for (int i = debugValues.size() - 1; i >= 0; i--) {
+ DebugValue debugValue = debugValues.get(i);
+ int index = debugValue.getIndex();
+ long total = collectTotal(topLevelMaps, index);
+ result.setCurrentValue(index, total);
+ }
+ printMap(log, new DebugValueScope(null, result), debugValues);
+ }
+
+ private long collectTotal(List maps, int index) {
+ long total = 0;
+ for (int i = 0; i < maps.size(); i++) {
+ DebugValueMap map = maps.get(i);
+ total += map.getCurrentValue(index);
+ total += collectTotal(map.getChildren(), index);
+ }
+ return total;
+ }
+
+ /**
+ * Tracks the scope when printing a {@link DebugValueMap}, allowing "empty" scopes to be
+ * omitted. An empty scope is one in which there are no (nested) non-zero debug values.
+ */
+ static class DebugValueScope {
+
+ final DebugValueScope parent;
+ final int level;
+ final DebugValueMap map;
+ private boolean printed;
+
+ DebugValueScope(DebugValueScope parent, DebugValueMap map) {
+ this.parent = parent;
+ this.map = map;
+ this.level = parent == null ? 0 : parent.level + 1;
+ }
+
+ public void print(LogStream log) {
+ if (!printed) {
+ printed = true;
+ if (parent != null) {
+ parent.print(log);
+ }
+ printIndent(log, level);
+ log.printf("%s%n", map.getName());
+ }
+ }
+
+ public String toRawString() {
+ return toRaw(new StringBuilder()).toString();
+ }
+
+ private StringBuilder toRaw(StringBuilder stringBuilder) {
+ final StringBuilder sb = (parent == null) ? stringBuilder : parent.toRaw(stringBuilder).append(SCOPE_DELIMITER);
+ return sb.append(map.getName());
+ }
+
+ }
+
+ private void printMap(LogStream log, DebugValueScope scope, List debugValues) {
+ if (DebugValueHumanReadable.getValue()) {
+ printMapHumanReadable(log, scope, debugValues);
+ } else {
+ printMapComputerReadable(log, scope, debugValues);
+ }
+ }
+
+ private void printMapComputerReadable(LogStream log, DebugValueScope scope, List debugValues) {
+
+ for (DebugValue value : debugValues) {
+ long l = scope.map.getCurrentValue(value.getIndex());
+ if (l != 0 || !SuppressZeroDebugValues.getValue()) {
+ CSVUtil.Escape.println(log, COMPUTER_READABLE_FMT, scope.toRawString(), value.getName(), value.toRawString(l), value.rawUnit());
+ }
+ }
+
+ List children = scope.map.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ DebugValueMap child = children.get(i);
+ printMapComputerReadable(log, new DebugValueScope(scope, child), debugValues);
+ }
+ }
+
+ private void printMapHumanReadable(LogStream log, DebugValueScope scope, List debugValues) {
+
+ for (DebugValue value : debugValues) {
+ long l = scope.map.getCurrentValue(value.getIndex());
+ if (l != 0 || !SuppressZeroDebugValues.getValue()) {
+ scope.print(log);
+ printIndent(log, scope.level + 1);
+ log.println(value.getName() + "=" + value.toString(l));
+ }
+ }
+
+ List children = scope.map.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ DebugValueMap child = children.get(i);
+ printMapHumanReadable(log, new DebugValueScope(scope, child), debugValues);
+ }
+ }
+
+ private static void printIndent(LogStream log, int level) {
+ for (int i = 0; i < level; ++i) {
+ log.print(" ");
+ }
+ log.print("|-> ");
+ }
+
+ public void clearDebugValues() {
+ List topLevelMaps = DebugValueMap.getTopLevelMaps();
+ List debugValues = KeyRegistry.getDebugValues();
+ if (debugValues.size() > 0) {
+ for (DebugValueMap map : topLevelMaps) {
+ map.reset();
+ }
+ }
+ if (mmPrinter != null) {
+ MethodMetricsImpl.clearMM();
+ }
+ }
+}