Skip to content

Commit 65a2111

Browse files
Col-Ejus7n
andcommitted
Make prior parallelism work configurable (enabled by default)
Co-Authored-By: Justin <[email protected]>
1 parent 5964d0e commit 65a2111

File tree

7 files changed

+52
-11
lines changed

7 files changed

+52
-11
lines changed

recaf-core/src/main/java/software/coley/recaf/services/transform/TransformationApplier.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
public class TransformationApplier {
4545
private static final DebuggingLogger logger = Logging.get(TransformationApplier.class);
4646
private final TransformationManager transformationManager;
47+
private final TransformationApplierConfig transformApplyConfig;
4748
private final InheritanceGraph inheritanceGraph;
4849
private final MappingApplier mappingApplier;
4950
private final Workspace workspace;
@@ -52,6 +53,8 @@ public class TransformationApplier {
5253
/**
5354
* @param transformationManager
5455
* Manager to pull transformer instances from.
56+
* @param transformApplyConfig
57+
* Transformation applier config.
5558
* @param inheritanceGraph
5659
* Inheritance graph to use for frame computation <i>(Some transformers will trigger this)</i>.
5760
* @param mappingApplier
@@ -60,10 +63,12 @@ public class TransformationApplier {
6063
* Workspace with classes to transform.
6164
*/
6265
public TransformationApplier(@Nonnull TransformationManager transformationManager,
66+
@Nonnull TransformationApplierConfig transformApplyConfig,
6367
@Nonnull InheritanceGraph inheritanceGraph,
6468
@Nonnull MappingApplier mappingApplier,
6569
@Nonnull Workspace workspace) {
6670
this.transformationManager = transformationManager;
71+
this.transformApplyConfig = transformApplyConfig;
6772
this.inheritanceGraph = inheritanceGraph;
6873
this.mappingApplier = mappingApplier;
6974
this.workspace = workspace;
@@ -141,7 +146,9 @@ public JvmTransformResult transformJvm(@Nonnull List<Class<? extends JvmClassTra
141146
}
142147
AtomicInteger finalPass = new AtomicInteger();
143148
List<JvmClassTransformer> prunedTransformers = new ArrayList<>();
144-
try (ExecutorService service = ThreadPoolFactory.newFixedThreadPool("transform-apply")) {
149+
try (ExecutorService service = transformApplyConfig.doParallelize().getValue() ?
150+
ThreadPoolFactory.newFixedThreadPool("transform-apply") :
151+
ThreadPoolFactory.newSingleThreadExecutor("transform-apply")) {
145152
resource.jvmAllClassBundleStreamRecursive().forEach(bundle -> {
146153
List<Callable<Void>> tasks = new ArrayList<>(bundle.size());
147154
BundlePathNode bundlePathNode = resourcePath.child(bundle);

recaf-core/src/main/java/software/coley/recaf/services/transform/TransformationApplierConfig.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package software.coley.recaf.services.transform;
22

3+
import jakarta.annotation.Nonnull;
34
import jakarta.enterprise.context.ApplicationScoped;
45
import jakarta.inject.Inject;
6+
import software.coley.observables.ObservableBoolean;
57
import software.coley.recaf.config.BasicConfigContainer;
8+
import software.coley.recaf.config.BasicConfigValue;
69
import software.coley.recaf.config.ConfigGroups;
710
import software.coley.recaf.services.ServiceConfig;
811

@@ -13,8 +16,19 @@
1316
*/
1417
@ApplicationScoped
1518
public class TransformationApplierConfig extends BasicConfigContainer implements ServiceConfig {
19+
private final ObservableBoolean parallelize = new ObservableBoolean(true);
20+
1621
@Inject
1722
public TransformationApplierConfig() {
1823
super(ConfigGroups.SERVICE_TRANSFORM, TransformationApplierService.SERVICE_ID + CONFIG_SUFFIX);
24+
addValue(new BasicConfigValue<>("parallelize", boolean.class, parallelize));
25+
}
26+
27+
/**
28+
* @return {@code true} to enable parallelization of transformer applications.
29+
*/
30+
@Nonnull
31+
public ObservableBoolean doParallelize() {
32+
return parallelize;
1933
}
2034
}

recaf-core/src/main/java/software/coley/recaf/services/transform/TransformationApplierService.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ public class TransformationApplierService implements Service {
3232
private final MappingApplierService mappingService;
3333
private final WorkspaceManager workspaceManager;
3434
private final TransformationApplierConfig config;
35+
private final TransformationApplierConfig applierConfig;
3536

3637
@Inject
3738
public TransformationApplierService(@Nonnull TransformationManager transformationManager,
3839
@Nonnull InheritanceGraphService graphService,
39-
@Nonnull MappingApplierService mappingService,
40+
@Nonnull MappingApplierService mappingService,
4041
@Nonnull WorkspaceManager workspaceManager,
41-
@Nonnull TransformationApplierConfig config) {
42+
@Nonnull TransformationApplierConfig config,
43+
@Nonnull TransformationApplierConfig applierConfig) {
4244
this.graphService = graphService;
4345
this.mappingService = mappingService;
4446
this.workspaceManager = workspaceManager;
4547
this.transformationManager = transformationManager;
4648
this.config = config;
49+
this.applierConfig = applierConfig;
4750
}
4851

4952
/**
@@ -94,7 +97,7 @@ public TransformationApplier newApplierForCurrentWorkspace() {
9497
@Nonnull
9598
private TransformationApplier newApplier(@Nonnull Workspace workspace, @Nonnull InheritanceGraph inheritanceGraph,
9699
@Nonnull MappingApplier mappingApplier) {
97-
return new TransformationApplier(transformationManager, inheritanceGraph, mappingApplier, workspace);
100+
return new TransformationApplier(transformationManager, applierConfig, inheritanceGraph, mappingApplier, workspace);
98101
}
99102

100103
@Nonnull

recaf-core/src/main/java/software/coley/recaf/services/workspace/io/BasicResourceImporter.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ private WorkspaceFileResource handleZip(@Nonnull WorkspaceFileResourceBuilder bu
210210

211211
// Build model from the contained files in the ZIP
212212
int maxZipDepth = config.getMaxEmbeddedZipDepth().getValue();
213-
try (ExecutorService service = ThreadPoolFactory.newFixedThreadPool("zip-import")) {
213+
try (ExecutorService service = config.doParallelize().getValue() ?
214+
ThreadPoolFactory.newFixedThreadPool("zip-import") :
215+
ThreadPoolFactory.newSingleThreadExecutor("zip-import")) {
214216
List<Callable<Void>> tasks = new ArrayList<>();
215217
for (LocalFileHeader header : archive.getLocalFiles()) {
216218
tasks.add(() -> {
@@ -294,7 +296,9 @@ private WorkspaceDirectoryResource handleDirectory(@Nonnull WorkspaceResourceBui
294296
Map<String, WorkspaceFileResource> embeddedResources = new ConcurrentHashMap<>();
295297

296298
// Walk the directory
297-
try (ExecutorService service = ThreadPoolFactory.newFixedThreadPool("directory-import")) {
299+
try (ExecutorService service = config.doParallelize().getValue() ?
300+
ThreadPoolFactory.newFixedThreadPool("directory-import") :
301+
ThreadPoolFactory.newSingleThreadExecutor("directory-import")) {
298302
List<Callable<Void>> tasks = new ArrayList<>();
299303
Files.walkFileTree(directoryPath, new SimpleFileVisitor<>() {
300304
@Override

recaf-core/src/main/java/software/coley/recaf/services/workspace/io/ResourceImporterConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class ResourceImporterConfig extends BasicConfigContainer implements Serv
4242
private final ObservableBoolean ignoreFileLengths = new ObservableBoolean(false);
4343
private final ObservableBoolean adoptStandardCenFileNames = new ObservableBoolean(false);
4444
private final ObservableInteger maxEmbeddedZipDepth = new ObservableInteger(3);
45+
private final ObservableBoolean parallelize = new ObservableBoolean(true);
4546

4647
@Inject
4748
public ResourceImporterConfig() {
@@ -53,6 +54,7 @@ public ResourceImporterConfig() {
5354
addValue(new BasicConfigValue<>("ignore-file-lengths", boolean.class, ignoreFileLengths));
5455
addValue(new BasicConfigValue<>("adapt-standard-cen-file-names", boolean.class, adoptStandardCenFileNames));
5556
addValue(new BasicConfigValue<>("max-embedded-zip-depth", int.class, maxEmbeddedZipDepth));
57+
addValue(new BasicConfigValue<>("parallelize", boolean.class, parallelize));
5658
}
5759

5860
/**
@@ -121,6 +123,14 @@ public ObservableInteger getMaxEmbeddedZipDepth() {
121123
return maxEmbeddedZipDepth;
122124
}
123125

126+
/**
127+
* @return {@code true} to enable parallelization of import logic.
128+
*/
129+
@Nonnull
130+
public ObservableBoolean doParallelize() {
131+
return parallelize;
132+
}
133+
124134
/**
125135
* @return Mapping of input bytes to a ZIP archive model.
126136
*/

recaf-core/src/test/java/software/coley/recaf/services/transform/TransformationApplierTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void independentAB() {
5959

6060
// If we transform with "B" we should observe that only "B" is called on sine the two hold no relation
6161
TransformationManager manager = new TransformationManager(map);
62-
TransformationApplier applier = new TransformationApplier(manager, inheritanceGraph, mappingApplier, workspace);
62+
TransformationApplier applier = new TransformationApplier(manager, config, inheritanceGraph, mappingApplier, workspace);
6363
assertDoesNotThrow(() -> applier.transformJvm(Collections.singletonList(JvmTransformerB.class)));
6464

6565
// "A" not used
@@ -83,7 +83,7 @@ void dependentAB() {
8383

8484
// If we transform with "B" we should observe that both "B" and "A" were called on.
8585
TransformationManager manager = new TransformationManager(map);
86-
TransformationApplier applier = new TransformationApplier(manager, inheritanceGraph, mappingApplier, workspace);
86+
TransformationApplier applier = new TransformationApplier(manager, config, inheritanceGraph, mappingApplier, workspace);
8787
assertDoesNotThrow(() -> applier.transformJvm(Collections.singletonList(JvmTransformerDependingOnA.class)));
8888
verify(transformerA, times(1)).transform(any(), same(workspace), any(), any(), any());
8989
verify(transformerB, times(1)).transform(any(), same(workspace), any(), any(), any());
@@ -103,7 +103,7 @@ void cycleAB() {
103103

104104
// If we transform with "A" or "B" we should observe an exception due to the detected cycle
105105
TransformationManager manager = new TransformationManager(map);
106-
TransformationApplier applier = new TransformationApplier(manager, inheritanceGraph, mappingApplier, workspace);
106+
TransformationApplier applier = new TransformationApplier(manager, config, inheritanceGraph, mappingApplier, workspace);
107107
assertThrows(TransformationException.class, () -> applier.transformJvm(Collections.singletonList(JvmCycleA.class)));
108108
assertThrows(TransformationException.class, () -> applier.transformJvm(Collections.singletonList(JvmCycleB.class)));
109109
verify(transformerA, never()).transform(any(), same(workspace), any(), any(), any());
@@ -121,7 +121,7 @@ void cycleSingle() {
121121

122122
// If we transform with the single transformer we should observe an exception due to the detected cycle
123123
TransformationManager manager = new TransformationManager(map);
124-
TransformationApplier applier = new TransformationApplier(manager, inheritanceGraph, mappingApplier, workspace);
124+
TransformationApplier applier = new TransformationApplier(manager, config, inheritanceGraph, mappingApplier, workspace);
125125
assertThrows(TransformationException.class, () -> applier.transformJvm(Collections.singletonList(JvmCycleSingle.class)));
126126
verify(transformer, never()).transform(any(), same(workspace), any(), any(), any());
127127
}
@@ -130,7 +130,7 @@ void cycleSingle() {
130130
void missingRegistration() {
131131
// If we transform with a transformer that is not registered in the manager, the transform should fail
132132
TransformationManager manager = new TransformationManager(Collections.emptyMap());
133-
TransformationApplier applier = new TransformationApplier(manager, inheritanceGraph, mappingApplier, workspace);
133+
TransformationApplier applier = new TransformationApplier(manager, config, inheritanceGraph, mappingApplier, workspace);
134134
assertThrows(TransformationException.class, () -> applier.transformJvm(Collections.singletonList(JvmCycleSingle.class)));
135135
}
136136

recaf-ui/src/main/resources/translations/en_US.lang

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,7 @@ service.io.resource-importer-config.skip-revisited-cen-to-local-links=Skip dupli
808808
service.io.resource-importer-config.ignore-file-lengths=Ignore reported file lengths with Naive/Standard strategy
809809
service.io.resource-importer-config.adapt-standard-cen-file-names=Adopt CEN file names with Standard strategy
810810
service.io.resource-importer-config.max-embedded-zip-depth=Max embedded zip traversal depth
811+
service.io.resource-importer-config.parallelize=Enable multi-core input reading
811812
service.mapping=Mapping
812813
service.mapping.mapping-aggregator-config=Mapping aggregation
813814
service.mapping.mapping-formats-config=Mapping formats
@@ -821,6 +822,8 @@ service.plugin.plugin-manager-config=Plugin manager
821822
service.plugin.plugin-manager-config.scan-on-start=Load on startup
822823
service.plugin.script-manager-config=Script manager
823824
service.plugin.script-manager-config.file-watching=Passively scan scripts directory for changes
825+
service.transform.transformation-applier-config=Transformation Application
826+
service.transform.transformation-applier-config.parallelize=Enable multi-core transformer application
824827
service.ui=User interface
825828
service.ui.bind-config=Bindings
826829
service.ui.bind-config.bundle=Binding map bundle

0 commit comments

Comments
 (0)