blob: 54397d242e196cdf79333dd58959a32057ac5d93 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrew Johnson (IBM Corporation) - initial API and implementation
*******************************************************************************/
package org.eclipse.mat.inspections;
import java.io.File;
import java.text.Format;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.eclipse.mat.query.BytesFormat;
import org.eclipse.mat.query.IResult;
import org.eclipse.mat.query.annotations.Argument;
import org.eclipse.mat.query.annotations.Argument.Advice;
import org.eclipse.mat.query.annotations.CommandName;
import org.eclipse.mat.query.annotations.Icon;
import org.eclipse.mat.query.results.CompositeResult;
import org.eclipse.mat.report.Params;
import org.eclipse.mat.report.QuerySpec;
import org.eclipse.mat.report.SectionSpec;
import org.eclipse.mat.snapshot.Histogram;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.query.SnapshotQuery;
import org.eclipse.mat.util.IProgressListener;
/**
* Looks for leaks based on a delta in retained sizes of
* the dominator tree from two snapshots.
*/
@CommandName("leakhunter2")
@Icon("/META-INF/icons/leak.gif")
public class LeakHunterQuery2 extends LeakHunterQuery
{
@Argument(advice = Advice.SECONDARY_SNAPSHOT)
public ISnapshot baseline;
@Argument(isMandatory = false)
public String options = "-prefix"; //$NON-NLS-1$
@Argument(isMandatory = false)
public Pattern mask = Pattern.compile("\\s@ 0x[0-9a-f]+|^\\[[0-9]+\\]$|(?<=\\p{javaJavaIdentifierPart}\\[)\\d+(?=\\])"); //$NON-NLS-1$
@Argument(isMandatory = false, flag = "x")
public String[] extraReferences = new String[] {
"java.util.HashMap$Node:key", //$NON-NLS-1$
"java.util.Hashtable$Entry:key", //$NON-NLS-1$
"java.util.WeakHashMap$Entry:referent", //$NON-NLS-1$
"java.util.concurrent.ConcurrentHashMap$Node:key" //$NON-NLS-1$
};
@Argument(isMandatory = false, flag = "xfile")
public File extraReferencesListFile;
public IResult execute(IProgressListener listener) throws Exception
{
// Get a signed bytes formatter
Histogram dummy = snapshot.getHistogram(new int[0], listener);
dummy = dummy.diffWithBaseline(dummy);
Format f = dummy.getColumns()[2].getFormatter();
if (f instanceof BytesFormat)
bytesFormatter = (BytesFormat)f;
IResult res = super.execute(listener);
if (res instanceof SectionSpec)
{
// Add in saved dominator tree
QuerySpec spec = new QuerySpec(savedResult.getName());
spec.setResult(savedResult.getResult());
spec.setCommand(savedcmd);
spec.set(Params.Html.COLLAPSED, Boolean.TRUE.toString());
spec.set(Params.Rendering.SORT_COLUMN, "#5"); //$NON-NLS-1$
spec.set(Params.Rendering.HIDE_COLUMN, "#7,#8,#9"); //$NON-NLS-1$
((SectionSpec) res).add(spec);
}
return res;
}
CompositeResult.Entry savedResult;
String savedcmd;
FindLeaksQuery.SuspectsResultTable callFindLeaks(IProgressListener listener) throws Exception
{
String querycmd = "find_leaks2"; //$NON-NLS-1$
if (options != null)
querycmd += " -options " + options; //$NON-NLS-1$
StringBuilder cmd = new StringBuilder(querycmd);
SnapshotQuery query = SnapshotQuery.parse(querycmd, snapshot)
.setArgument("threshold_percent", threshold_percent) //$NON-NLS-1$
.setArgument("max_paths", max_paths) //$NON-NLS-1$
.setArgument("baseline", baseline); //$NON-NLS-1$
cmd.append(" -threshold_percent ").append(threshold_percent); //$NON-NLS-1$
cmd.append(" -max_paths ").append(max_paths); //$NON-NLS-1$
cmd.append(" -baseline ").append(baseline.getSnapshotInfo().getPath()); //$NON-NLS-1$
if (mask != null)
{
query.setArgument("mask", mask); //$NON-NLS-1$
cmd.append(" ").append("-mask ").append(escape(mask.pattern())); //$NON-NLS-1$ //$NON-NLS-2$
}
if (extraReferences != null)
{
query.setArgument("extraReferences", Arrays.asList(extraReferences)); //$NON-NLS-1$
cmd.append(" ").append("-x "); //$NON-NLS-1$ //$NON-NLS-2$
for (String e : extraReferences)
cmd.append(" ").append(escape(e)); //$NON-NLS-1$
}
if (extraReferencesListFile != null)
{
query.setArgument("extraReferencesListFile", extraReferencesListFile); //$NON-NLS-1$
cmd.append(" -xfile ").append(escape(extraReferencesListFile.getAbsolutePath())); //$NON-NLS-1$
}
savedcmd = cmd.toString();
IResult ret = query.execute(listener);
if (ret instanceof CompositeResult)
{
CompositeResult cr = (CompositeResult)ret;
// The delta dominator tree, save for later.
savedResult = cr.getResultEntries().get(0);
// The leaks, pass back to LinkHunterQuery.
return (FindLeaksQuery.SuspectsResultTable)cr.getResultEntries().get(1).getResult();
}
else
{
return (FindLeaksQuery.SuspectsResultTable)ret;
}
}
static String escape(String s)
{
/*
* abc\def -> abc\def
* abc"def -> abc\"def
* abc\\def -> abc\\\def
* abc\"def -> abc\\\"def
*/
s = s.replaceAll("\\\\(?=\\\\)|\\\\(?=\")|\"", "\\\\$0"); //$NON-NLS-1$ //$NON-NLS-2$
if (s.indexOf(' ') >= 0)
return "\"" + s + "\""; //$NON-NLS-1$ //$NON-NLS-2$
return s;
}
}