Skip to content

Commit

Permalink
WINDUP-336: Tweaks to reduce memory usage and improve overall perform…
Browse files Browse the repository at this point in the history
…ance.
  • Loading branch information
jsight committed Nov 24, 2014
1 parent 0a365ff commit 712987f
Show file tree
Hide file tree
Showing 18 changed files with 642 additions and 148 deletions.
24 changes: 14 additions & 10 deletions config/api/src/main/java/org/jboss/windup/config/RuleSubset.java
Expand Up @@ -31,6 +31,7 @@
import org.jboss.windup.graph.model.performance.RulePhaseExecutionStatisticsModel;
import org.jboss.windup.graph.model.performance.RuleProviderExecutionStatisticsModel;
import org.jboss.windup.graph.service.GraphService;
import org.jboss.windup.graph.service.RuleProviderExecutionStatisticsService;
import org.jboss.windup.util.exception.WindupException;
import org.ocpsoft.common.util.Assert;
import org.ocpsoft.rewrite.bind.Binding;
Expand Down Expand Up @@ -74,14 +75,16 @@ public class RuleSubset extends DefaultOperationBuilder implements CompositeOper
private static Logger log = Logger.getLogger(RuleSubset.class.getName());

/**
* Used for tracking the time taken by the rules within each RuleProvider
* Used for tracking the time taken by the rules within each RuleProvider. This links from a {@link WindupRuleProvider} to the ID of a
* {@link RuleProviderExecutionStatisticsModel}
*/
private final IdentityHashMap<WindupRuleProvider, RuleProviderExecutionStatisticsModel> timeTakenByProvider = new IdentityHashMap<>();
private final IdentityHashMap<WindupRuleProvider, Object> timeTakenByProvider = new IdentityHashMap<>();

/**
* Used for tracking the time taken by each phase of execution
* Used for tracking the time taken by each phase of execution. This links from a {@link RulePhase} to the ID of a
* {@link RulePhaseExecutionStatisticsModel}
*/
private final Map<RulePhase, RulePhaseExecutionStatisticsModel> timeTakenByPhase = new HashMap<>();
private final Map<RulePhase, Object> timeTakenByPhase = new HashMap<>();

private final Configuration config;

Expand Down Expand Up @@ -109,17 +112,17 @@ private void logTimeTakenByRuleProvider(GraphContext graphContext, Context conte

if (!timeTakenByProvider.containsKey(ruleProvider))
{
RuleProviderExecutionStatisticsModel model = new GraphService<>(graphContext,
RuleProviderExecutionStatisticsModel.class).create();
RuleProviderExecutionStatisticsModel model = new RuleProviderExecutionStatisticsService(graphContext).create();
model.setRuleIndex(ruleIndex);
model.setRuleProviderID(ruleProvider.getID());
model.setTimeTaken(timeTaken);

timeTakenByProvider.put(ruleProvider, model);
timeTakenByProvider.put(ruleProvider, model.asVertex().getId());
}
else
{
RuleProviderExecutionStatisticsModel model = timeTakenByProvider.get(ruleProvider);
RuleProviderExecutionStatisticsService service = new RuleProviderExecutionStatisticsService(graphContext);
RuleProviderExecutionStatisticsModel model = service.getById(timeTakenByProvider.get(ruleProvider));
int prevTimeTaken = model.getTimeTaken();
model.setTimeTaken(prevTimeTaken + timeTaken);
}
Expand All @@ -137,11 +140,12 @@ private void logTimeTakenByPhase(GraphContext graphContext, RulePhase phase, int
RulePhaseExecutionStatisticsModel.class).create();
model.setRulePhase(phase.toString());
model.setTimeTaken(timeTaken);
timeTakenByPhase.put(phase, model);
timeTakenByPhase.put(phase, model.asVertex().getId());
}
else
{
RulePhaseExecutionStatisticsModel model = timeTakenByPhase.get(phase);
GraphService<RulePhaseExecutionStatisticsModel> service = new GraphService<>(graphContext, RulePhaseExecutionStatisticsModel.class);
RulePhaseExecutionStatisticsModel model = service.getById(timeTakenByPhase.get(phase));
int prevTimeTaken = model.getTimeTaken();
model.setTimeTaken(prevTimeTaken + timeTaken);
}
Expand Down
18 changes: 6 additions & 12 deletions config/api/src/main/java/org/jboss/windup/config/query/Query.java
Expand Up @@ -15,6 +15,7 @@
import org.jboss.windup.config.condition.GraphCondition;
import org.jboss.windup.config.operation.Iteration;
import org.jboss.windup.config.selectors.FramesSelector;
import org.jboss.windup.graph.frames.VertexFromFramedIterable;
import org.jboss.windup.graph.model.WindupVertexFrame;
import org.jboss.windup.util.ExecutionStatistics;
import org.jboss.windup.util.Task;
Expand Down Expand Up @@ -95,11 +96,8 @@ public Boolean execute()
Query.this.setInitialFramesSelector(createInitialFramesSelector(Query.this));
Iterable<WindupVertexFrame> resultIterable = framesSelector.getFrames(event, context);
Iterator<WindupVertexFrame> iterator = resultIterable.iterator();
List<WindupVertexFrame> result = new ArrayList<WindupVertexFrame>();
while (iterator.hasNext())
{
result.add(iterator.next());
}

Iterable<WindupVertexFrame> result = resultIterable;

if (resultFilter != null)
{
Expand All @@ -111,7 +109,8 @@ public Boolean execute()
filtered.add(frame);
}
}
result.retainAll(filtered);

result = filtered;
}

Variables variables = (Variables) event.getRewriteContext().get(Variables.class);
Expand Down Expand Up @@ -180,12 +179,7 @@ private Iterable<Vertex> getStartingVertices(GraphRewrite event)
}
Variables variables = (Variables) event.getRewriteContext().get(Variables.class);
Iterable<WindupVertexFrame> frames = variables.findVariable(query.getInputVariablesName());
List<Vertex> startingVerticesList = new ArrayList<Vertex>();
for (WindupVertexFrame frame : frames)
{
startingVerticesList.add(frame.asVertex());
}
return startingVerticesList;
return new VertexFromFramedIterable(frames);
}
else
{
Expand Down
@@ -0,0 +1,19 @@
package org.jboss.windup.decompiler.api;

/**
* Called to indicate the progress during decompilation
*/
public interface DecompilationListener
{
/**
* Indicates that the file at inputPath has been decompiled to outputPath
*/
public void fileDecompiled(String inputPath, String outputPath);

/**
* Indicates that the decompilation process is complete for all files within the archive (or directory).
*
* This allows for cleanup, such as committing all results to disk.
*/
public void decompilationProcessComplete();
}
Expand Up @@ -7,16 +7,15 @@
import java.util.Map;

/**
* Keeps a count of successful decompilations and list of failed ones, in the form of an exception with String path and
* cause exception.
* Keeps a count of successful decompilations and list of failed ones, in the form of an exception with String path and cause exception.
*
* @author Ondrej Zizka, ozizka at redhat.com
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class DecompilationResult
{
private final List<DecompilationFailure> failed = new LinkedList<>();
private final Map<String, String> decompiledFiles = new HashMap<>();
private final List<DecompilationFailure> failed = Collections.synchronizedList(new LinkedList<DecompilationFailure>());
private final Map<String, String> decompiledFiles = Collections.synchronizedMap(new HashMap<String, String>());

public void addDecompiled(String inputPath, String path)
{
Expand Down
Expand Up @@ -15,25 +15,22 @@
public interface Decompiler
{
/**
* Decompiles the given .class file and creates the specified output source file in the given output dir under
* appropriate package subdirectories, like $outputDir/org/jboss/Foo.java. Decompilation may need multiple .class
* files for one .java file, e.g. for inner classes.
* Decompiles the given .class file and creates the specified output source file in the given output dir under appropriate package subdirectories,
* like $outputDir/org/jboss/Foo.java. Decompilation may need multiple .class files for one .java file, e.g. for inner classes.
*
* @param classFile the .class file to be decompiled.
* @param outputDir The directory where decompiled .java files will be placed.
*/
public DecompilationResult decompileClassFile(File rootDir, Path classFilePath, File outputDir)
throws DecompilationException;

/**
* Close all the resources
*/
public void close();


/**
* Decompiles all .class files and archives in the given directory and places results in the specified output
* directory.
* Decompiles all .class files and archives in the given directory and places results in the specified output directory.
* <p>
* Discovered archives will be decompiled into directories matching the name of the archive, e.g.
* <code>foo.ear/bar.jar/src/com/foo/bar/Baz.java</code>.
Expand All @@ -55,9 +52,9 @@ public DecompilationResult decompileClassFile(File rootDir, Path classFilePath,
*
* @param archive The archive containing source files and archives.
* @param outputDir The directory where decompiled .java files will be placed.
* @param listener This is called after each successful decompilation
*/
public DecompilationResult decompileArchive(File archive, File outputDir) throws DecompilationException;

public DecompilationResult decompileArchive(File archive, File outputDir, DecompilationListener listener) throws DecompilationException;

/**
* Decompiles all .class files and nested archives in the given archive.
Expand All @@ -70,7 +67,8 @@ public DecompilationResult decompileClassFile(File rootDir, Path classFilePath,
* @param archive The archive containing source files and archives.
* @param outputDir The directory where decompiled .java files will be placed.
* @param filter Decides what files from the archive to decompile.
* @param listener This is called after each successful decompilation
*/
public DecompilationResult decompileArchive(File archive, File outputDir, Filter<ZipEntry> filter)
public DecompilationResult decompileArchive(File archive, File outputDir, Filter<ZipEntry> filter, DecompilationListener listener)
throws DecompilationException;
}
Expand Up @@ -10,6 +10,7 @@
import org.apache.commons.io.FileUtils;
import org.jboss.windup.decompiler.api.DecompilationException;
import org.jboss.windup.decompiler.api.DecompilationFailure;
import org.jboss.windup.decompiler.api.DecompilationListener;
import org.jboss.windup.decompiler.api.DecompilationResult;
import org.jboss.windup.decompiler.api.Decompiler;
import org.jboss.windup.decompiler.util.CountClassesFilter;
Expand Down Expand Up @@ -112,7 +113,20 @@ public void testDecompileWicketJar() throws DecompilationException
File decompDir = new File(testTempDir, "decompiled");

final Decompiler dec = this.getDecompiler();
final DecompilationResult res = dec.decompileArchive(archive, decompDir, new CountClassesFilter(100));
final DecompilationResult res = dec.decompileArchive(archive, decompDir, new CountClassesFilter(100), new DecompilationListener()
{
@Override
public void decompilationProcessComplete()
{
// noop
}

@Override
public void fileDecompiled(String inputPath, String outputPath)
{
// noop
}
});

Assert.assertNotNull("Results object returned", res);

Expand Down
7 changes: 6 additions & 1 deletion decompiler/impl-procyon/pom.xml
Expand Up @@ -16,7 +16,7 @@
<name>Windup Engine - Decompiler Procyon</name>

<properties>
<version.procyon>0.5.25</version.procyon>
<version.procyon>0.5.27</version.procyon>
</properties>

<dependencies>
Expand All @@ -32,6 +32,11 @@
<artifactId>procyon-compilertools</artifactId>
<version>${version.procyon}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

<!-- Addon Dependencies -->
<dependency>
Expand Down
@@ -0,0 +1,117 @@
package com.strobel.assembler.metadata;

import org.apache.commons.collections4.map.LRUMap;

import com.strobel.core.VerifyArgument;

/**
* Keeps a set of types which failed to load and also uses an LRUCache to reduce the memory footprint for cached lookups.
*
* @author Ondrej Zizka, ozizka at redhat.com
*/
public final class NoRetryMetadataSystem extends MetadataSystem
{
private final static TypeDefinition[] PRIMITIVE_TYPES_BY_NAME = new TypeDefinition['Z' - 'B' + 1];
private final static TypeDefinition[] PRIMITIVE_TYPES_BY_DESCRIPTOR = new TypeDefinition[16];
private final LRUMap<String, Boolean> failedTypes = new LRUMap<>(1000);
private final LRUMap<String, TypeDefinition> resolvedTypes = new LRUMap<>(1000);
private final ITypeLoader typeLoader;

public NoRetryMetadataSystem(final ITypeLoader typeLoader)
{
super(typeLoader);
this.typeLoader = typeLoader;
}

public void addTypeDefinition(final TypeDefinition type)
{
VerifyArgument.notNull(type, "type");
resolvedTypes.put(type.getInternalName(), type);
}

@Override
protected TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive)
{
if (failedTypes.containsKey(descriptor))
return null;

TypeDefinition result = resolveTypeInternal(descriptor, mightBePrimitive);

if (result == null)
failedTypes.put(descriptor, true);

return result;
}

protected TypeDefinition resolveTypeInternal(final String descriptor, final boolean mightBePrimitive)
{
VerifyArgument.notNull(descriptor, "descriptor");

if (mightBePrimitive)
{
if (descriptor.length() == 1)
{
final int primitiveHash = descriptor.charAt(0) - 'B';

if (primitiveHash >= 0 && primitiveHash < PRIMITIVE_TYPES_BY_DESCRIPTOR.length)
{
final TypeDefinition primitiveType = PRIMITIVE_TYPES_BY_DESCRIPTOR[primitiveHash];

if (primitiveType != null)
{
return primitiveType;
}
}
}
else
{
final int primitiveHash = hashPrimitiveName(descriptor);

if (primitiveHash >= 0 && primitiveHash < PRIMITIVE_TYPES_BY_NAME.length)
{
final TypeDefinition primitiveType = PRIMITIVE_TYPES_BY_NAME[primitiveHash];

if (primitiveType != null && descriptor.equals(primitiveType.getName()))
{
return primitiveType;
}
}
}
}

TypeDefinition cachedDefinition = resolvedTypes.get(descriptor);

if (cachedDefinition != null)
{
return cachedDefinition;
}

final Buffer buffer = new Buffer(0);

if (!this.typeLoader.tryLoadType(descriptor, buffer))
{
return null;
}

final TypeDefinition typeDefinition = ClassFileReader.readClass(ClassFileReader.OPTIONS_DEFAULT, this, buffer);

cachedDefinition = resolvedTypes.put(descriptor, typeDefinition);
typeDefinition.setTypeLoader(this.typeLoader);

if (cachedDefinition != null)
{
return cachedDefinition;
}

return typeDefinition;
}

private static int hashPrimitiveName(final String name)
{
if (name.length() < 3)
{
return 0;
}
return (name.charAt(0) + name.charAt(2)) % 16;
}
}

0 comments on commit 712987f

Please sign in to comment.