blob: e48f134b3b0de401bb7d0a69508819e5f56b895b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP AG - initial API and implementation
* IBM Corporation - enhancements and fixes
* James Livingston - expose collection utils as API
*******************************************************************************/
package org.eclipse.mat.inspections.collections;
import java.util.Arrays;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.collect.ArrayInt;
import org.eclipse.mat.collect.ArrayIntBig;
import org.eclipse.mat.collect.ArrayLong;
import org.eclipse.mat.collect.ArrayLongBig;
import org.eclipse.mat.collect.HashMapIntLong;
import org.eclipse.mat.collect.HashMapIntObject;
import org.eclipse.mat.collect.HashMapLongObject;
import org.eclipse.mat.collect.HashMapObjectLong;
import org.eclipse.mat.collect.QueueInt;
import org.eclipse.mat.collect.SetInt;
import org.eclipse.mat.collect.SetLong;
import org.eclipse.mat.inspections.collectionextract.AbstractExtractedCollection;
import org.eclipse.mat.inspections.collectionextract.CollectionExtractionUtils;
import org.eclipse.mat.inspections.collectionextract.ICollectionExtractor;
import org.eclipse.mat.internal.Messages;
import org.eclipse.mat.query.quantize.Quantize;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.SnapshotInfo;
import org.eclipse.mat.snapshot.model.IClass;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.model.IObjectArray;
import org.eclipse.mat.util.IProgressListener;
import org.eclipse.mat.util.MessageUtil;
public class AbstractFillRatioQuery
{
private static class Result
{
final double fill;
final long used;
final long wasted;
public Result(double fill, long used, long wasted)
{
this.fill = fill;
this.used = used;
this.wasted = wasted;
}
}
protected void runQuantizer(IProgressListener listener, Quantize quantize, ICollectionExtractor specificExtractor,
String specificClass, ISnapshot snapshot, Iterable<int[]> objects, String msg) throws SnapshotException
{
SnapshotInfo info = snapshot.getSnapshotInfo();
final int refsize = info.getIdentifierSize() == 8
&& Boolean.TRUE.equals((Boolean) info.getProperty("$useCompressedOops")) //$NON-NLS-1$
? 4
: info.getIdentifierSize();
final long LIMIT = 20;
HashMapIntLong exceptions = new HashMapIntLong();
int counter = 0;
IClass type = null;
for (int[] objectIds : objects)
{
HashMapIntObject<Result> resultMap = null;
int sortedObjs[] = objectIds;
int prev = Integer.MIN_VALUE;
for (int objectId : objectIds)
{
if (objectId < prev)
{
sortedObjs = objectIds.clone();
Arrays.sort(sortedObjs);
resultMap = new HashMapIntObject<Result>();
break;
}
prev = objectId;
}
for (int objectId : sortedObjs)
{
if (listener.isCanceled())
break;
IObject obj = snapshot.getObject(objectId);
if (counter++ % 1000 == 0 && !obj.getClazz().equals(type))
{
type = obj.getClazz();
listener.subTask(msg + "\n" + type.getName()); //$NON-NLS-1$
}
try
{
AbstractExtractedCollection<?, ?> coll = CollectionExtractionUtils.extractCollection(obj, specificClass,
specificExtractor);
if (coll != null && coll.hasCapacity())
{
Double fillRatio = coll.getFillRatio();
if (fillRatio != null)
{
long wasted = 0;
if (coll.hasCapacity())
{
Integer c = coll.getCapacity();
if (c != null)
{
// These don't have reference sized slots
int refsize2;
if (obj.getClazz().getName().equals(SetInt.class.getName()))
refsize2 = 4;
else if (obj.getClazz().getName().equals(ArrayInt.class.getName()))
refsize2 = 4;
else if (obj.getClazz().getName().equals(QueueInt.class.getName()))
refsize2 = 4;
else if (obj.getClazz().getName().equals(SetLong.class.getName()))
refsize2 = 8;
else if (obj.getClazz().getName().equals(ArrayLong.class.getName()))
refsize2 = 8;
else if (obj.getClazz().getName().equals(HashMapIntLong.class.getName()))
refsize2 = 13;
else if (obj.getClazz().getName().equals(HashMapIntObject.class.getName()))
refsize2 = 5 + refsize;
else if (obj.getClazz().getName().equals(HashMapLongObject.class.getName()))
refsize2 = 9 + refsize;
else if (obj.getClazz().getName().equals(HashMapObjectLong.class.getName()))
refsize2 = 9 + refsize;
else if (obj.getClazz().getName().equals(ArrayIntBig.class.getName()))
refsize2 = 4;
else if (obj.getClazz().getName().equals(ArrayLongBig.class.getName()))
refsize2 = 8;
else
refsize2 = refsize;
wasted = (long)(c * refsize2 * (1 - fillRatio));
}
}
else if (coll.hasExtractableArray())
{
IObjectArray backing = coll.extractEntries();
if (backing != null)
{
wasted = (long)(backing.getClazz().getHeapSizePerInstance() * (1 - fillRatio));
}
}
else if (coll.hasSize())
{
Integer size = coll.size();
if (size != null)
{
int s = size;
// Try to have some limits on what might be calculated
if (fillRatio > 0)
{
wasted = (long) Math.min((s * refsize / (1 - fillRatio)),
coll.getUsedHeapSize());
}
}
}
if (resultMap != null)
resultMap.put(objectId, new Result(fillRatio, coll.getUsedHeapSize(),wasted));
else
quantize.addValue(objectId, fillRatio, 1, coll.getUsedHeapSize(), wasted);
}
}
}
catch (RuntimeException e)
{
int classId = obj.getClazz().getObjectId();
if (!exceptions.containsKey(classId))
{
exceptions.put(classId, 0);
}
long c = exceptions.get(classId);
exceptions.put(classId, c + 1);
if (c < LIMIT)
{
listener.sendUserMessage(
IProgressListener.Severity.INFO,
MessageUtil.format(Messages.CollectionFillRatioQuery_IgnoringCollection,
obj.getTechnicalName()), e);
}
}
}
if (resultMap != null)
{
for (int objectId : objectIds)
{
if (resultMap.containsKey(objectId))
{
Result r = resultMap.get(objectId);
quantize.addValue(objectId, r.fill, 1, r.used, r.wasted);
}
}
}
if (listener.isCanceled())
break;
}
}
}