blob: 0ff35ea49bf3b04bc38104c5fafcafe8b1eb52c0 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
package org.eclipse.jifa.worker.route.heapdump;
import org.eclipse.jifa.worker.route.ParamKey;
import org.eclipse.jifa.worker.route.RouteMeta;
import org.eclipse.jifa.worker.support.Analyzer;
import org.eclipse.jifa.worker.support.heapdump.HeapDumpSupport;
import org.eclipse.jifa.worker.vo.heapdump.HeapObject;
import org.eclipse.jifa.worker.vo.heapdump.gcrootpath.Result;
import io.vertx.core.Future;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.snapshot.IPathsFromGCRootsComputer;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.model.IClass;
import org.eclipse.mat.snapshot.model.IObject;
import java.util.*;
import java.util.regex.Pattern;
import static org.eclipse.jifa.common.util.Assertion.ASSERT;
class PathToGCRootsRoute extends HeapBaseRoute {
private List<String> excludes =
Arrays.asList("java.lang.ref.WeakReference:referent", "java.lang.ref.SoftReference:referent");
private static Map<IClass, Set<String>> convert(ISnapshot snapshot,
List<String> excludes) throws SnapshotException {
Map<IClass, Set<String>> excludeMap = null;
if (excludes != null && !excludes.isEmpty()) {
excludeMap = new HashMap<IClass, Set<String>>();
for (String entry : excludes) {
String pattern = entry;
Set<String> fields = null;
int colon = entry.indexOf(':');
if (colon >= 0) {
fields = new HashSet<String>();
StringTokenizer tokens = new StringTokenizer(entry.substring(colon + 1), ","); //$NON-NLS-1$
while (tokens.hasMoreTokens())
fields.add(tokens.nextToken());
pattern = pattern.substring(0, colon);
}
for (IClass clazz : snapshot.getClassesByName(Pattern.compile(pattern), true))
excludeMap.put(clazz, fields);
}
}
return excludeMap;
}
@RouteMeta(path = "/pathToGCRoots")
void path(Future<Result> future, @ParamKey("file") String file, @ParamKey("origin") int origin,
@ParamKey("skip") int skip, @ParamKey("count") int count) throws Exception {
ASSERT.isTrue(origin >= 0).isTrue(skip >= 0).isTrue(count > 0);
ISnapshot snapshot = Analyzer.getOrOpenSnapshotContext(file).getSnapshot();
Map<IClass, Set<String>> excludeMap = convert(snapshot, excludes);
IPathsFromGCRootsComputer computer = snapshot.getPathsFromGCRoots(origin, excludeMap);
List<int[]> paths = new ArrayList<>();
int index = 0;
int[] current;
int get = 0;
while (get < count && (current = computer.getNextShortestPath()) != null) {
if (index < skip) {
index++;
continue;
}
paths.add(current);
get++;
}
future.complete(build(snapshot, origin, paths, computer.getNextShortestPath() != null));
}
private Result build(ISnapshot snapshot, int originId, List<int[]> paths, boolean hasMore) throws Exception {
Result result = new Result();
result.setCount(paths.size());
result.setHasMore(hasMore);
Result.Node origin = new Result.Node();
IObject object = snapshot.getObject(originId);
origin.setOrigin(true);
origin.setObjectId(originId);
origin.setLabel(object.getDisplayName());
origin.setSuffix(HeapDumpSupport.suffix(snapshot, originId));
origin.setGCRoot(snapshot.isGCRoot(originId));
origin.setObjectType(HeapObject.Type.typeOf(object));
origin.setShallowSize(object.getUsedHeapSize());
origin.setRetainedSize(object.getRetainedHeapSize());
result.setTree(origin);
if (paths.size() == 0) {
return result;
}
for (int[] path : paths) {
Result.Node parentNode = origin;
for (int index = 1; index < path.length; index++) {
int childId = path[index];
Result.Node childNode = parentNode.getChild(childId);
if (childNode == null) {
IObject childObj = snapshot.getObject(childId);
childNode = new Result.Node();
childNode.setObjectId(childId);
childNode.setPrefix(HeapDumpSupport.prefix(snapshot, childId, parentNode.getObjectId()));
childNode.setLabel(childObj.getDisplayName());
childNode.setSuffix(HeapDumpSupport.suffix(snapshot, childId));
childNode.setGCRoot(snapshot.isGCRoot(childId));
childNode.setObjectType(HeapObject.Type.typeOf(childObj));
childNode.setShallowSize(childObj.getUsedHeapSize());
childNode.setRetainedSize(childObj.getRetainedHeapSize());
parentNode.addChild(childNode);
}
parentNode = childNode;
}
}
return result;
}
}