blob: 77351038c20cf157bd3c38b371acf8ee9de88873 [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.support.heapdump;
import lombok.Data;
import org.eclipse.mat.inspections.ClassLoaderExplorerQuery;
import org.eclipse.mat.inspections.LeakHunterQuery;
import org.eclipse.mat.inspections.OQLQuery;
import org.eclipse.mat.internal.snapshot.SnapshotQueryContext;
import org.eclipse.mat.internal.snapshot.inspections.OldObjRefYoungObjQuery;
import org.eclipse.mat.query.Column;
import org.eclipse.mat.query.IResult;
import org.eclipse.mat.query.IResultTable;
import org.eclipse.mat.query.IResultTree;
import org.eclipse.mat.query.refined.RefinedResultBuilder;
import org.eclipse.mat.query.refined.RefinedTable;
import org.eclipse.mat.snapshot.ISnapshot;
import java.lang.ref.SoftReference;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SnapshotContext {
private ISnapshot snapshot;
private SoftReference<DirectByteBuffer> directByteBuffer;
private SoftReference<ClassLoaderExplorer> classLoaderExplorer;
private SoftReference<LeakReport> leakReport;
public SnapshotContext(ISnapshot snapshot) {
this.snapshot = snapshot;
}
private synchronized <T> T fetch(SoftReference<T> cache, Builder<T> builder) throws Exception {
T res;
if (cache == null || (res = cache.get()) == null) {
res = builder.build();
}
return res;
}
public synchronized ClassLoaderExplorer classLoaderExplorer() throws Exception {
return fetch(classLoaderExplorer, () -> {
ClassLoaderExplorer result = new ClassLoaderExplorer();
classLoaderExplorer = new SoftReference<>(result);
return result;
});
}
public synchronized DirectByteBuffer directByteBuffer() throws Exception {
return fetch(directByteBuffer, () -> {
DirectByteBuffer result = new DirectByteBuffer();
directByteBuffer = new SoftReference<>(result);
return result;
});
}
public synchronized LeakReport leakReport() throws Exception {
return fetch(leakReport, () -> {
LeakReport result = new LeakReport();
leakReport = new SoftReference<>(result);
return result;
});
}
public ISnapshot getSnapshot() {
return snapshot;
}
interface Builder<T> {
T build() throws Exception;
}
@Data
public class LeakReport {
IResult result;
LeakReport() throws Exception {
LeakHunterQuery query = new LeakHunterQuery();
query.snapshot = snapshot;
result = query.execute(HeapDumpSupport.VOID_LISTENER);
}
}
@Data
public class DirectByteBuffer {
private static final String OQL =
"SELECT s.@displayName as label, s.position as position, s.limit as limit, s.capacity as " +
"capacity FROM java.nio.DirectByteBuffer s where s.cleaner != null";
RefinedTable resultContext;
private long position;
private long limit;
private long capacity;
private int totalSize;
DirectByteBuffer() throws Exception {
OQLQuery query = new OQLQuery();
query.snapshot = snapshot;
query.queryString = OQL;
IResult result = query.execute(HeapDumpSupport.VOID_LISTENER);
if (result instanceof IResultTable) {
RefinedResultBuilder builder =
new RefinedResultBuilder(new SnapshotQueryContext(snapshot), (IResultTable) result);
builder.setSortOrder(3, Column.SortDirection.DESC);
resultContext = (RefinedTable) builder.build();
totalSize = resultContext.getRowCount();
for (int i = 0; i < totalSize; i++) {
Object row = resultContext.getRow(i);
position += position(row);
limit += limit(row);
capacity += capacity(row);
}
}
}
public String label(Object row) {
return (String) resultContext.getColumnValue(row, 0);
}
public int position(Object row) {
return (Integer) resultContext.getColumnValue(row, 1);
}
public int limit(Object row) {
return (Integer) resultContext.getColumnValue(row, 2);
}
public int capacity(Object row) {
return (Integer) resultContext.getColumnValue(row, 3);
}
}
@Data
public class OldObjRefYoungObj {
private OldObjRefYoungObjQuery.Tree result;
private List<?> records;
private int refCount;
OldObjRefYoungObj() throws Exception {
OldObjRefYoungObjQuery query = new OldObjRefYoungObjQuery();
query.snapshot = snapshot;
query.groupBy = OldObjRefYoungObjQuery.Grouping.BY_CLASS;
result = query.execute(HeapDumpSupport.VOID_LISTENER);
records = result.getElements();
for (Object record : records) {
refCount += (int) result.getColumnValue(record, 1);
}
}
}
@Data
public class ClassLoaderExplorer {
private IResult resultContext;
// classloader object Id -> record
private Map<Integer, Object> classLoaderIdMap;
private List<?> records;
private int definedClasses;
private int numberOfInstances;
ClassLoaderExplorer() throws Exception {
ClassLoaderExplorerQuery query = new ClassLoaderExplorerQuery();
query.snapshot = snapshot;
IResultTree result = (IResultTree) query.execute(HeapDumpSupport.VOID_LISTENER);
this.resultContext = result;
Map<Integer, Object> classLoaderIdMap = new HashMap<>();
for (Object r : result.getElements()) {
classLoaderIdMap.put(result.getContext(r).getObjectId(), r);
}
this.records = result.getElements();
this.records.sort((Comparator<Object>) (o1, o2) -> Integer
.compare((int) result.getColumnValue(o2, 1), (int) result.getColumnValue(o1, 1)));
this.classLoaderIdMap = classLoaderIdMap;
for (Object record : records) {
definedClasses += (int) result.getColumnValue(record, 1);
numberOfInstances += (int) result.getColumnValue(record, 2);
}
}
}
}