未验证 提交 a61ebaaa 编写于 作者: S Skylot

fix: sum only sub dependencies in batches build (#1376)

上级 7a5a2fcd
...@@ -758,6 +758,10 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN ...@@ -758,6 +758,10 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
this.codegenDeps = codegenDeps; this.codegenDeps = codegenDeps;
} }
public int getTotalDepsCount() {
return dependencies.size() + codegenDeps.size();
}
public List<ClassNode> getUseIn() { public List<ClassNode> getUseIn() {
return useIn; return useIn;
} }
......
...@@ -3,11 +3,10 @@ package jadx.core.utils; ...@@ -3,11 +3,10 @@ package jadx.core.utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -33,16 +32,21 @@ public class DecompilerScheduler implements IDecompileScheduler { ...@@ -33,16 +32,21 @@ public class DecompilerScheduler implements IDecompileScheduler {
@Override @Override
public List<List<JavaClass>> buildBatches(List<JavaClass> classes) { public List<List<JavaClass>> buildBatches(List<JavaClass> classes) {
long start = System.currentTimeMillis(); try {
List<List<ClassNode>> batches = internalBatches(Utils.collectionMap(classes, JavaClass::getClassNode)); long start = System.currentTimeMillis();
List<List<JavaClass>> result = Utils.collectionMap(batches, l -> Utils.collectionMapNoNull(l, decompiler::getJavaClassByNode)); List<List<ClassNode>> batches = internalBatches(Utils.collectionMap(classes, JavaClass::getClassNode));
if (LOG.isDebugEnabled()) { List<List<JavaClass>> result = Utils.collectionMap(batches, l -> Utils.collectionMapNoNull(l, decompiler::getJavaClassByNode));
LOG.debug("Build decompilation batches in {}ms", System.currentTimeMillis() - start); if (LOG.isDebugEnabled()) {
} LOG.debug("Build decompilation batches in {}ms", System.currentTimeMillis() - start);
if (DEBUG_BATCHES) { }
check(result, classes); if (DEBUG_BATCHES) {
check(result, classes);
}
return result;
} catch (Throwable e) {
LOG.warn("Build batches failed (continue with fallback)", e);
return buildFallback(classes);
} }
return result;
} }
/** /**
...@@ -50,17 +54,9 @@ public class DecompilerScheduler implements IDecompileScheduler { ...@@ -50,17 +54,9 @@ public class DecompilerScheduler implements IDecompileScheduler {
* Build batches for dependencies of single class to avoid locking from another thread. * Build batches for dependencies of single class to avoid locking from another thread.
*/ */
public List<List<ClassNode>> internalBatches(List<ClassNode> classes) { public List<List<ClassNode>> internalBatches(List<ClassNode> classes) {
Map<ClassNode, DepInfo> depsMap = new HashMap<>(classes.size()); List<DepInfo> deps = sumDependencies(classes);
Set<ClassNode> visited = new HashSet<>();
for (ClassNode classNode : classes) {
visited.clear();
sumDeps(classNode, depsMap, visited);
}
List<DepInfo> deps = new ArrayList<>(depsMap.values());
Collections.sort(deps);
Set<ClassNode> added = new HashSet<>(classes.size()); Set<ClassNode> added = new HashSet<>(classes.size());
Comparator<ClassNode> cmpDepSize = Comparator.comparingInt(c -> c.getDependencies().size()); Comparator<ClassNode> cmpDepSize = Comparator.comparingInt(ClassNode::getTotalDepsCount);
List<List<ClassNode>> result = new ArrayList<>(); List<List<ClassNode>> result = new ArrayList<>();
List<ClassNode> mergedBatch = new ArrayList<>(MERGED_BATCH_SIZE); List<ClassNode> mergedBatch = new ArrayList<>(MERGED_BATCH_SIZE);
for (DepInfo depInfo : deps) { for (DepInfo depInfo : deps) {
...@@ -68,7 +64,7 @@ public class DecompilerScheduler implements IDecompileScheduler { ...@@ -68,7 +64,7 @@ public class DecompilerScheduler implements IDecompileScheduler {
if (!added.add(cls)) { if (!added.add(cls)) {
continue; continue;
} }
int depsSize = cls.getDependencies().size(); int depsSize = cls.getTotalDepsCount();
if (depsSize == 0) { if (depsSize == 0) {
// add classes without dependencies in merged batch // add classes without dependencies in merged batch
mergedBatch.add(cls); mergedBatch.add(cls);
...@@ -99,21 +95,17 @@ public class DecompilerScheduler implements IDecompileScheduler { ...@@ -99,21 +95,17 @@ public class DecompilerScheduler implements IDecompileScheduler {
return result; return result;
} }
public int sumDeps(ClassNode cls, Map<ClassNode, DepInfo> depsMap, Set<ClassNode> visited) { private static List<DepInfo> sumDependencies(List<ClassNode> classes) {
visited.add(cls); List<DepInfo> deps = new ArrayList<>(classes.size());
DepInfo depInfo = depsMap.get(cls); for (ClassNode cls : classes) {
if (depInfo != null) { int count = 0;
return depInfo.getDepsCount(); for (ClassNode dep : cls.getDependencies()) {
} count += 1 + dep.getTotalDepsCount();
List<ClassNode> deps = cls.getDependencies();
int count = deps.size();
for (ClassNode dep : deps) {
if (!visited.contains(dep)) {
count += sumDeps(dep, depsMap, visited);
} }
deps.add(new DepInfo(cls, count));
} }
depsMap.put(cls, new DepInfo(cls, count)); Collections.sort(deps);
return count; return deps;
} }
private static final class DepInfo implements Comparable<DepInfo> { private static final class DepInfo implements Comparable<DepInfo> {
...@@ -135,20 +127,36 @@ public class DecompilerScheduler implements IDecompileScheduler { ...@@ -135,20 +127,36 @@ public class DecompilerScheduler implements IDecompileScheduler {
@Override @Override
public int compareTo(@NotNull DecompilerScheduler.DepInfo o) { public int compareTo(@NotNull DecompilerScheduler.DepInfo o) {
return Integer.compare(depsCount, o.depsCount); int deps = Integer.compare(depsCount, o.depsCount);
if (deps == 0) {
return cls.compareTo(o.cls);
}
return deps;
}
@Override
public String toString() {
return cls + ":" + depsCount;
} }
} }
private static List<List<JavaClass>> buildFallback(List<JavaClass> classes) {
return classes.stream()
.sorted(Comparator.comparingInt(c -> c.getClassNode().getTotalDepsCount()))
.map(Collections::singletonList)
.collect(Collectors.toList());
}
private void dumpBatchesStats(List<ClassNode> classes, List<List<ClassNode>> result, List<DepInfo> deps) { private void dumpBatchesStats(List<ClassNode> classes, List<List<ClassNode>> result, List<DepInfo> deps) {
double avg = result.stream().mapToInt(List::size).average().orElse(-1); double avg = result.stream().mapToInt(List::size).average().orElse(-1);
int maxSingleDeps = classes.stream().mapToInt(c -> c.getDependencies().size()).max().orElse(-1); int maxSingleDeps = classes.stream().mapToInt(ClassNode::getTotalDepsCount).max().orElse(-1);
int maxRecursiveDeps = deps.stream().mapToInt(DepInfo::getDepsCount).max().orElse(-1); int maxSubDeps = deps.stream().mapToInt(DepInfo::getDepsCount).max().orElse(-1);
LOG.info("Batches stats:" LOG.info("Batches stats:"
+ "\n input classes: " + classes.size() + "\n input classes: " + classes.size()
+ ",\n batches: " + result.size() + ",\n batches: " + result.size()
+ ",\n average batch size: " + String.format("%.2f", avg) + ",\n average batch size: " + String.format("%.2f", avg)
+ ",\n max single deps count: " + maxSingleDeps + ",\n max single deps count: " + maxSingleDeps
+ ",\n max recursive deps count: " + maxRecursiveDeps); + ",\n max sub deps count: " + maxSubDeps);
} }
private static void check(List<List<JavaClass>> result, List<JavaClass> classes) { private static void check(List<List<JavaClass>> result, List<JavaClass> classes) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册