org.adoptopenjdk.jitwatch.jarscan.JarScan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jitwatch-jarscan-maven-plugin Show documentation
Show all versions of jitwatch-jarscan-maven-plugin Show documentation
A Maven plugin that scans the project artifact and its dependencies for methods that cannot be inlined by the JIT
compiler. It uses the JarScan utility from the JITWatch project to do that.
See https://github.com/AdoptOpenJDK/jitwatch .
The newest version!
/*
* Copyright (c) 2013-2016 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.jarscan;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_DOT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_DOT_CLASS;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_SLASH;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_COMMA;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_ASTERISK;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_EMPTY;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.adoptopenjdk.jitwatch.jarscan.allocationcount.AllocationCountOperation;
import org.adoptopenjdk.jitwatch.jarscan.freqinlinesize.FreqInlineSizeOperation;
import org.adoptopenjdk.jitwatch.jarscan.instructioncount.InstructionCountOperation;
import org.adoptopenjdk.jitwatch.jarscan.invokecount.InvokeCountOperation;
import org.adoptopenjdk.jitwatch.jarscan.methodlength.MethodLengthOperation;
import org.adoptopenjdk.jitwatch.jarscan.methodsizehisto.MethodSizeHistoOperation;
import org.adoptopenjdk.jitwatch.jarscan.nextinstruction.NextInstructionOperation;
import org.adoptopenjdk.jitwatch.jarscan.sequencecount.SequenceCountOperation;
import org.adoptopenjdk.jitwatch.jarscan.sequencesearch.SequenceSearchOperation;
import org.adoptopenjdk.jitwatch.loader.BytecodeLoader;
import org.adoptopenjdk.jitwatch.model.bytecode.ClassBC;
import org.adoptopenjdk.jitwatch.model.bytecode.MemberBytecode;
public class JarScan
{
private IJarScanOperation operation;
private List allowedPackagePrefixes = new ArrayList<>();
public JarScan(IJarScanOperation operation)
{
this.operation = operation;
}
public void writeReport()
{
Writer writer = new PrintWriter(System.out);
String report = operation.getReport();
try
{
writer.write(report);
writer.flush();
writer.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void iterateJar(File jarFile) throws IOException
{
List classLocations = new ArrayList<>();
classLocations.add(jarFile.getPath());
try (ZipFile zip = new ZipFile(jarFile))
{
@SuppressWarnings("unchecked")
Enumeration list = (Enumeration) zip.entries();
while (list.hasMoreElements())
{
ZipEntry entry = list.nextElement();
String name = entry.getName();
if (name.endsWith(S_DOT_CLASS))
{
String fqName = name.replace(S_SLASH, S_DOT).substring(0, name.length() - S_DOT_CLASS.length());
process(classLocations, fqName);
}
}
}
}
public void addAllowedPackagePrefix(String prefix)
{
allowedPackagePrefixes.add(prefix);
}
private boolean isAllowedPackage(String fqClassName)
{
boolean allowed = false;
if (allowedPackagePrefixes.size() == 0)
{
allowed = true;
}
else
{
for (String allowedPrefix : allowedPackagePrefixes)
{
if (fqClassName.startsWith(allowedPrefix))
{
allowed = true;
break;
}
}
}
return allowed;
}
private void process(List classLocations, String fqClassName)
{
if (!isAllowedPackage(fqClassName))
{
return;
}
boolean cacheBytecode = false;
ClassBC classBytecode = BytecodeLoader.fetchBytecodeForClass(classLocations, fqClassName, cacheBytecode);
if (classBytecode != null)
{
for (MemberBytecode memberBytecode : classBytecode.getMemberBytecodeList())
{
try
{
operation.processInstructions(fqClassName, memberBytecode);
}
catch (Exception e)
{
System.err.println(
"Could not process " + fqClassName + " " + memberBytecode.getMemberSignatureParts().getMemberName());
System.err.println(memberBytecode.toString());
e.printStackTrace();
System.exit(-1);
}
}
}
else
{
System.err.println("An error occurred while parsing " + fqClassName);
}
}
private static void showUsage()
{
StringBuilder builder = new StringBuilder();
String SEPARATOR = "---------------------------------------------------------------------------------------------------";
builder.append("JarScan --mode= [options] [params] ").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append("Options:").append(S_NEWLINE);
builder.append(" --packages=a,b,c Only include methods from named packages. E.g. --packages=java.util.*")
.append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append("Modes:").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" maxMethodSize List every method with bytecode larger than specified limit.").append(S_NEWLINE);
builder.append(" --limit=n Report methods larger than n bytes.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" sequenceCount Count instruction sequences.").append(S_NEWLINE);
builder.append(" --length=n Report sequences of length n.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" invokeCount Count the most called methods for each invoke instruction.").append(S_NEWLINE);
builder.append(" [--limit=n] Limit to top n results per invoke type.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" nextInstructionFreq List the most popular next instruction for each bytecode instruction.")
.append(S_NEWLINE);
builder.append(" [--limit=n] Limit to top n results per instruction.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" allocationCount Count the most allocated types.").append(S_NEWLINE);
builder.append(" [--limit=n] Limit to top n results.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" instructionCount Count occurences of each bytecode instruction.").append(S_NEWLINE);
builder.append(" [--limit=n] Limit to top n results.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" sequenceSearch List methods containing the specified bytecode sequence.").append(S_NEWLINE);
builder.append(" --sequence=a,b,c,... Comma separated sequence of bytecode instructions.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" methodSizeHisto List frequencies of method bytecode sizes.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
builder.append(" methodLength List methods of the given bytecode size.").append(S_NEWLINE);
builder.append(" --length=n Size of methods to find.").append(S_NEWLINE);
builder.append(SEPARATOR).append(S_NEWLINE);
System.err.println(builder.toString());
}
private static final String ARG_PACKAGES = "--packages=";
private static final String ARG_MODE = "--mode=";
private static final String ARG_LIMIT = "--limit=";
private static final String ARG_LENGTH = "--length=";
private static final String ARG_SEQUENCE = "--sequence=";
private static int getParam(String[] args, String paramName, boolean mandatory)
{
int result;
if (!mandatory)
{
result = 0;
}
else
{
result = -1;
}
for (String param : args)
{
if (param.startsWith(paramName))
{
String argValue = param.substring(paramName.length(), param.length());
try
{
result = Integer.parseInt(argValue);
}
catch (NumberFormatException nfe)
{
System.err.println("Could not parse parameter " + paramName + " : " + argValue);
}
break;
}
}
return result;
}
private static String getParamString(String[] args, String paramName)
{
String result = null;
for (String param : args)
{
if (param.startsWith(paramName))
{
result = param.substring(paramName.length(), param.length());
break;
}
}
return result;
}
private static IJarScanOperation getJarScanOperation(String[] args)
{
IJarScanOperation operation = null;
String mode = getParamString(args, ARG_MODE);
if (mode != null)
{
String modeParam = mode.toLowerCase();
switch (modeParam)
{
case "maxmethodsize":
{
int paramValue = getParam(args, ARG_LIMIT, true);
if (paramValue > 0)
{
operation = new FreqInlineSizeOperation(paramValue);
}
break;
}
case "sequencecount":
{
int paramValue = getParam(args, ARG_LENGTH, true);
if (paramValue > 0)
{
operation = new SequenceCountOperation(paramValue);
}
break;
}
case "invokecount":
{
int paramValue = getParam(args, ARG_LIMIT, false);
if (paramValue >= 0)
{
operation = new InvokeCountOperation(paramValue);
}
break;
}
case "nextinstructionfreq":
{
int paramValue = getParam(args, ARG_LIMIT, false);
if (paramValue >= 0)
{
operation = new NextInstructionOperation(paramValue);
}
}
break;
case "allocationcount":
{
int paramValue = getParam(args, ARG_LIMIT, false);
if (paramValue >= 0)
{
operation = new AllocationCountOperation(paramValue);
}
break;
}
case "instructioncount":
{
int paramValue = getParam(args, ARG_LIMIT, false);
if (paramValue >= 0)
{
operation = new InstructionCountOperation(paramValue);
}
break;
}
case "sequencesearch":
{
String sequence = getParamString(args, ARG_SEQUENCE);
if (sequence != null)
{
operation = new SequenceSearchOperation(sequence);
}
break;
}
case "methodsizehisto":
{
operation = new MethodSizeHistoOperation();
break;
}
case "methodlength":
{
int paramValue = getParam(args, ARG_LENGTH, true);
if (paramValue > 0)
{
operation = new MethodLengthOperation(paramValue);
}
break;
}
}
}
return operation;
}
public static void main(String[] args) throws IOException
{
IJarScanOperation operation = getJarScanOperation(args);
if (operation == null)
{
showUsage();
System.exit(-1);
}
JarScan scanner = new JarScan(operation);
String packages = getParamString(args, ARG_PACKAGES);
if (packages != null)
{
String[] prefixes = packages.split(S_COMMA);
for (String prefix : prefixes)
{
prefix = prefix.replace(S_ASTERISK, S_EMPTY);
scanner.addAllowedPackagePrefix(prefix);
}
}
for (String arg : args)
{
if (arg.startsWith("--"))
{
continue;
}
File jarFile = new File(arg);
if (jarFile.exists() && jarFile.isFile())
{
scanner.iterateJar(jarFile);
}
else
{
System.err.println("Could not scan jar " + jarFile.toString());
}
}
scanner.writeReport();
}
}