Skip to content

Commit 663fae6

Browse files
authored
perf: Remove Unnecessary Recursion from Select/Update (deephaven#5924)
This reorganizes how select/update builds the resulting formula columns, column source maps, and work to be processed on the PUG. Instead of using recursion, it now builds things up in a dynamic-programming style without redoing work. As a result, select/update operations with thousands of columns now use significantly less memory and cpu to perform the same work. A simple 50k select-column update operation initializes in 2.5m (source starts empty and this is on an m2 mac) and has cycle times of ~650ms.
1 parent e919d52 commit 663fae6

27 files changed

+1146
-1219
lines changed

Util/src/main/java/io/deephaven/util/SimpleTypeMap.java

+41-2
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,56 @@
77

88
public final class SimpleTypeMap<V> {
99

10-
public static <V> SimpleTypeMap<V> create(V forBoolean, V forChar, V forByte, V forShort, V forInt, V forLong,
11-
V forFloat, V forDouble, V forObject) {
10+
/**
11+
* Create a mapping from type {@link Class classes} to a value.
12+
*
13+
* @param forBoolean The mapping for {@code boolean} types (<em>note</em> {@link Boolean} maps to {@code forObject})
14+
* @param forChar The mapping for {@code char} and {@link Character} types
15+
* @param forByte The mapping for {@code byte} and {@link Byte} types
16+
* @param forShort The mapping for {@code short} and {@link Short} types
17+
* @param forInt The mapping for {@code int} and {@link Integer} types
18+
* @param forLong The mapping for {@code long} and {@link Long} types
19+
* @param forFloat The mapping for {@code float} and {@link Float} types
20+
* @param forDouble The mapping for {@code double} and {@link Double} types
21+
* @param forObject The mapping for all other types
22+
* @return A SimpleTypeMap to the provided values
23+
*/
24+
public static <V> SimpleTypeMap<V> create(
25+
V forBoolean,
26+
V forChar,
27+
V forByte,
28+
V forShort,
29+
V forInt,
30+
V forLong,
31+
V forFloat,
32+
V forDouble,
33+
V forObject) {
1234
final HashMap<Class<?>, V> map = new HashMap<>();
35+
1336
map.put(boolean.class, forBoolean);
37+
// Note: Booleans are treated as Objects, unlike other boxed primitives
38+
1439
map.put(char.class, forChar);
40+
map.put(Character.class, forChar);
41+
1542
map.put(byte.class, forByte);
43+
map.put(Byte.class, forByte);
44+
1645
map.put(short.class, forShort);
46+
map.put(Short.class, forShort);
47+
1748
map.put(int.class, forInt);
49+
map.put(Integer.class, forInt);
50+
1851
map.put(long.class, forLong);
52+
map.put(Long.class, forLong);
53+
1954
map.put(float.class, forFloat);
55+
map.put(Float.class, forFloat);
56+
2057
map.put(double.class, forDouble);
58+
map.put(Double.class, forDouble);
59+
2160
return new SimpleTypeMap<>(map, forObject);
2261
}
2362

engine/table/src/main/java/io/deephaven/engine/table/impl/QueryCompilerRequestProcessor.java

+16-31
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
package io.deephaven.engine.table.impl;
55

66
import io.deephaven.UncheckedDeephavenException;
7-
import io.deephaven.api.util.NameValidator;
87
import io.deephaven.engine.context.ExecutionContext;
98
import io.deephaven.engine.context.QueryCompiler;
109
import io.deephaven.engine.context.QueryCompilerRequest;
11-
import io.deephaven.engine.context.QueryScope;
1210
import io.deephaven.engine.table.impl.perf.QueryPerformanceRecorder;
11+
import io.deephaven.engine.table.impl.select.codegen.FormulaAnalyzer;
1312
import io.deephaven.util.MultiException;
1413
import io.deephaven.util.SafeCloseable;
1514
import io.deephaven.util.CompletionStageFuture;
@@ -18,68 +17,60 @@
1817
import org.jetbrains.annotations.VisibleForTesting;
1918

2019
import java.util.ArrayList;
21-
import java.util.Collections;
2220
import java.util.List;
23-
import java.util.Map;
2421
import java.util.concurrent.ExecutionException;
2522
import java.util.concurrent.TimeUnit;
2623
import java.util.concurrent.TimeoutException;
2724

28-
public interface QueryCompilerRequestProcessor {
25+
public abstract class QueryCompilerRequestProcessor {
2926

3027
/**
3128
* @return An immediate QueryCompilerRequestProcessor
3229
*/
33-
static QueryCompilerRequestProcessor.ImmediateProcessor immediate() {
30+
public static QueryCompilerRequestProcessor.ImmediateProcessor immediate() {
3431
return new ImmediateProcessor();
3532
}
3633

3734
/**
3835
* @return A batch QueryCompilerRequestProcessor
3936
*/
40-
static QueryCompilerRequestProcessor.BatchProcessor batch() {
37+
public static QueryCompilerRequestProcessor.BatchProcessor batch() {
4138
return new BatchProcessor();
4239
}
4340

4441
/**
45-
* @return a CachingSupplier that supplies a snapshot of the current query scope variables
42+
* @return a CachingSupplier that supplies a snapshot of current query scope variables and query library imports
4643
*/
4744
@VisibleForTesting
48-
static CachingSupplier<Map<String, Object>> newQueryScopeVariableSupplier() {
49-
final QueryScope queryScope = ExecutionContext.getContext().getQueryScope();
50-
return new CachingSupplier<>(() -> Collections.unmodifiableMap(
51-
queryScope.toMap((name, value) -> NameValidator.isValidQueryParameterName(name))));
45+
public static CachingSupplier<FormulaAnalyzer.Imports> newFormulaImportsSupplier() {
46+
return new CachingSupplier<>(FormulaAnalyzer.Imports::new);
5247
}
5348

49+
private final CachingSupplier<FormulaAnalyzer.Imports> formulaImportsSupplier = newFormulaImportsSupplier();
50+
5451
/**
55-
* @return a lazily cached snapshot of the current query scope variables
52+
* @return a lazily cached snapshot of current query scope variables and query library imports
5653
*/
57-
Map<String, Object> getQueryScopeVariables();
54+
public final FormulaAnalyzer.Imports getFormulaImports() {
55+
return formulaImportsSupplier.get();
56+
}
5857

5958
/**
6059
* Submit a request for compilation. The QueryCompilerRequestProcessor is not required to immediately compile this
6160
* request.
6261
*
6362
* @param request the request to compile
6463
*/
65-
CompletionStageFuture<Class<?>> submit(@NotNull QueryCompilerRequest request);
64+
public abstract CompletionStageFuture<Class<?>> submit(@NotNull QueryCompilerRequest request);
6665

6766
/**
6867
* A QueryCompilerRequestProcessor that immediately compiles requests.
6968
*/
70-
class ImmediateProcessor implements QueryCompilerRequestProcessor {
71-
72-
private final CachingSupplier<Map<String, Object>> queryScopeVariableSupplier = newQueryScopeVariableSupplier();
73-
69+
public static class ImmediateProcessor extends QueryCompilerRequestProcessor {
7470
private ImmediateProcessor() {
7571
// force use of static factory method
7672
}
7773

78-
@Override
79-
public Map<String, Object> getQueryScopeVariables() {
80-
return queryScopeVariableSupplier.get();
81-
}
82-
8374
@Override
8475
public CompletionStageFuture<Class<?>> submit(@NotNull final QueryCompilerRequest request) {
8576
final String desc = "Compile: " + request.description();
@@ -108,20 +99,14 @@ public CompletionStageFuture<Class<?>> submit(@NotNull final QueryCompilerReques
10899
* <p>
109100
* The compile method must be called to actually compile the requests.
110101
*/
111-
class BatchProcessor implements QueryCompilerRequestProcessor {
102+
public static class BatchProcessor extends QueryCompilerRequestProcessor {
112103
private final List<QueryCompilerRequest> requests = new ArrayList<>();
113104
private final List<CompletionStageFuture.Resolver<Class<?>>> resolvers = new ArrayList<>();
114-
private final CachingSupplier<Map<String, Object>> queryScopeVariableSupplier = newQueryScopeVariableSupplier();
115105

116106
private BatchProcessor() {
117107
// force use of static factory method
118108
}
119109

120-
@Override
121-
public Map<String, Object> getQueryScopeVariables() {
122-
return queryScopeVariableSupplier.get();
123-
}
124-
125110
@Override
126111
public CompletionStageFuture<Class<?>> submit(@NotNull final QueryCompilerRequest request) {
127112
final CompletionStageFuture.Resolver<Class<?>> resolver = CompletionStageFuture.make();

0 commit comments

Comments
 (0)