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

View File

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