Improve DependencyChecker performance

This commit is contained in:
Alexey Andreev 2017-11-05 14:54:37 +03:00
parent bc51940ce1
commit 90e9792892
2 changed files with 37 additions and 28 deletions

View File

@ -68,6 +68,7 @@ public class DependencyChecker implements DependencyInfo {
private List<DependencyListener> listeners = new ArrayList<>(); private List<DependencyListener> listeners = new ArrayList<>();
private ServiceRepository services; private ServiceRepository services;
private Queue<Runnable> tasks = new ArrayDeque<>(); private Queue<Runnable> tasks = new ArrayDeque<>();
private Queue<Runnable> deferredTasks = new ArrayDeque<>();
List<DependencyType> types = new ArrayList<>(); List<DependencyType> types = new ArrayList<>();
private Map<String, DependencyType> typeMap = new HashMap<>(); private Map<String, DependencyType> typeMap = new HashMap<>();
private DependencyCheckerInterruptor interruptor; private DependencyCheckerInterruptor interruptor;
@ -199,7 +200,7 @@ public class DependencyChecker implements DependencyInfo {
dep.used = false; dep.used = false;
lock(dep, false); lock(dep, false);
tasks.add(() -> { deferredTasks.add(() -> {
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
graphBuilder.buildGraph(dep); graphBuilder.buildGraph(dep);
dep.used = true; dep.used = true;
@ -277,7 +278,7 @@ public class DependencyChecker implements DependencyInfo {
added = classesAddedByRoot.add(className); added = classesAddedByRoot.add(className);
} }
if (!dep.isMissing() && added) { if (!dep.isMissing() && added) {
tasks.add(() -> { deferredTasks.add(() -> {
for (DependencyListener listener : listeners) { for (DependencyListener listener : listeners) {
listener.classReached(agent, className, callLocation); listener.classReached(agent, className, callLocation);
} }
@ -352,7 +353,7 @@ public class DependencyChecker implements DependencyInfo {
ClassReader reader = cls.getClassReader(); ClassReader reader = cls.getClassReader();
MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class)); MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class));
if (method != null) { if (method != null) {
tasks.add(() -> linkMethod(method.getReference(), callLocation).use()); deferredTasks.add(() -> linkMethod(method.getReference(), callLocation).use());
} }
} }
@ -385,7 +386,7 @@ public class DependencyChecker implements DependencyInfo {
MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown, MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
method, methodRef); method, methodRef);
if (method != null) { if (method != null) {
tasks.add(() -> { deferredTasks.add(() -> {
CallLocation caller = new CallLocation(dep.getMethod().getReference()); CallLocation caller = new CallLocation(dep.getMethod().getReference());
linkClass(dep.getMethod().getOwnerName(), caller).initClass(caller); linkClass(dep.getMethod().getOwnerName(), caller).initClass(caller);
}); });
@ -394,7 +395,7 @@ public class DependencyChecker implements DependencyInfo {
} }
void scheduleMethodAnalysis(MethodDependency dep) { void scheduleMethodAnalysis(MethodDependency dep) {
tasks.add(() -> { deferredTasks.add(() -> {
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
graphBuilder.buildGraph(dep); graphBuilder.buildGraph(dep);
}); });
@ -429,7 +430,7 @@ public class DependencyChecker implements DependencyInfo {
} }
FieldDependency dep = fieldCache.map(fieldRef); FieldDependency dep = fieldCache.map(fieldRef);
if (!dep.isMissing()) { if (!dep.isMissing()) {
tasks.add(() -> linkClass(fieldRef.getClassName(), location).initClass(location)); deferredTasks.add(() -> linkClass(fieldRef.getClassName(), location).initClass(location));
} }
if (!dep.isMissing() && added) { if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) { for (DependencyListener listener : listeners) {
@ -508,6 +509,7 @@ public class DependencyChecker implements DependencyInfo {
return; return;
} }
int index = 0; int index = 0;
while (true) {
while (!tasks.isEmpty()) { while (!tasks.isEmpty()) {
tasks.poll().run(); tasks.poll().run();
if (++index == 100) { if (++index == 100) {
@ -518,6 +520,11 @@ public class DependencyChecker implements DependencyInfo {
index = 0; index = 0;
} }
} }
if (deferredTasks.isEmpty()) {
break;
}
deferredTasks.poll().run();
}
} }
public void processDependencies() { public void processDependencies() {

View File

@ -153,19 +153,7 @@ public class DependencyNode implements ValueDependencyInfo {
} }
followers.add(consumer); followers.add(consumer);
if (this.types != null) { propagateTypes(consumer, null);
List<DependencyType> types = new ArrayList<>();
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
types.add(dependencyChecker.types.get(index));
}
dependencyChecker.schedulePropagation(consumer, types.toArray(new DependencyType[types.size()]));
} else if (this.smallTypes != null) {
DependencyType[] types = new DependencyType[smallTypes.length];
for (int i = 0; i < types.length; ++i) {
types[i] = dependencyChecker.types.get(smallTypes[i]);
}
dependencyChecker.schedulePropagation(consumer, types);
}
} }
public void connect(DependencyNode node, DependencyTypeFilter filter) { public void connect(DependencyNode node, DependencyTypeFilter filter) {
@ -192,16 +180,30 @@ public class DependencyNode implements ValueDependencyInfo {
System.out.println("Connecting " + tag + " to " + node.tag); System.out.println("Connecting " + tag + " to " + node.tag);
} }
propagateTypes(transition, filter);
}
private void propagateTypes(DependencyConsumer transition, DependencyTypeFilter filter) {
if (this.types != null) { if (this.types != null) {
List<DependencyType> types = new ArrayList<>(); List<DependencyType> types = new ArrayList<>();
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) { for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
types.add(dependencyChecker.types.get(index)); DependencyType type = dependencyChecker.types.get(index);
if (filter == null || filter.match(type)) {
types.add(type);
}
} }
dependencyChecker.schedulePropagation(transition, types.toArray(new DependencyType[types.size()])); dependencyChecker.schedulePropagation(transition, types.toArray(new DependencyType[types.size()]));
} else if (this.smallTypes != null) { } else if (this.smallTypes != null) {
DependencyType[] types = new DependencyType[smallTypes.length]; DependencyType[] types = new DependencyType[smallTypes.length];
int j = 0;
for (int i = 0; i < types.length; ++i) { for (int i = 0; i < types.length; ++i) {
types[i] = dependencyChecker.types.get(smallTypes[i]); DependencyType type = dependencyChecker.types.get(smallTypes[i]);
if (filter == null || filter.match(type)) {
types[j++] = type;
}
}
if (j < types.length) {
types = Arrays.copyOf(types, j);
} }
dependencyChecker.schedulePropagation(transition, types); dependencyChecker.schedulePropagation(transition, types);
} }