766
|
1 |
/*
|
1623
|
2 |
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
|
766
|
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. Sun designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Sun in the LICENSE file that accompanied this code.
|
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
|
21 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
23 |
* have any questions.
|
|
24 |
*/
|
|
25 |
package com.sun.hotspot.igv.difference;
|
|
26 |
|
|
27 |
import com.sun.hotspot.igv.data.Group;
|
|
28 |
import com.sun.hotspot.igv.data.InputEdge;
|
|
29 |
import com.sun.hotspot.igv.data.InputGraph;
|
|
30 |
import com.sun.hotspot.igv.data.InputNode;
|
|
31 |
import com.sun.hotspot.igv.data.Property;
|
1497
|
32 |
import java.util.Collection;
|
766
|
33 |
import java.util.HashMap;
|
|
34 |
import java.util.HashSet;
|
|
35 |
import java.util.Map;
|
|
36 |
import java.util.Set;
|
|
37 |
|
|
38 |
/**
|
|
39 |
*
|
|
40 |
* @author Thomas Wuerthinger
|
|
41 |
*/
|
|
42 |
public class Difference {
|
|
43 |
|
|
44 |
public static final String PROPERTY_STATE = "state";
|
|
45 |
public static final String VALUE_NEW = "new";
|
|
46 |
public static final String VALUE_CHANGED = "changed";
|
|
47 |
public static final String VALUE_SAME = "same";
|
|
48 |
public static final String VALUE_DELETED = "deleted";
|
|
49 |
public static final String OLD_PREFIX = "OLD_";
|
|
50 |
public static final String MAIN_PROPERTY = "name";
|
|
51 |
public static final double LIMIT = 100.0;
|
|
52 |
public static final String[] IGNORE_PROPERTIES = new String[]{"idx", "debug_idx"};
|
|
53 |
|
|
54 |
public static InputGraph createDiffGraph(InputGraph a, InputGraph b) {
|
|
55 |
if (a.getGroup() == b.getGroup()) {
|
|
56 |
return createDiffSameGroup(a, b);
|
|
57 |
} else {
|
|
58 |
return createDiff(a, b);
|
|
59 |
}
|
|
60 |
}
|
|
61 |
|
|
62 |
private static InputGraph createDiffSameGroup(InputGraph a, InputGraph b) {
|
|
63 |
Map<Integer, InputNode> keyMapB = new HashMap<Integer, InputNode>();
|
|
64 |
for (InputNode n : b.getNodes()) {
|
|
65 |
Integer key = n.getId();
|
|
66 |
assert !keyMapB.containsKey(key);
|
|
67 |
keyMapB.put(key, n);
|
|
68 |
}
|
|
69 |
|
|
70 |
Set<Pair> pairs = new HashSet<Pair>();
|
|
71 |
|
|
72 |
for (InputNode n : a.getNodes()) {
|
|
73 |
Integer key = n.getId();
|
|
74 |
|
|
75 |
|
|
76 |
if (keyMapB.containsKey(key)) {
|
|
77 |
InputNode nB = keyMapB.get(key);
|
|
78 |
pairs.add(new Pair(n, nB));
|
|
79 |
}
|
|
80 |
}
|
|
81 |
|
|
82 |
return createDiff(a, b, pairs);
|
|
83 |
}
|
|
84 |
|
|
85 |
private static InputGraph createDiff(InputGraph a, InputGraph b, Set<Pair> pairs) {
|
|
86 |
Group g = new Group();
|
|
87 |
g.setMethod(a.getGroup().getMethod());
|
|
88 |
g.setAssembly(a.getGroup().getAssembly());
|
|
89 |
g.getProperties().setProperty("name", "Difference");
|
|
90 |
InputGraph graph = new InputGraph(g, null);
|
|
91 |
graph.setName(a.getName() + ", " + b.getName());
|
|
92 |
graph.setIsDifferenceGraph(true);
|
|
93 |
|
|
94 |
Set<InputNode> nodesA = new HashSet<InputNode>(a.getNodes());
|
|
95 |
Set<InputNode> nodesB = new HashSet<InputNode>(b.getNodes());
|
|
96 |
|
|
97 |
Map<InputNode, InputNode> inputNodeMap = new HashMap<InputNode, InputNode>();
|
|
98 |
for (Pair p : pairs) {
|
|
99 |
InputNode n = p.getN1();
|
|
100 |
assert nodesA.contains(n);
|
|
101 |
InputNode nB = p.getN2();
|
|
102 |
assert nodesB.contains(nB);
|
|
103 |
|
|
104 |
nodesA.remove(n);
|
|
105 |
nodesB.remove(nB);
|
|
106 |
InputNode n2 = new InputNode(n);
|
|
107 |
inputNodeMap.put(n, n2);
|
|
108 |
inputNodeMap.put(nB, n2);
|
|
109 |
graph.addNode(n2);
|
|
110 |
markAsChanged(n2, n, nB);
|
|
111 |
}
|
|
112 |
|
|
113 |
for (InputNode n : nodesA) {
|
|
114 |
InputNode n2 = new InputNode(n);
|
|
115 |
graph.addNode(n2);
|
|
116 |
markAsNew(n2);
|
|
117 |
inputNodeMap.put(n, n2);
|
|
118 |
}
|
|
119 |
|
|
120 |
for (InputNode n : nodesB) {
|
|
121 |
InputNode n2 = new InputNode(n);
|
|
122 |
n2.setId(-n2.getId());
|
|
123 |
graph.addNode(n2);
|
|
124 |
markAsDeleted(n2);
|
|
125 |
inputNodeMap.put(n, n2);
|
|
126 |
}
|
|
127 |
|
1497
|
128 |
Collection<InputEdge> edgesA = a.getEdges();
|
|
129 |
Collection<InputEdge> edgesB = b.getEdges();
|
766
|
130 |
|
|
131 |
Set<InputEdge> newEdges = new HashSet<InputEdge>();
|
|
132 |
|
|
133 |
for (InputEdge e : edgesA) {
|
|
134 |
int from = e.getFrom();
|
|
135 |
int to = e.getTo();
|
|
136 |
InputNode nodeFrom = inputNodeMap.get(a.getNode(from));
|
|
137 |
InputNode nodeTo = inputNodeMap.get(a.getNode(to));
|
|
138 |
char index = e.getToIndex();
|
|
139 |
|
|
140 |
InputEdge newEdge = new InputEdge(index, nodeFrom.getId(), nodeTo.getId());
|
|
141 |
if (!newEdges.contains(newEdge)) {
|
|
142 |
markAsNew(newEdge);
|
|
143 |
newEdges.add(newEdge);
|
|
144 |
graph.addEdge(newEdge);
|
|
145 |
}
|
|
146 |
}
|
|
147 |
|
|
148 |
for (InputEdge e : edgesB) {
|
|
149 |
int from = e.getFrom();
|
|
150 |
int to = e.getTo();
|
|
151 |
InputNode nodeFrom = inputNodeMap.get(b.getNode(from));
|
|
152 |
InputNode nodeTo = inputNodeMap.get(b.getNode(to));
|
|
153 |
char index = e.getToIndex();
|
|
154 |
|
|
155 |
InputEdge newEdge = new InputEdge(index, nodeFrom.getId(), nodeTo.getId());
|
|
156 |
if (!newEdges.contains(newEdge)) {
|
|
157 |
markAsDeleted(newEdge);
|
|
158 |
newEdges.add(newEdge);
|
|
159 |
graph.addEdge(newEdge);
|
|
160 |
} else {
|
|
161 |
newEdges.remove(newEdge);
|
|
162 |
graph.removeEdge(newEdge);
|
|
163 |
markAsSame(newEdge);
|
|
164 |
newEdges.add(newEdge);
|
|
165 |
graph.addEdge(newEdge);
|
|
166 |
}
|
|
167 |
}
|
|
168 |
|
|
169 |
g.addGraph(graph);
|
|
170 |
return graph;
|
|
171 |
}
|
|
172 |
|
|
173 |
private static class Pair {
|
|
174 |
|
|
175 |
private InputNode n1;
|
|
176 |
private InputNode n2;
|
|
177 |
|
|
178 |
public Pair(InputNode n1, InputNode n2) {
|
|
179 |
this.n1 = n1;
|
|
180 |
this.n2 = n2;
|
|
181 |
}
|
|
182 |
|
|
183 |
public double getValue() {
|
|
184 |
|
|
185 |
double result = 0.0;
|
1497
|
186 |
for (Property p : n1.getProperties()) {
|
766
|
187 |
double faktor = 1.0;
|
|
188 |
for (String forbidden : IGNORE_PROPERTIES) {
|
|
189 |
if (p.getName().equals(forbidden)) {
|
|
190 |
faktor = 0.1;
|
|
191 |
break;
|
|
192 |
}
|
|
193 |
}
|
|
194 |
String p2 = n2.getProperties().get(p.getName());
|
|
195 |
result += evaluate(p.getValue(), p2) * faktor;
|
|
196 |
}
|
|
197 |
|
|
198 |
return result;
|
|
199 |
}
|
|
200 |
|
|
201 |
private double evaluate(String p, String p2) {
|
|
202 |
if (p2 == null) {
|
|
203 |
return 1.0;
|
|
204 |
}
|
|
205 |
if (p.equals(p2)) {
|
|
206 |
return 0.0;
|
|
207 |
} else {
|
|
208 |
return (double) (Math.abs(p.length() - p2.length())) / p.length() + 0.5;
|
|
209 |
}
|
|
210 |
}
|
|
211 |
|
|
212 |
public InputNode getN1() {
|
|
213 |
return n1;
|
|
214 |
}
|
|
215 |
|
|
216 |
public InputNode getN2() {
|
|
217 |
return n2;
|
|
218 |
}
|
|
219 |
}
|
|
220 |
|
|
221 |
private static InputGraph createDiff(InputGraph a, InputGraph b) {
|
|
222 |
|
|
223 |
Set<InputNode> matched = new HashSet<InputNode>();
|
|
224 |
|
|
225 |
Set<Pair> pairs = new HashSet<Pair>();
|
|
226 |
for (InputNode n : a.getNodes()) {
|
|
227 |
String s = n.getProperties().get(MAIN_PROPERTY);
|
|
228 |
if (s == null) {
|
|
229 |
s = "";
|
|
230 |
}
|
|
231 |
for (InputNode n2 : b.getNodes()) {
|
|
232 |
String s2 = n2.getProperties().get(MAIN_PROPERTY);
|
|
233 |
if (s2 == null) {
|
|
234 |
s2 = "";
|
|
235 |
}
|
|
236 |
|
|
237 |
if (s.equals(s2)) {
|
|
238 |
Pair p = new Pair(n, n2);
|
|
239 |
pairs.add(p);
|
|
240 |
}
|
|
241 |
}
|
|
242 |
}
|
|
243 |
|
|
244 |
Set<Pair> selectedPairs = new HashSet<Pair>();
|
|
245 |
while (pairs.size() > 0) {
|
|
246 |
|
|
247 |
double min = Double.MAX_VALUE;
|
|
248 |
Pair minPair = null;
|
|
249 |
for (Pair p : pairs) {
|
|
250 |
double cur = p.getValue();
|
|
251 |
if (cur < min) {
|
|
252 |
minPair = p;
|
|
253 |
min = cur;
|
|
254 |
}
|
|
255 |
}
|
|
256 |
|
|
257 |
if (min > LIMIT) {
|
|
258 |
break;
|
|
259 |
} else {
|
|
260 |
selectedPairs.add(minPair);
|
|
261 |
|
|
262 |
Set<Pair> toRemove = new HashSet<Pair>();
|
|
263 |
for (Pair p : pairs) {
|
|
264 |
if (p.getN1() == minPair.getN1() || p.getN2() == minPair.getN2()) {
|
|
265 |
toRemove.add(p);
|
|
266 |
}
|
|
267 |
}
|
|
268 |
pairs.removeAll(toRemove);
|
|
269 |
}
|
|
270 |
}
|
|
271 |
|
|
272 |
return createDiff(a, b, selectedPairs);
|
|
273 |
}
|
|
274 |
|
|
275 |
private static void markAsNew(InputEdge e) {
|
|
276 |
e.setState(InputEdge.State.NEW);
|
|
277 |
}
|
|
278 |
|
|
279 |
private static void markAsDeleted(InputEdge e) {
|
|
280 |
e.setState(InputEdge.State.DELETED);
|
|
281 |
|
|
282 |
}
|
|
283 |
|
|
284 |
private static void markAsSame(InputEdge e) {
|
|
285 |
e.setState(InputEdge.State.SAME);
|
|
286 |
}
|
|
287 |
|
|
288 |
private static void markAsChanged(InputNode n, InputNode firstNode, InputNode otherNode) {
|
|
289 |
|
|
290 |
boolean difference = false;
|
1497
|
291 |
for (Property p : otherNode.getProperties()) {
|
|
292 |
String s = firstNode.getProperties().get(p.getName());
|
766
|
293 |
if (!p.getValue().equals(s)) {
|
|
294 |
difference = true;
|
1497
|
295 |
n.getProperties().setProperty(OLD_PREFIX + p.getName(), p.getValue());
|
766
|
296 |
}
|
|
297 |
}
|
|
298 |
|
1497
|
299 |
for (Property p : firstNode.getProperties()) {
|
|
300 |
String s = otherNode.getProperties().get(p.getName());
|
766
|
301 |
if (s == null && p.getValue().length() > 0) {
|
|
302 |
difference = true;
|
1497
|
303 |
n.getProperties().setProperty(OLD_PREFIX + p.getName(), "");
|
766
|
304 |
}
|
|
305 |
}
|
|
306 |
|
|
307 |
if (difference) {
|
1497
|
308 |
n.getProperties().setProperty(PROPERTY_STATE, VALUE_CHANGED);
|
766
|
309 |
} else {
|
1497
|
310 |
n.getProperties().setProperty(PROPERTY_STATE, VALUE_SAME);
|
766
|
311 |
}
|
|
312 |
}
|
|
313 |
|
|
314 |
private static void markAsDeleted(InputNode n) {
|
1497
|
315 |
n.getProperties().setProperty(PROPERTY_STATE, VALUE_DELETED);
|
766
|
316 |
}
|
|
317 |
|
|
318 |
private static void markAsNew(InputNode n) {
|
1497
|
319 |
n.getProperties().setProperty(PROPERTY_STATE, VALUE_NEW);
|
766
|
320 |
}
|
|
321 |
}
|