diff --git a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java index 5bc0019e723d..43a1bb3413c7 100644 --- a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java +++ b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java @@ -168,7 +168,15 @@ public class SqlExpressionBenchmark extends SqlBaseQueryBenchmark // 61-63: cast "SELECT CAST(string1 as BIGINT) + CAST(string3 as DOUBLE) + long3, COUNT(*) FROM expressions GROUP BY 1 ORDER BY 2", "SELECT COUNT(*), SUM(CAST(string1 as BIGINT) + CAST(string3 as BIGINT)) FROM expressions WHERE double3 < 1010.0 AND double3 > 100.0", - "SELECT COUNT(*) FROM expressions WHERE __time >= TIMESTAMP '2000-01-01 00:00:00' AND __time < TIMESTAMP '2000-01-02 00:00:00' AND (UPPER(COALESCE(string3,'')) LIKE '1%' OR TRIM(UPPER(COALESCE(string3,''))) LIKE '1%' OR SUBSTRING(UPPER(COALESCE(string3,'')),1,1) IN ('1','2','3','4','5') OR ('X' || UPPER(COALESCE(string3,''))) LIKE 'X1%') AND (UPPER(COALESCE(string5,'')) LIKE '2%' OR TRIM(UPPER(COALESCE(string5,''))) LIKE '2%' OR SUBSTRING(UPPER(COALESCE(string5,'')),1,1) IN ('1','2','3','4','5') OR ('Y' || UPPER(COALESCE(string5,''))) LIKE 'Y2%') AND CAST(double4 * 1000 AS BIGINT) BETWEEN -850000000 AND 850000000" + "SELECT COUNT(*) FROM expressions WHERE __time >= TIMESTAMP '2000-01-01 00:00:00' AND __time < TIMESTAMP '2000-01-02 00:00:00' AND (UPPER(COALESCE(string3,'')) LIKE '1%' OR TRIM(UPPER(COALESCE(string3,''))) LIKE '1%' OR SUBSTRING(UPPER(COALESCE(string3,'')),1,1) IN ('1','2','3','4','5') OR ('X' || UPPER(COALESCE(string3,''))) LIKE 'X1%') AND (UPPER(COALESCE(string5,'')) LIKE '2%' OR TRIM(UPPER(COALESCE(string5,''))) LIKE '2%' OR SUBSTRING(UPPER(COALESCE(string5,'')),1,1) IN ('1','2','3','4','5') OR ('Y' || UPPER(COALESCE(string5,''))) LIKE 'Y2%') AND CAST(double4 * 1000 AS BIGINT) BETWEEN -850000000 AND 850000000", + // 64,65: unary negate on a double column (companion to 15 which does long negate) + "SELECT SUM(-double1) FROM expressions", + "SELECT SUM(-double4) FROM expressions", + // 66,67: unary abs on long and double columns + "SELECT SUM(ABS(long4)) FROM expressions", + "SELECT SUM(ABS(double1)) FROM expressions", + // 68: unary abs of a binary subtraction (composes SIMD sub with SIMD abs) + "SELECT SUM(ABS(long1 - long4)) FROM expressions" ); @Param({ @@ -248,7 +256,12 @@ public class SqlExpressionBenchmark extends SqlBaseQueryBenchmark "60", "61", "62", - "63" + "63", + "64", + "65", + "66", + "67", + "68" }) private String query; diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateProcessorFactory.java b/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateProcessorFactory.java index 8c1c041b123f..581de8a6c639 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateProcessorFactory.java +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/SimpleVectorMathUnivariateProcessorFactory.java @@ -20,32 +20,56 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.Expr; +import org.apache.druid.math.expr.ExpressionProcessing; import org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction; import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction; +import org.apache.druid.math.expr.vector.simd.SimdProcessors; +import org.apache.druid.math.expr.vector.simd.SimdSupportedUnaryOp; + +import javax.annotation.Nullable; /** * Make a 1 argument math processor with the following type rules * long -> long * double -> double - * using simple scalar functions {@link LongUnivariateLongFunction} and {@link DoubleUnivariateDoubleFunction} + * using simple scalar functions {@link LongUnivariateLongFunction} and {@link DoubleUnivariateDoubleFunction}. + * + * If a non-null {@link SimdSupportedUnaryOp} is supplied to the constructor and + * {@link ExpressionProcessing#useVectorApi()} is true, this factory will return SIMD-specialized processors backed + * by the JDK incubator {@code jdk.incubator.vector} API instead of the standard scalar implementations. */ public class SimpleVectorMathUnivariateProcessorFactory extends VectorMathUnivariateProcessorFactory { private final LongUnivariateLongFunction longFunction; private final DoubleUnivariateDoubleFunction doubleFunction; + @Nullable + private final SimdSupportedUnaryOp simdOp; public SimpleVectorMathUnivariateProcessorFactory( LongUnivariateLongFunction longFunction, DoubleUnivariateDoubleFunction doubleFunction ) + { + this(longFunction, doubleFunction, null); + } + + protected SimpleVectorMathUnivariateProcessorFactory( + LongUnivariateLongFunction longFunction, + DoubleUnivariateDoubleFunction doubleFunction, + @Nullable SimdSupportedUnaryOp simdOp + ) { this.longFunction = longFunction; this.doubleFunction = doubleFunction; + this.simdOp = simdOp; } @Override public final ExprVectorProcessor longProcessor(Expr.VectorInputBindingInspector inspector, Expr arg) { + if (simdOp != null && ExpressionProcessing.useVectorApi()) { + return SimdProcessors.makeLongUnary(arg.asVectorProcessor(inspector), simdOp, longFunction); + } return new LongUnivariateLongFunctionVectorProcessor( arg.asVectorProcessor(inspector), longFunction @@ -55,6 +79,9 @@ public final ExprVectorProcessor longProcessor(Expr.VectorInputBindingIn @Override public final ExprVectorProcessor doubleProcessor(Expr.VectorInputBindingInspector inspector, Expr arg) { + if (simdOp != null && ExpressionProcessing.useVectorApi()) { + return SimdProcessors.makeDoubleUnary(arg.asVectorProcessor(inspector), simdOp, doubleFunction); + } return new DoubleUnivariateDoubleFunctionVectorProcessor( arg.asVectorProcessor(inspector), doubleFunction diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java index 3b4f3b8cb30e..17b9a629fafe 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java @@ -24,6 +24,7 @@ import org.apache.druid.math.expr.ExpressionValidationException; import org.apache.druid.math.expr.Function; import org.apache.druid.math.expr.vector.simd.SimdSupportedBinaryOp; +import org.apache.druid.math.expr.vector.simd.SimdSupportedUnaryOp; public class VectorMathProcessors { @@ -411,7 +412,8 @@ public Negate() { super( input -> -input, - input -> -input + input -> -input, + SimdSupportedUnaryOp.NEG ); } } @@ -542,7 +544,7 @@ public static final class Abs extends SimpleVectorMathUnivariateProcessorFactory public Abs() { - super(Math::abs, Math::abs); + super(Math::abs, Math::abs, SimdSupportedUnaryOp.ABS); } } diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleAbsProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleAbsProcessor.java new file mode 100644 index 000000000000..d11aecf3b71e --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleAbsProcessor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.DoubleVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction; + +import java.util.Arrays; + +/** + * SIMD specialization of {@code (double[]) -> double[]} absolute value. The op is hardcoded to + * {@link DoubleVector#abs} so the JIT statically resolves it to the platform's double-abs intrinsic. + */ +public final class SimdDoubleAbsProcessor extends SimdDoubleUnaryProcessor +{ + public SimdDoubleAbsProcessor(ExprVectorProcessor input, DoubleUnivariateDoubleFunction scalarFallback) + { + super(input, scalarFallback); + } + + @Override + protected void processVector(double[] input, boolean[] inputNulls, int currentSize) + { + final int laneCount = SPECIES.length(); + final int upperBound = SPECIES.loopBound(currentSize); + int i = 0; + for (; i < upperBound; i += laneCount) { + DoubleVector.fromArray(SPECIES, input, i).abs().intoArray(outValues, i); + } + for (; i < currentSize; i++) { + outValues[i] = scalarFallback.process(input[i]); + } + if (inputNulls == null) { + Arrays.fill(outNulls, 0, currentSize, false); + } else { + System.arraycopy(inputNulls, 0, outNulls, 0, currentSize); + } + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleNegProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleNegProcessor.java new file mode 100644 index 000000000000..37b093b849c5 --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleNegProcessor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.DoubleVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction; + +import java.util.Arrays; + +/** + * SIMD specialization of {@code (double[]) -> double[]} negation. The op is hardcoded to {@link DoubleVector#neg} + * so the JIT statically resolves it to the platform's double-negate intrinsic. + */ +public final class SimdDoubleNegProcessor extends SimdDoubleUnaryProcessor +{ + public SimdDoubleNegProcessor(ExprVectorProcessor input, DoubleUnivariateDoubleFunction scalarFallback) + { + super(input, scalarFallback); + } + + @Override + protected void processVector(double[] input, boolean[] inputNulls, int currentSize) + { + final int laneCount = SPECIES.length(); + final int upperBound = SPECIES.loopBound(currentSize); + int i = 0; + for (; i < upperBound; i += laneCount) { + DoubleVector.fromArray(SPECIES, input, i).neg().intoArray(outValues, i); + } + for (; i < currentSize; i++) { + outValues[i] = scalarFallback.process(input[i]); + } + if (inputNulls == null) { + Arrays.fill(outNulls, 0, currentSize, false); + } else { + System.arraycopy(inputNulls, 0, outNulls, 0, currentSize); + } + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleUnaryProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleUnaryProcessor.java new file mode 100644 index 000000000000..20527f68634d --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdDoubleUnaryProcessor.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.DoubleVector; +import jdk.incubator.vector.VectorSpecies; +import org.apache.druid.math.expr.Expr; +import org.apache.druid.math.expr.ExpressionType; +import org.apache.druid.math.expr.vector.CastToTypeVectorProcessor; +import org.apache.druid.math.expr.vector.ExprEvalDoubleVector; +import org.apache.druid.math.expr.vector.ExprEvalVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction; + +import javax.annotation.Nullable; + +/** + * Abstract base for SIMD processors that compute {@code (double[]) -> double[]} unary ops. See + * {@link SimdLongUnaryProcessor} for the design rationale. + */ +abstract class SimdDoubleUnaryProcessor implements ExprVectorProcessor +{ + static final VectorSpecies SPECIES = DoubleVector.SPECIES_PREFERRED; + + private final ExprVectorProcessor input; + final DoubleUnivariateDoubleFunction scalarFallback; + final double[] outValues; + final boolean[] outNulls; + + protected SimdDoubleUnaryProcessor( + ExprVectorProcessor input, + DoubleUnivariateDoubleFunction scalarFallback + ) + { + this.input = CastToTypeVectorProcessor.cast(input, ExpressionType.DOUBLE); + this.scalarFallback = scalarFallback; + this.outValues = new double[this.input.maxVectorSize()]; + this.outNulls = new boolean[this.input.maxVectorSize()]; + } + + @Override + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + { + final ExprEvalVector lhs = input.evalVector(bindings); + processVector(lhs.values(), lhs.getNullVector(), bindings.getCurrentVectorSize()); + return new ExprEvalDoubleVector(outValues, outNulls); + } + + protected abstract void processVector(double[] input, @Nullable boolean[] inputNulls, int currentSize); + + @Override + public final ExpressionType getOutputType() + { + return ExpressionType.DOUBLE; + } + + @Override + public final int maxVectorSize() + { + return outValues.length; + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongAbsProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongAbsProcessor.java new file mode 100644 index 000000000000..b5489cbdc52b --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongAbsProcessor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.LongVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction; + +import java.util.Arrays; + +/** + * SIMD specialization of {@code (long[]) -> long[]} absolute value. The op is hardcoded to {@link LongVector#abs} + * so the JIT statically resolves it to the platform's long-abs intrinsic. + */ +public final class SimdLongAbsProcessor extends SimdLongUnaryProcessor +{ + public SimdLongAbsProcessor(ExprVectorProcessor input, LongUnivariateLongFunction scalarFallback) + { + super(input, scalarFallback); + } + + @Override + protected void processVector(long[] input, boolean[] inputNulls, int currentSize) + { + final int laneCount = SPECIES.length(); + final int upperBound = SPECIES.loopBound(currentSize); + int i = 0; + for (; i < upperBound; i += laneCount) { + LongVector.fromArray(SPECIES, input, i).abs().intoArray(outValues, i); + } + for (; i < currentSize; i++) { + outValues[i] = scalarFallback.process(input[i]); + } + if (inputNulls == null) { + Arrays.fill(outNulls, 0, currentSize, false); + } else { + System.arraycopy(inputNulls, 0, outNulls, 0, currentSize); + } + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongNegProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongNegProcessor.java new file mode 100644 index 000000000000..03ba4a344b87 --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongNegProcessor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.LongVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction; + +import java.util.Arrays; + +/** + * SIMD specialization of {@code (long[]) -> long[]} negation. The op is hardcoded to {@link LongVector#neg} + * so the JIT statically resolves it to the platform's long-negate intrinsic. + */ +public final class SimdLongNegProcessor extends SimdLongUnaryProcessor +{ + public SimdLongNegProcessor(ExprVectorProcessor input, LongUnivariateLongFunction scalarFallback) + { + super(input, scalarFallback); + } + + @Override + protected void processVector(long[] input, boolean[] inputNulls, int currentSize) + { + final int laneCount = SPECIES.length(); + final int upperBound = SPECIES.loopBound(currentSize); + int i = 0; + for (; i < upperBound; i += laneCount) { + LongVector.fromArray(SPECIES, input, i).neg().intoArray(outValues, i); + } + for (; i < currentSize; i++) { + outValues[i] = scalarFallback.process(input[i]); + } + if (inputNulls == null) { + Arrays.fill(outNulls, 0, currentSize, false); + } else { + System.arraycopy(inputNulls, 0, outNulls, 0, currentSize); + } + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongUnaryProcessor.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongUnaryProcessor.java new file mode 100644 index 000000000000..e36c6adeb17f --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdLongUnaryProcessor.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +import jdk.incubator.vector.LongVector; +import jdk.incubator.vector.VectorSpecies; +import org.apache.druid.math.expr.Expr; +import org.apache.druid.math.expr.ExpressionType; +import org.apache.druid.math.expr.vector.CastToTypeVectorProcessor; +import org.apache.druid.math.expr.vector.ExprEvalLongVector; +import org.apache.druid.math.expr.vector.ExprEvalVector; +import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction; + +import javax.annotation.Nullable; + +/** + * Abstract base for SIMD processors that compute {@code (long[]) -> long[]} unary ops. Each concrete subclass + * (one per op) overrides {@link #processVector} with a hot loop that calls a statically-resolved {@link LongVector} + * method (e.g. {@code va.neg()} or {@code va.abs()}) so the JIT emits the corresponding SIMD intrinsic. + */ +abstract class SimdLongUnaryProcessor implements ExprVectorProcessor +{ + static final VectorSpecies SPECIES = LongVector.SPECIES_PREFERRED; + + private final ExprVectorProcessor input; + final LongUnivariateLongFunction scalarFallback; + final long[] outValues; + final boolean[] outNulls; + + protected SimdLongUnaryProcessor( + ExprVectorProcessor input, + LongUnivariateLongFunction scalarFallback + ) + { + this.input = CastToTypeVectorProcessor.cast(input, ExpressionType.LONG); + this.scalarFallback = scalarFallback; + this.outValues = new long[this.input.maxVectorSize()]; + this.outNulls = new boolean[this.input.maxVectorSize()]; + } + + @Override + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + { + final ExprEvalVector lhs = input.evalVector(bindings); + processVector(lhs.values(), lhs.getNullVector(), bindings.getCurrentVectorSize()); + return new ExprEvalLongVector(outValues, outNulls); + } + + protected abstract void processVector(long[] input, @Nullable boolean[] inputNulls, int currentSize); + + @Override + public final ExpressionType getOutputType() + { + return ExpressionType.LONG; + } + + @Override + public final int maxVectorSize() + { + return outValues.length; + } +} diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java index 55ca4c81076f..c7ce4878ee8a 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdProcessors.java @@ -24,11 +24,14 @@ import org.apache.druid.math.expr.vector.functional.DoubleBivariateDoubleLongFunction; import org.apache.druid.math.expr.vector.functional.DoubleBivariateDoublesFunction; import org.apache.druid.math.expr.vector.functional.DoubleBivariateLongDoubleFunction; +import org.apache.druid.math.expr.vector.functional.DoubleUnivariateDoubleFunction; import org.apache.druid.math.expr.vector.functional.LongBivariateLongsFunction; +import org.apache.druid.math.expr.vector.functional.LongUnivariateLongFunction; /** - * Dispatch table from a {@link SimdSupportedBinaryOp} identifier to a concrete, op-specialized SIMD processor. - * One class per op and type-combo so the JIT sees a monomorphic call site for the SIMD operation in each hot loop. + * Dispatch table from {@link SimdSupportedBinaryOp} / {@link SimdSupportedUnaryOp} identifiers to concrete, + * op-specialized SIMD processors. One class per op and type-combo so the JIT sees a monomorphic call site for + * the SIMD operation in each hot loop. */ public final class SimdProcessors { @@ -98,4 +101,30 @@ public static ExprVectorProcessor makeDoubleLong( default -> throw DruidException.defensive("Unsupported SIMD binary op[%s]", op); }; } + + public static ExprVectorProcessor makeLongUnary( + ExprVectorProcessor input, + SimdSupportedUnaryOp op, + LongUnivariateLongFunction scalarFallback + ) + { + return switch (op) { + case NEG -> new SimdLongNegProcessor(input, scalarFallback); + case ABS -> new SimdLongAbsProcessor(input, scalarFallback); + default -> throw DruidException.defensive("Unsupported SIMD unary op[%s]", op); + }; + } + + public static ExprVectorProcessor makeDoubleUnary( + ExprVectorProcessor input, + SimdSupportedUnaryOp op, + DoubleUnivariateDoubleFunction scalarFallback + ) + { + return switch (op) { + case NEG -> new SimdDoubleNegProcessor(input, scalarFallback); + case ABS -> new SimdDoubleAbsProcessor(input, scalarFallback); + default -> throw DruidException.defensive("Unsupported SIMD unary op[%s]", op); + }; + } } diff --git a/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java new file mode 100644 index 000000000000..260fd24d2acd --- /dev/null +++ b/processing/src/main/java/org/apache/druid/math/expr/vector/simd/SimdSupportedUnaryOp.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.druid.math.expr.vector.simd; + +/** + * Identifies which unary math operations have a {@code jdk.incubator.vector} (SIMD) specialization. Used by + * {@link org.apache.druid.math.expr.vector.SimpleVectorMathUnivariateProcessorFactory} subclasses to declare that + * their operation can be dispatched to a SIMD variant when the user enables + * {@link org.apache.druid.math.expr.ExpressionProcessingConfig#USE_VECTOR_API}. + * + * Deliberately does not reference any {@code jdk.incubator.vector} types so that callers wiring the enum into + * factories do not need the incubator module visible. + */ +public enum SimdSupportedUnaryOp +{ + NEG, + ABS +}