1 /* 2 * Copyright (c) 2012, 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 package org.graalvm.compiler.debug; 24 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * A node in a tree of values. 34 */ 35 public class DebugValueMap { 36 37 /** 38 * The top level maps for all threads. 39 */ 40 private static final List<DebugValueMap> topLevelMaps = new ArrayList<>(); 41 42 private long[] values; 43 private List<DebugValueMap> children; 44 private String name; 45 46 public DebugValueMap(String name) { 47 this.name = name; 48 } 49 50 public void setCurrentValue(int index, long l) { 51 ensureSize(index); 52 values[index] = l; 53 } 54 55 public long getCurrentValue(int index) { 56 ensureSize(index); 57 return values[index]; 58 } 59 60 public void clearChildren() { 61 if (children != null) { 62 children.clear(); 63 } 64 } 65 66 public void reset() { 67 if (values != null) { 68 Arrays.fill(values, 0L); 69 } 70 if (children != null) { 71 for (DebugValueMap child : children) { 72 child.reset(); 73 } 74 } 75 } 76 77 private void ensureSize(int index) { 78 if (values == null) { 79 values = new long[index + 1]; 80 } 81 if (values.length <= index) { 82 values = Arrays.copyOf(values, index + 1); 83 } 84 } 85 86 private int capacity() { 87 return (values == null) ? 0 : values.length; 88 } 89 90 public void addChild(DebugValueMap map) { 91 if (children == null) { 92 children = new ArrayList<>(4); 93 } 94 children.add(map); 95 } 96 97 public List<DebugValueMap> getChildren() { 98 if (children == null) { 99 return Collections.emptyList(); 100 } else { 101 return Collections.unmodifiableList(children); 102 } 103 } 104 105 public boolean hasChildren() { 106 return children != null && !children.isEmpty(); 107 } 108 109 public String getName() { 110 return this.name; 111 } 112 113 @Override 114 public String toString() { 115 return "DebugValueMap<" + getName() + ">"; 116 } 117 118 public static synchronized void registerTopLevel(DebugValueMap map) { 119 topLevelMaps.add(map); 120 } 121 122 public static synchronized List<DebugValueMap> getTopLevelMaps() { 123 return topLevelMaps; 124 } 125 126 /** 127 * The top level map for the current thread. 128 */ 129 private static final ThreadLocal<DebugValueMap> topLevelMap = new ThreadLocal<>(); 130 131 static DebugValueMap getTopLevelMap() { 132 DebugValueMap map = topLevelMap.get(); 133 if (map == null) { 134 map = new DebugValueMap(Thread.currentThread().getName()); 135 topLevelMap.set(map); 136 registerTopLevel(map); 137 } 138 return map; 139 } 140 141 public void normalize() { 142 if (hasChildren()) { 143 Map<String, DebugValueMap> occurred = new HashMap<>(); 144 for (DebugValueMap map : children) { 145 String mapName = map.getName(); 146 if (!occurred.containsKey(mapName)) { 147 occurred.put(mapName, map); 148 map.normalize(); 149 } else { 150 occurred.get(mapName).mergeWith(map); 151 occurred.get(mapName).normalize(); 152 } 153 } 154 155 if (occurred.values().size() < children.size()) { 156 // At least one duplicate was found. 157 children.clear(); 158 for (DebugValueMap map : occurred.values()) { 159 addChild(map); 160 map.normalize(); 161 } 162 } 163 } 164 } 165 166 private void mergeWith(DebugValueMap map) { 167 if (map.hasChildren()) { 168 if (hasChildren()) { 169 children.addAll(map.children); 170 } else { 171 children = map.children; 172 } 173 map.children = null; 174 } 175 176 int size = Math.max(this.capacity(), map.capacity()); 177 ensureSize(size); 178 for (int i = 0; i < size; ++i) { 179 long curValue = getCurrentValue(i); 180 long otherValue = map.getCurrentValue(i); 181 setCurrentValue(i, curValue + otherValue); 182 } 183 } 184 185 public void group() { 186 if (this.hasChildren()) { 187 List<DebugValueMap> oldChildren = new ArrayList<>(this.children); 188 this.children.clear(); 189 for (DebugValueMap map : oldChildren) { 190 mergeWith(map); 191 } 192 } 193 } 194 }