This is an automated email from the ASF dual-hosted git repository.

panxiaolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 0f7a1c316da [opt](expr) Remove FixedContainer optimization for 
StringValueSet (#62243)
0f7a1c316da is described below

commit 0f7a1c316da24e2d7af0332cfb49a486b2402818
Author: Mryange <[email protected]>
AuthorDate: Thu Apr 9 17:52:08 2026 +0800

    [opt](expr) Remove FixedContainer optimization for StringValueSet (#62243)
    
    Benchmark results show that `FixedContainer` (SIMD linear scan) is
    slower than `DynamicContainer` (hash set) for `std::string`/`StringRef`
    when N >= 2. The FixedContainer optimization only benefits integer types
    at small sizes, but hurts string lookups due to expensive comparisons
    scaling linearly with N.
    
    This PR removes the `FixedContainer` specialization from
    `create_string_value_set`, always using the hash-based
    `DynamicContainer` instead.
    
    Additionally fixes deprecated `DoNotOptimize` warnings in benchmark
    files and adds a new `FixedContainer` vs `DynamicContainer` benchmark.
    
    ```
    Fixed_Int32_N1                                                              
            5.28 us         5.25 us       100000
    Dynamic_Int32_N1                                                            
            29.4 us         29.1 us        23538
    Fixed_Int32_N2                                                              
            15.7 us         15.6 us        46383
    Dynamic_Int32_N2                                                            
            41.4 us         41.2 us        16213
    Fixed_Int32_N3                                                              
            25.7 us         25.6 us        27386
    Dynamic_Int32_N3                                                            
            45.9 us         45.5 us        14574
    Fixed_Int32_N4                                                              
            9.45 us         9.40 us        79614
    Dynamic_Int32_N4                                                            
            40.5 us         40.3 us        15873
    Fixed_Int32_N5                                                              
            22.9 us         22.8 us        29587
    Dynamic_Int32_N5                                                            
            46.5 us         46.3 us        14624
    Fixed_Int32_N6                                                              
            31.5 us         31.3 us        22306
    Dynamic_Int32_N6                                                            
            46.5 us         46.3 us        14851
    Fixed_Int32_N7                                                              
            41.6 us         41.4 us        17142
    Dynamic_Int32_N7                                                            
            56.1 us         55.8 us        12542
    Fixed_Int32_N8                                                              
            11.1 us         11.1 us        70730
    Dynamic_Int32_N8                                                            
            43.3 us         42.1 us        12838
    Fixed_Int64_N1                                                              
            5.91 us         5.88 us       121146
    Dynamic_Int64_N1                                                            
            41.5 us         41.3 us        19183
    Fixed_Int64_N2                                                              
            16.0 us         16.0 us        47690
    Dynamic_Int64_N2                                                            
            40.2 us         40.0 us        18290
    Fixed_Int64_N3                                                              
            27.0 us         26.9 us        27097
    Dynamic_Int64_N3                                                            
            46.9 us         46.6 us        15495
    Fixed_Int64_N4                                                              
            24.8 us         24.6 us        28495
    Dynamic_Int64_N4                                                            
            40.5 us         40.2 us        17581
    Fixed_Int64_N5                                                              
            39.9 us         39.6 us        18133
    Dynamic_Int64_N5                                                            
            47.4 us         47.2 us        14943
    Fixed_Int64_N6                                                              
            45.8 us         45.5 us        15396
    Dynamic_Int64_N6                                                            
            49.2 us         48.9 us        14062
    Fixed_Int64_N7                                                              
            55.0 us         54.8 us        12726
    Dynamic_Int64_N7                                                            
            57.6 us         57.3 us        12673
    Fixed_Int64_N8                                                              
            14.5 us         14.4 us        48230
    Dynamic_Int64_N8                                                            
            40.3 us         40.1 us        17560
    Fixed_String_N1                                                             
             243 us          242 us         2884
    Dynamic_String_N1                                                           
            1364 us         1358 us          516
    Fixed_String_N2                                                             
            1195 us         1189 us          591
    Dynamic_String_N2                                                           
             739 us          736 us          946
    Fixed_String_N3                                                             
             163 us          163 us         4433
    Dynamic_String_N3                                                           
             226 us          225 us         3257
    Fixed_String_N4                                                             
             214 us          213 us         3290
    Dynamic_String_N4                                                           
             205 us          204 us         3437
    Fixed_String_N5                                                             
             266 us          265 us         2634
    Dynamic_String_N5                                                           
             220 us          219 us         2900
    Fixed_String_N6                                                             
             313 us          312 us         2246
    Dynamic_String_N6                                                           
             220 us          219 us         3195
    Fixed_String_N7                                                             
             362 us          360 us         1962
    Dynamic_String_N7                                                           
             234 us          233 us         3008
    Fixed_String_N8                                                             
            2586 us         2575 us          274
    Dynamic_String_N8                                                           
             213 us          212 us         3350
    
    ```
---
 be/benchmark/benchmark_bit_pack.hpp      |  12 +-
 be/benchmark/benchmark_hybrid_set.hpp    | 190 +++++++++++++++++++++++++++++++
 be/benchmark/benchmark_main.cpp          |   1 +
 be/benchmark/benchmark_string.hpp        |  34 +++---
 be/benchmark/binary_cast_benchmark.hpp   |  12 +-
 be/src/exprs/create_predicate_function.h |  27 +----
 6 files changed, 230 insertions(+), 46 deletions(-)

diff --git a/be/benchmark/benchmark_bit_pack.hpp 
b/be/benchmark/benchmark_bit_pack.hpp
index c0e383c6b1c..10b0fc03f8a 100644
--- a/be/benchmark/benchmark_bit_pack.hpp
+++ b/be/benchmark/benchmark_bit_pack.hpp
@@ -65,8 +65,10 @@ static void BM_BitPack(benchmark::State& state) {
     std::vector<uint8_t> output(size);
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
-        benchmark::DoNotOptimize(output.data());
+        auto* td = test_data.data();
+        auto* od = output.data();
+        benchmark::DoNotOptimize(td);
+        benchmark::DoNotOptimize(od);
         bit_pack(test_data.data(), (uint8_t)n, w, output.data());
         benchmark::ClobberMemory();
     }
@@ -92,8 +94,10 @@ static void BM_BitPackOptimized(benchmark::State& state) {
     ForEncoder<__int128_t> forEncoder(nullptr);
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
-        benchmark::DoNotOptimize(output.data());
+        auto* td = test_data.data();
+        auto* od = output.data();
+        benchmark::DoNotOptimize(td);
+        benchmark::DoNotOptimize(od);
         forEncoder.bit_pack(test_data.data(), (uint8_t)n, w, output.data());
         benchmark::ClobberMemory();
     }
diff --git a/be/benchmark/benchmark_hybrid_set.hpp 
b/be/benchmark/benchmark_hybrid_set.hpp
new file mode 100644
index 00000000000..fee58c56013
--- /dev/null
+++ b/be/benchmark/benchmark_hybrid_set.hpp
@@ -0,0 +1,190 @@
+// 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.
+
+// ============================================================
+// Benchmark: FixedContainer vs DynamicContainer (from hybrid_set.h)
+//
+// Measures find() performance for different container sizes (1-8)
+// and element types (int32_t, int64_t, std::string).
+// ============================================================
+
+#pragma once
+
+#include <benchmark/benchmark.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "exprs/hybrid_set.h"
+
+namespace doris {
+
+// ============================================================
+// Test data generators
+// ============================================================
+
+template <typename T>
+static std::vector<T> generate_values(size_t n);
+
+template <>
+std::vector<int32_t> generate_values<int32_t>(size_t n) {
+    std::vector<int32_t> vals;
+    vals.reserve(n);
+    for (size_t i = 0; i < n; ++i) {
+        vals.push_back(static_cast<int32_t>(i * 7 + 13));
+    }
+    return vals;
+}
+
+template <>
+std::vector<int64_t> generate_values<int64_t>(size_t n) {
+    std::vector<int64_t> vals;
+    vals.reserve(n);
+    for (size_t i = 0; i < n; ++i) {
+        vals.push_back(static_cast<int64_t>(i * 7 + 13));
+    }
+    return vals;
+}
+
+template <>
+std::vector<std::string> generate_values<std::string>(size_t n) {
+    std::vector<std::string> vals;
+    vals.reserve(n);
+    for (size_t i = 0; i < n; ++i) {
+        vals.push_back("key_" + std::to_string(i * 7 + 13));
+    }
+    return vals;
+}
+
+// Number of find() calls per iteration to amortize loop overhead.
+static constexpr size_t FIND_ITERS = 10000;
+
+// ============================================================
+// FixedContainer benchmark: insert N values, then find them
+// ============================================================
+
+template <typename T, size_t N>
+static void BM_FixedContainer_Find(benchmark::State& state) {
+    auto values = generate_values<T>(N);
+
+    // Also prepare a "miss" value for interleaving hit/miss lookups.
+    auto miss_values = generate_values<T>(N + 4);
+
+    for (auto _ : state) {
+        FixedContainer<T, N> container;
+        for (size_t i = 0; i < N; ++i) {
+            container.insert(values[i]);
+        }
+
+        int64_t found = 0;
+        for (size_t iter = 0; iter < FIND_ITERS; ++iter) {
+            // Hit: search for existing value
+            found += container.find(values[iter % N]);
+            // Miss: search for non-existing value
+            found += container.find(miss_values[N + (iter % 4)]);
+        }
+        benchmark::DoNotOptimize(found);
+    }
+}
+
+// ============================================================
+// DynamicContainer benchmark: insert N values, then find them
+// ============================================================
+
+template <typename T, size_t N>
+static void BM_DynamicContainer_Find(benchmark::State& state) {
+    auto values = generate_values<T>(N);
+    auto miss_values = generate_values<T>(N + 4);
+
+    for (auto _ : state) {
+        DynamicContainer<T> container;
+        for (size_t i = 0; i < N; ++i) {
+            container.insert(values[i]);
+        }
+
+        int64_t found = 0;
+        for (size_t iter = 0; iter < FIND_ITERS; ++iter) {
+            found += container.find(values[iter % N]);
+            found += container.find(miss_values[N + (iter % 4)]);
+        }
+        benchmark::DoNotOptimize(found);
+    }
+}
+
+// ============================================================
+// Register benchmarks for int32_t
+// ============================================================
+
+#define REGISTER_FIXED_INT32(N)                                                
            \
+    BENCHMARK(BM_FixedContainer_Find<int32_t, N>)->Name("Fixed_Int32_N" 
#N)->Unit(         \
+            benchmark::kMicrosecond);                                          
            \
+    BENCHMARK(BM_DynamicContainer_Find<int32_t, N>)->Name("Dynamic_Int32_N" 
#N)->Unit(     \
+            benchmark::kMicrosecond);
+
+REGISTER_FIXED_INT32(1)
+REGISTER_FIXED_INT32(2)
+REGISTER_FIXED_INT32(3)
+REGISTER_FIXED_INT32(4)
+REGISTER_FIXED_INT32(5)
+REGISTER_FIXED_INT32(6)
+REGISTER_FIXED_INT32(7)
+REGISTER_FIXED_INT32(8)
+
+// ============================================================
+// Register benchmarks for int64_t
+// ============================================================
+
+#define REGISTER_FIXED_INT64(N)                                                
            \
+    BENCHMARK(BM_FixedContainer_Find<int64_t, N>)->Name("Fixed_Int64_N" 
#N)->Unit(         \
+            benchmark::kMicrosecond);                                          
            \
+    BENCHMARK(BM_DynamicContainer_Find<int64_t, N>)->Name("Dynamic_Int64_N" 
#N)->Unit(     \
+            benchmark::kMicrosecond);
+
+REGISTER_FIXED_INT64(1)
+REGISTER_FIXED_INT64(2)
+REGISTER_FIXED_INT64(3)
+REGISTER_FIXED_INT64(4)
+REGISTER_FIXED_INT64(5)
+REGISTER_FIXED_INT64(6)
+REGISTER_FIXED_INT64(7)
+REGISTER_FIXED_INT64(8)
+
+// ============================================================
+// Register benchmarks for std::string
+// ============================================================
+
+#define REGISTER_FIXED_STRING(N)                                               
                \
+    BENCHMARK(BM_FixedContainer_Find<std::string, N>)->Name("Fixed_String_N" 
#N)->Unit(        \
+            benchmark::kMicrosecond);                                          
                \
+    BENCHMARK(BM_DynamicContainer_Find<std::string, 
N>)->Name("Dynamic_String_N" #N)->Unit(    \
+            benchmark::kMicrosecond);
+
+REGISTER_FIXED_STRING(1)
+REGISTER_FIXED_STRING(2)
+REGISTER_FIXED_STRING(3)
+REGISTER_FIXED_STRING(4)
+REGISTER_FIXED_STRING(5)
+REGISTER_FIXED_STRING(6)
+REGISTER_FIXED_STRING(7)
+REGISTER_FIXED_STRING(8)
+
+#undef REGISTER_FIXED_INT32
+#undef REGISTER_FIXED_INT64
+#undef REGISTER_FIXED_STRING
+
+} // namespace doris
diff --git a/be/benchmark/benchmark_main.cpp b/be/benchmark/benchmark_main.cpp
index f76dbb370e5..21e629e3d6f 100644
--- a/be/benchmark/benchmark_main.cpp
+++ b/be/benchmark/benchmark_main.cpp
@@ -23,6 +23,7 @@
 #include "benchmark_column_view.hpp"
 #include "benchmark_fastunion.hpp"
 #include "benchmark_hll_merge.hpp"
+#include "benchmark_hybrid_set.hpp"
 #include "benchmark_string.hpp"
 #include "binary_cast_benchmark.hpp"
 #include "core/block/block.h"
diff --git a/be/benchmark/benchmark_string.hpp 
b/be/benchmark/benchmark_string.hpp
index bab869b693d..fdb1762ed8c 100644
--- a/be/benchmark/benchmark_string.hpp
+++ b/be/benchmark/benchmark_string.hpp
@@ -211,7 +211,8 @@ static void BM_ToBase64Impl_Old(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(OldToBase64Impl::vector(data, offsets, 
dst_data, dst_offsets));
+        auto status = OldToBase64Impl::vector(data, offsets, dst_data, 
dst_offsets);
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -228,7 +229,8 @@ static void BM_ToBase64Impl_New(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(ToBase64Impl::vector(data, offsets, dst_data, 
dst_offsets));
+        auto status = ToBase64Impl::vector(data, offsets, dst_data, 
dst_offsets);
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -258,8 +260,9 @@ static void BM_FromBase64Impl_Old(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(OldFromBase64Impl::vector(data, offsets, 
dst_data, dst_offsets,
-                                                           
null_map->get_data()));
+        auto status = OldFromBase64Impl::vector(data, offsets, dst_data, 
dst_offsets,
+                                                    null_map->get_data());
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -277,8 +280,9 @@ static void BM_FromBase64Impl_New(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(
-                FromBase64Impl::vector(data, offsets, dst_data, dst_offsets, 
null_map->get_data()));
+        auto status =
+                FromBase64Impl::vector(data, offsets, dst_data, dst_offsets, 
null_map->get_data());
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -307,7 +311,8 @@ static void BM_UnhexImpl_Old(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(OldUnHexImpl::vector(data, offsets, dst_data, 
dst_offsets));
+        auto status = OldUnHexImpl::vector(data, offsets, dst_data, 
dst_offsets);
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -324,8 +329,9 @@ static void BM_UnhexImpl_New(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(
-                UnHexImpl<UnHexImplEmpty>::vector(data, offsets, dst_data, 
dst_offsets));
+        auto status =
+                UnHexImpl<UnHexImplEmpty>::vector(data, offsets, dst_data, 
dst_offsets);
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -355,8 +361,9 @@ static void BM_UnhexNullImpl_Old(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(
-                OldUnHexImpl::vector(data, offsets, dst_data, dst_offsets, 
&null_map->get_data()));
+        auto status =
+                OldUnHexImpl::vector(data, offsets, dst_data, dst_offsets, 
&null_map->get_data());
+        benchmark::DoNotOptimize(status);
     }
 }
 
@@ -374,8 +381,9 @@ static void BM_UnhexNullImpl_New(benchmark::State& state) {
     for (auto _ : state) {
         dst_data.clear();
         dst_offsets.clear();
-        benchmark::DoNotOptimize(UnHexImpl<UnHexImplNull>::vector(
-                data, offsets, dst_data, dst_offsets, &null_map->get_data()));
+        auto status = UnHexImpl<UnHexImplNull>::vector(
+                data, offsets, dst_data, dst_offsets, &null_map->get_data());
+        benchmark::DoNotOptimize(status);
     }
 }
 
diff --git a/be/benchmark/binary_cast_benchmark.hpp 
b/be/benchmark/binary_cast_benchmark.hpp
index fec9ddb949a..a130b3fc528 100644
--- a/be/benchmark/binary_cast_benchmark.hpp
+++ b/be/benchmark/binary_cast_benchmark.hpp
@@ -138,7 +138,8 @@ static void 
BM_BinaryCast_UI64_to_DateTimeV2(benchmark::State& state) {
     state.ResumeTiming();
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
+        auto* td = test_data.data();
+        benchmark::DoNotOptimize(td);
 
         for (size_t i = 0; i < data_size; ++i) {
             auto result = binary_cast<uint64_t, 
DateV2Value<DateTimeV2ValueType>>(test_data[i]);
@@ -160,7 +161,8 @@ static void 
BM_OldBinaryCast_UI64_to_DateTimeV2(benchmark::State& state) {
     state.ResumeTiming();
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
+        auto* td = test_data.data();
+        benchmark::DoNotOptimize(td);
 
         for (size_t i = 0; i < data_size; ++i) {
             auto result = old_binary_cast<uint64_t, 
DateV2Value<DateTimeV2ValueType>>(test_data[i]);
@@ -183,7 +185,8 @@ static void 
BM_BinaryCast_DateTimeV2_to_UI64(benchmark::State& state) {
     state.ResumeTiming();
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
+        auto* td = test_data.data();
+        benchmark::DoNotOptimize(td);
 
         for (size_t i = 0; i < data_size; ++i) {
             auto result = binary_cast<DateV2Value<DateTimeV2ValueType>, 
uint64_t>(test_data[i]);
@@ -206,7 +209,8 @@ static void 
BM_OldBinaryCast_DateTimeV2_to_UI64(benchmark::State& state) {
     state.ResumeTiming();
 
     for (auto _ : state) {
-        benchmark::DoNotOptimize(test_data.data());
+        auto* td = test_data.data();
+        benchmark::DoNotOptimize(td);
 
         for (size_t i = 0; i < data_size; ++i) {
             auto result = old_binary_cast<DateV2Value<DateTimeV2ValueType>, 
uint64_t>(test_data[i]);
diff --git a/be/src/exprs/create_predicate_function.h 
b/be/src/exprs/create_predicate_function.h
index 94f8802569c..ee8f3a5e927 100644
--- a/be/src/exprs/create_predicate_function.h
+++ b/be/src/exprs/create_predicate_function.h
@@ -188,35 +188,12 @@ inline auto create_set(PrimitiveType type, size_t size, 
bool null_aware) {
     }
 }
 
-template <size_t N = 0>
 inline HybridSetBase* create_string_value_set(bool null_aware) {
-    if constexpr (N >= 1 && N <= FIXED_CONTAINER_MAX_SIZE) {
-        return new StringValueSet<FixedContainer<StringRef, N>>(null_aware);
-    } else {
-        return new StringValueSet(null_aware);
-    }
+    return new StringValueSet(null_aware);
 }
 
 inline HybridSetBase* create_string_value_set(size_t size, bool null_aware) {
-    if (size == 1) {
-        return create_string_value_set<1>(null_aware);
-    } else if (size == 2) {
-        return create_string_value_set<2>(null_aware);
-    } else if (size == 3) {
-        return create_string_value_set<3>(null_aware);
-    } else if (size == 4) {
-        return create_string_value_set<4>(null_aware);
-    } else if (size == 5) {
-        return create_string_value_set<5>(null_aware);
-    } else if (size == 6) {
-        return create_string_value_set<6>(null_aware);
-    } else if (size == 7) {
-        return create_string_value_set<7>(null_aware);
-    } else if (size == FIXED_CONTAINER_MAX_SIZE) {
-        return create_string_value_set<FIXED_CONTAINER_MAX_SIZE>(null_aware);
-    } else {
-        return create_string_value_set(null_aware);
-    }
+    return create_string_value_set(null_aware);
 }
 
 inline auto create_bloom_filter(PrimitiveType type, bool null_aware) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to