Skip to content

Commit 091ed9d

Browse files
committed
Add simd support detection logic
1 parent 4e425ed commit 091ed9d

File tree

7 files changed

+249
-1
lines changed

7 files changed

+249
-1
lines changed

core/trino-main/pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,4 +556,29 @@
556556
<scope>test</scope>
557557
</dependency>
558558
</dependencies>
559+
560+
<build>
561+
<pluginManagement>
562+
<plugins>
563+
<plugin>
564+
<groupId>org.apache.maven.plugins</groupId>
565+
<artifactId>maven-compiler-plugin</artifactId>
566+
<configuration>
567+
<!-- Ensure incubator Vector API is on the module path for javac -->
568+
<compilerArgs combine.self="merge">
569+
<arg>${extraJavaVectorArgs}</arg>
570+
</compilerArgs>
571+
</configuration>
572+
</plugin>
573+
<plugin>
574+
<groupId>org.apache.maven.plugins</groupId>
575+
<artifactId>maven-javadoc-plugin</artifactId>
576+
<configuration>
577+
<!-- Ensure javadoc resolves incubator Vector API -->
578+
<additionalOptions combine.self="merge">${extraJavaVectorArgs}</additionalOptions>
579+
</configuration>
580+
</plugin>
581+
</plugins>
582+
</pluginManagement>
583+
</build>
559584
</project>

core/trino-main/src/main/java/io/trino/FeaturesConfig.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public class FeaturesConfig
9494
* default value is overwritten for fault tolerant execution in {@link #applyFaultTolerantExecutionDefaults()}}
9595
*/
9696
private CompressionCodec exchangeCompressionCodec = NONE;
97+
private BlockSerdeVectorizedNullSuppressionStrategy blockSerdeVectorizedNullSuppressionStrategy = BlockSerdeVectorizedNullSuppressionStrategy.AUTO;
9798
private boolean pagesIndexEagerCompactionEnabled;
9899
private boolean omitDateTimeTypePrecision;
99100
private int maxRecursionDepth = 10;
@@ -133,6 +134,12 @@ public enum DataIntegrityVerification
133134
/**/;
134135
}
135136

137+
public enum BlockSerdeVectorizedNullSuppressionStrategy
138+
{
139+
AUTO,
140+
NONE,
141+
}
142+
136143
public boolean isOmitDateTimeTypePrecision()
137144
{
138145
return omitDateTimeTypePrecision;
@@ -366,6 +373,19 @@ public FeaturesConfig setExchangeCompressionCodec(CompressionCodec exchangeCompr
366373
return this;
367374
}
368375

376+
@Config("experimental.blockserde-vectorized-null-suppression-strategy")
377+
@ConfigDescription("Strategy used for vectorized null suppression in block serde")
378+
public FeaturesConfig setBlockSerdeVectorizedNullSuppressionStrategy(BlockSerdeVectorizedNullSuppressionStrategy blockSerdeVectorizedNullSuppressionStrategy)
379+
{
380+
this.blockSerdeVectorizedNullSuppressionStrategy = blockSerdeVectorizedNullSuppressionStrategy;
381+
return this;
382+
}
383+
384+
public BlockSerdeVectorizedNullSuppressionStrategy getBlockSerdeVectorizedNullSuppressionStrategy()
385+
{
386+
return blockSerdeVectorizedNullSuppressionStrategy;
387+
}
388+
369389
public DataIntegrityVerification getExchangeDataIntegrityVerification()
370390
{
371391
return exchangeDataIntegrityVerification;

core/trino-main/src/main/java/io/trino/server/ServerMainModule.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import io.trino.server.protocol.PreparedStatementEncoder;
101101
import io.trino.server.protocol.spooling.SpoolingServerModule;
102102
import io.trino.server.remotetask.HttpLocationFactory;
103+
import io.trino.simd.BlockEncodingSimdSupport;
103104
import io.trino.spi.PageIndexerFactory;
104105
import io.trino.spi.PageSorter;
105106
import io.trino.spi.VersionEmbedder;
@@ -427,6 +428,9 @@ protected void setup(Binder binder)
427428
.to(ServerPluginsProvider.class).in(Scopes.SINGLETON);
428429
configBinder(binder).bindConfig(ServerPluginsProviderConfig.class);
429430

431+
// SIMD support
432+
binder.bind(BlockEncodingSimdSupport.class).in(Scopes.SINGLETON);
433+
430434
// block encodings
431435
binder.bind(BlockEncodingManager.class).in(Scopes.SINGLETON);
432436
jsonBinder(binder).addSerializerBinding(Block.class).to(BlockJsonSerde.Serializer.class);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.simd;
15+
16+
import com.google.inject.Inject;
17+
import com.google.inject.Singleton;
18+
import io.trino.FeaturesConfig;
19+
import io.trino.spi.SimdSupport;
20+
import io.trino.util.MachineInfo;
21+
import jdk.incubator.vector.ByteVector;
22+
import jdk.incubator.vector.IntVector;
23+
import jdk.incubator.vector.LongVector;
24+
import jdk.incubator.vector.ShortVector;
25+
import oshi.hardware.CentralProcessor.ProcessorIdentifier;
26+
27+
import java.util.EnumSet;
28+
import java.util.Set;
29+
30+
import static io.trino.FeaturesConfig.BlockSerdeVectorizedNullSuppressionStrategy.AUTO;
31+
import static io.trino.util.MachineInfo.readCpuFlags;
32+
import static java.util.Locale.ENGLISH;
33+
34+
@Singleton
35+
public final class BlockEncodingSimdSupport
36+
{
37+
public static final int MINIMUM_SIMD_LENGTH = 512;
38+
private final SimdSupport simdSupport;
39+
private static final SimdSupport AUTO_DETECTED_SUPPORT = detectSimd();
40+
41+
@Inject
42+
public BlockEncodingSimdSupport(
43+
FeaturesConfig featuresConfig)
44+
{
45+
this(featuresConfig.getBlockSerdeVectorizedNullSuppressionStrategy().equals(AUTO));
46+
}
47+
48+
public BlockEncodingSimdSupport(
49+
boolean enableAutoDetectedSimdSupport)
50+
{
51+
if (enableAutoDetectedSimdSupport) {
52+
simdSupport = AUTO_DETECTED_SUPPORT;
53+
}
54+
else {
55+
simdSupport = SimdSupport.NONE;
56+
}
57+
}
58+
59+
private static SimdSupport detectSimd()
60+
{
61+
ProcessorIdentifier id = MachineInfo.getProcessorInfo();
62+
63+
String vendor = id.getVendor().toLowerCase(ENGLISH);
64+
65+
if (vendor.contains("intel") || vendor.contains("amd")) {
66+
return detectX86SimdSupport();
67+
}
68+
69+
return SimdSupport.NONE;
70+
}
71+
72+
private static SimdSupport detectX86SimdSupport()
73+
{
74+
enum X86SimdInstructionSet {
75+
avx512f,
76+
avx512vbmi2
77+
}
78+
79+
Set<String> flags = readCpuFlags();
80+
EnumSet<X86SimdInstructionSet> x86Flags = EnumSet.noneOf(X86SimdInstructionSet.class);
81+
82+
if (!flags.isEmpty()) {
83+
for (X86SimdInstructionSet instructionSet : X86SimdInstructionSet.values()) {
84+
if (flags.contains(instructionSet.name())) {
85+
x86Flags.add(instructionSet);
86+
}
87+
}
88+
}
89+
90+
return new SimdSupport(
91+
(ByteVector.SPECIES_PREFERRED.vectorBitSize() >= MINIMUM_SIMD_LENGTH) && (x86Flags.contains(X86SimdInstructionSet.avx512vbmi2)),
92+
(ShortVector.SPECIES_PREFERRED.vectorBitSize() >= MINIMUM_SIMD_LENGTH) && (x86Flags.contains(X86SimdInstructionSet.avx512vbmi2)),
93+
(IntVector.SPECIES_PREFERRED.vectorBitSize() >= MINIMUM_SIMD_LENGTH) && (x86Flags.contains(X86SimdInstructionSet.avx512f)),
94+
(LongVector.SPECIES_PREFERRED.vectorBitSize() >= MINIMUM_SIMD_LENGTH) && (x86Flags.contains(X86SimdInstructionSet.avx512f)));
95+
}
96+
}

core/trino-main/src/main/java/io/trino/util/MachineInfo.java

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,25 @@
1414
package io.trino.util;
1515

1616
import com.google.common.base.StandardSystemProperty;
17+
import com.google.common.collect.ImmutableSet;
1718
import oshi.SystemInfo;
19+
import oshi.hardware.CentralProcessor;
20+
import oshi.hardware.CentralProcessor.ProcessorIdentifier;
1821

22+
import java.util.Arrays;
23+
import java.util.HashSet;
24+
import java.util.List;
25+
import java.util.Set;
26+
27+
import static com.google.common.collect.ImmutableSet.toImmutableSet;
1928
import static java.lang.Math.min;
29+
import static java.util.Locale.ENGLISH;
2030

2131
public final class MachineInfo
2232
{
2333
// cache physical processor count, so that it's not queried multiple times during tests
2434
private static volatile int physicalProcessorCount = -1;
35+
private static final SystemInfo SYSTEM_INFO = new SystemInfo();
2536

2637
private MachineInfo() {}
2738

@@ -38,7 +49,7 @@ public static int getAvailablePhysicalProcessorCount()
3849
if ("amd64".equals(osArch) || "x86_64".equals(osArch)) {
3950
// Oshi can recognize physical processor count (without hyper threading) for x86 platforms.
4051
// However, it doesn't correctly recognize physical processor count for ARM platforms.
41-
totalPhysicalProcessorCount = new SystemInfo()
52+
totalPhysicalProcessorCount = SYSTEM_INFO
4253
.getHardware()
4354
.getProcessor()
4455
.getPhysicalProcessorCount();
@@ -52,4 +63,68 @@ public static int getAvailablePhysicalProcessorCount()
5263
physicalProcessorCount = min(totalPhysicalProcessorCount, availableProcessorCount);
5364
return physicalProcessorCount;
5465
}
66+
67+
public static ProcessorIdentifier getProcessorInfo()
68+
{
69+
return SYSTEM_INFO.getHardware().getProcessor().getProcessorIdentifier();
70+
}
71+
72+
public static Set<String> readCpuFlags()
73+
{
74+
CentralProcessor cpu = SYSTEM_INFO.getHardware().getProcessor();
75+
List<String> flags = cpu.getFeatureFlags();
76+
if (flags == null || flags.isEmpty()) {
77+
return ImmutableSet.of();
78+
}
79+
// Each element of flags represents the hardware support for an individual core, so we're want to calculate flags
80+
// advertised by all cores
81+
Set<String> intersection = null;
82+
83+
for (String line : flags) {
84+
if (line == null || line.isBlank()) {
85+
continue;
86+
}
87+
88+
// Strip the "flags:" / "Features:" prefix if present.
89+
String body = line;
90+
int colon = line.indexOf(':');
91+
if (colon >= 0) {
92+
body = line.substring(colon + 1);
93+
}
94+
95+
// Tokenize + normalize.
96+
Set<String> tokens = Arrays.stream(body.trim().split("\\s+"))
97+
.map(token -> normalizeFlag(token))
98+
.filter(token -> !token.isEmpty())
99+
.collect(toImmutableSet());
100+
101+
if (tokens.isEmpty()) {
102+
continue;
103+
}
104+
105+
if (intersection == null) {
106+
intersection = new HashSet<>(tokens);
107+
}
108+
else {
109+
intersection.retainAll(tokens);
110+
if (intersection.isEmpty()) {
111+
break; // nothing in common
112+
}
113+
}
114+
}
115+
116+
return intersection == null ? ImmutableSet.of() : intersection;
117+
}
118+
119+
public static String normalizeFlag(String flag)
120+
{
121+
flag = flag.toLowerCase(ENGLISH).replace("_", "").trim();
122+
123+
// Skip stray keys that may sneak in if the colon wasn’t found.
124+
if (flag.equals("flags") || flag.equals("features")) {
125+
return "";
126+
}
127+
128+
return flag;
129+
}
55130
}

core/trino-main/src/test/java/io/trino/sql/analyzer/TestFeaturesConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.common.collect.ImmutableMap;
1818
import io.airlift.units.DataSize;
1919
import io.trino.FeaturesConfig;
20+
import io.trino.FeaturesConfig.BlockSerdeVectorizedNullSuppressionStrategy;
2021
import io.trino.FeaturesConfig.DataIntegrityVerification;
2122
import org.junit.jupiter.api.Test;
2223

@@ -54,6 +55,7 @@ public void testDefaults()
5455
.setMemoryRevokingThreshold(0.9)
5556
.setMemoryRevokingTarget(0.5)
5657
.setExchangeCompressionCodec(NONE)
58+
.setBlockSerdeVectorizedNullSuppressionStrategy(BlockSerdeVectorizedNullSuppressionStrategy.AUTO)
5759
.setExchangeDataIntegrityVerification(DataIntegrityVerification.ABORT)
5860
.setPagesIndexEagerCompactionEnabled(false)
5961
.setFilterAndProjectMinOutputPageSize(DataSize.of(500, KILOBYTE))
@@ -89,6 +91,7 @@ public void testExplicitPropertyMappings()
8991
.put("memory-revoking-threshold", "0.2")
9092
.put("memory-revoking-target", "0.8")
9193
.put("exchange.compression-codec", "ZSTD")
94+
.put("experimental.blockserde-vectorized-null-suppression-strategy", "NONE")
9295
.put("exchange.data-integrity-verification", "RETRY")
9396
.put("pages-index.eager-compaction-enabled", "true")
9497
.put("filter-and-project-min-output-page-size", "1MB")
@@ -121,6 +124,7 @@ public void testExplicitPropertyMappings()
121124
.setMemoryRevokingThreshold(0.2)
122125
.setMemoryRevokingTarget(0.8)
123126
.setExchangeCompressionCodec(ZSTD)
127+
.setBlockSerdeVectorizedNullSuppressionStrategy(BlockSerdeVectorizedNullSuppressionStrategy.NONE)
124128
.setExchangeDataIntegrityVerification(DataIntegrityVerification.RETRY)
125129
.setPagesIndexEagerCompactionEnabled(true)
126130
.setFilterAndProjectMinOutputPageSize(DataSize.of(1, MEGABYTE))
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.spi;
15+
16+
public record SimdSupport(
17+
boolean expandAndCompressByte,
18+
boolean expandAndCompressShort,
19+
boolean expandAndCompressInt,
20+
boolean expandAndCompressLong)
21+
{
22+
public static final SimdSupport NONE = new SimdSupport(false, false, false, false);
23+
public static final SimdSupport ALL = new SimdSupport(true, true, true, true);
24+
}

0 commit comments

Comments
 (0)