001/* 002 * Copyright (c) 2014, 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 com.oracle.graal.debug.GraalDebugConfig.*; 026 027import java.io.*; 028import java.util.*; 029import java.util.regex.*; 030import java.util.stream.*; 031 032import jdk.internal.jvmci.common.*; 033 034import com.oracle.graal.debug.*; 035import com.oracle.graal.debug.internal.*; 036 037/** 038 * Facility for printing the {@linkplain KeyRegistry#getDebugValues() values} collected across all 039 * {@link DebugValueMap#getTopLevelMaps() threads}. 040 */ 041public class DebugValuesPrinter { 042 043 public void printDebugValues() throws JVMCIError { 044 TTY.println(); 045 TTY.println("<DebugValues>"); 046 List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps(); 047 List<DebugValue> debugValues = KeyRegistry.getDebugValues(); 048 if (debugValues.size() > 0) { 049 try { 050 ArrayList<DebugValue> sortedValues = new ArrayList<>(debugValues); 051 Collections.sort(sortedValues); 052 053 String summary = DebugValueSummary.getValue(); 054 if (summary == null) { 055 summary = "Complete"; 056 } 057 if (DebugValueThreadFilter.getValue() != null && topLevelMaps.size() != 0) { 058 topLevelMaps = topLevelMaps.stream().filter(map -> Pattern.compile(DebugValueThreadFilter.getValue()).matcher(map.getName()).find()).collect(Collectors.toList()); 059 if (topLevelMaps.size() == 0) { 060 TTY.println("Warning: DebugValueThreadFilter=%s eliminated all maps so nothing will be printed", DebugValueThreadFilter.getValue()); 061 } 062 } 063 switch (summary) { 064 case "Name": 065 printSummary(topLevelMaps, sortedValues); 066 break; 067 case "Partial": { 068 DebugValueMap globalMap = new DebugValueMap("Global"); 069 for (DebugValueMap map : topLevelMaps) { 070 flattenChildren(map, globalMap); 071 } 072 globalMap.normalize(); 073 printMap(new DebugValueScope(null, globalMap), sortedValues); 074 break; 075 } 076 case "Complete": { 077 DebugValueMap globalMap = new DebugValueMap("Global"); 078 for (DebugValueMap map : topLevelMaps) { 079 globalMap.addChild(map); 080 } 081 globalMap.group(); 082 globalMap.normalize(); 083 printMap(new DebugValueScope(null, globalMap), sortedValues); 084 break; 085 } 086 case "Thread": 087 for (DebugValueMap map : topLevelMaps) { 088 TTY.println("Showing the results for thread: " + map.getName()); 089 map.group(); 090 map.normalize(); 091 printMap(new DebugValueScope(null, map), sortedValues); 092 } 093 break; 094 default: 095 throw new JVMCIError("Unknown summary type: %s", summary); 096 } 097 for (DebugValueMap topLevelMap : topLevelMaps) { 098 topLevelMap.reset(); 099 } 100 } catch (Throwable e) { 101 // Don't want this to change the exit status of the VM 102 PrintStream err = System.err; 103 err.println("Error while printing debug values:"); 104 e.printStackTrace(); 105 } 106 } 107 TTY.println("</DebugValues>"); 108 } 109 110 private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) { 111 globalMap.addChild(map); 112 for (DebugValueMap child : map.getChildren()) { 113 flattenChildren(child, globalMap); 114 } 115 map.clearChildren(); 116 } 117 118 private void printSummary(List<DebugValueMap> topLevelMaps, List<DebugValue> debugValues) { 119 DebugValueMap result = new DebugValueMap("Summary"); 120 for (int i = debugValues.size() - 1; i >= 0; i--) { 121 DebugValue debugValue = debugValues.get(i); 122 int index = debugValue.getIndex(); 123 long total = collectTotal(topLevelMaps, index); 124 result.setCurrentValue(index, total); 125 } 126 printMap(new DebugValueScope(null, result), debugValues); 127 } 128 129 private long collectTotal(List<DebugValueMap> maps, int index) { 130 long total = 0; 131 for (int i = 0; i < maps.size(); i++) { 132 DebugValueMap map = maps.get(i); 133 total += map.getCurrentValue(index); 134 total += collectTotal(map.getChildren(), index); 135 } 136 return total; 137 } 138 139 /** 140 * Tracks the scope when printing a {@link DebugValueMap}, allowing "empty" scopes to be 141 * omitted. An empty scope is one in which there are no (nested) non-zero debug values. 142 */ 143 static class DebugValueScope { 144 145 final DebugValueScope parent; 146 final int level; 147 final DebugValueMap map; 148 private boolean printed; 149 150 public DebugValueScope(DebugValueScope parent, DebugValueMap map) { 151 this.parent = parent; 152 this.map = map; 153 this.level = parent == null ? 0 : parent.level + 1; 154 } 155 156 public void print() { 157 if (!printed) { 158 printed = true; 159 if (parent != null) { 160 parent.print(); 161 } 162 printIndent(level); 163 TTY.println("%s", map.getName()); 164 } 165 } 166 } 167 168 private void printMap(DebugValueScope scope, List<DebugValue> debugValues) { 169 170 for (DebugValue value : debugValues) { 171 long l = scope.map.getCurrentValue(value.getIndex()); 172 if (l != 0 || !SuppressZeroDebugValues.getValue()) { 173 scope.print(); 174 printIndent(scope.level + 1); 175 TTY.println(value.getName() + "=" + value.toString(l)); 176 } 177 } 178 179 for (DebugValueMap child : scope.map.getChildren()) { 180 printMap(new DebugValueScope(scope, child), debugValues); 181 } 182 } 183 184 private static void printIndent(int level) { 185 for (int i = 0; i < level; ++i) { 186 TTY.print(" "); 187 } 188 TTY.print("|-> "); 189 } 190}