This is an automated email from the ASF dual-hosted git repository.
HappenLee 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 ddbaaab1388 [fix](build) prevent math regression from global lance-c
linkage (#67237)
ddbaaab1388 is described below
commit ddbaaab13882dab3dfa51ffb8038218df869e360
Author: linrrarity <[email protected]>
AuthorDate: Wed Sep 2 16:12:11 2026 +0800
[fix](build) prevent math regression from global lance-c linkage (#67237)
Problem Summary:
PR #65304 added the following libraries to `COMMON_THIRDPARTY`:
```cmake
list(APPEND COMMON_THIRDPARTY m lance_c)
```
As a result, some math symbols are resolved by the system `libm` before
the linker scans Doris' optimized compatibility implementations, causing
a noticeable performance regression for functions such as `exp`, `log`,
and `pow`:
- exp: approximately 220%
- ln: approximately 167%
- log: approximately 197%
- log2: approximately 165%
Simply moving `-lm` and `lance_c` after `glibc-compatibility` exposes
another issue. Once Lance is actually referenced, `liblance_c.a` pulls
in Rust std objects containing late unresolved references to:
- `posix_spawnp`
- `posix_spawn_file_actions_init`
- `posix_spawn_file_actions_destroy`
- `posix_spawn_file_actions_adddup2`
- `preadv`
- `splice`
The LDB toolchain resolves these references by extracting its monolithic
`glibc-compatibility.c.o`, which also defines `getrandom`. This
conflicts with Doris' explicitly linked `getrandom.c.o` and causes a
duplicate-symbol error.
#### Solution
1. Restore the required link order
For `GLIBC_COMPATIBILITY=ON`, use the following order:
```text
glibc-compatibility-explicit
→ glibc-compatibility
→ -lm
→ lance_c
```
This ordering ensures that:
- Doris' optimized math implementations are scanned before `-lm`.
- `-lm` is scanned before `lance_c`, preventing Rust compiler_builtins
symbols such as cbrt from being selected.
- `lance_c` remains available to its consumers.
2. Resolve the late Lance/Rust libc references
Add a small set of hidden symbol-version adapters for the six strong
libc references introduced by the Rust std object.
Each adapter has two parts. For example, the `splice` adapter is
conceptually:
```c
extern __typeof__(splice) __doris_old_splice;
__asm__(
".symver __doris_old_splice,"
"splice@GLIBC_2.5"
);
__attribute__((visibility("hidden")))
ssize_t splice(...) {
return __doris_old_splice(...);
}
```
The hidden `splice` wrapper is included in the
`glibc-compatibility-explicit` OBJECT target, so its symbol is visible
to the linker before `liblance_c.a` is processed.
#### performance
```text
Doris> select count(exp(db)) from double_ranges;
+----------------+
| count(exp(db)) |
+----------------+
| 50000000 |
+----------------+
1 row in set (0.980 sec)
Doris> select count(exp(db)) from double_ranges;
+----------------+
| count(exp(db)) |
+----------------+
| 50000000 |
+----------------+
1 row in set (0.347 sec)
Doris> select count(ln(db)), count(ln(in_one)) from double_ranges;
+---------------+-------------------+
| count(ln(db)) | count(ln(in_one)) |
+---------------+-------------------+
| 50000000 | 50000000 |
+---------------+-------------------+
1 row in set (1.486 sec)
Doris> select count(ln(db)), count(ln(in_one)) from double_ranges;
+---------------+-------------------+
| count(ln(db)) | count(ln(in_one)) |
+---------------+-------------------+
| 50000000 | 50000000 |
+---------------+-------------------+
1 row in set (0.607 sec)
Doris> select count(log(db, db)), count(log(in_one, db)), count(log(db,
in_one)), count(log(db, in_ten)) from double_ranges;
+--------------------+------------------------+------------------------+------------------------+
| count(log(db, db)) | count(log(in_one, db)) | count(log(db, in_one)) |
count(log(db, in_ten)) |
+--------------------+------------------------+------------------------+------------------------+
| 50000000 | 49999990 | 50000000 |
50000000 |
+--------------------+------------------------+------------------------+------------------------+
1 row in set (5.944 sec)
Doris> select count(log(db, db)), count(log(in_one, db)), count(log(db,
in_one)), count(log(db, in_ten)) from double_ranges;
+--------------------+------------------------+------------------------+------------------------+
| count(log(db, db)) | count(log(in_one, db)) | count(log(db, in_one)) |
count(log(db, in_ten)) |
+--------------------+------------------------+------------------------+------------------------+
| 50000000 | 49999990 | 50000000 |
50000000 |
+--------------------+------------------------+------------------------+------------------------+
1 row in set (2.356 sec)
Doris> select count(log2(db)), count(log2(in_one)) from double_ranges;
+-----------------+---------------------+
| count(log2(db)) | count(log2(in_one)) |
+-----------------+---------------------+
| 50000000 | 50000000 |
+-----------------+---------------------+
1 row in set (1.616 sec)
Doris> select count(log2(db)), count(log2(in_one)) from double_ranges;
+-----------------+---------------------+
| count(log2(db)) | count(log2(in_one)) |
+-----------------+---------------------+
| 50000000 | 50000000 |
+-----------------+---------------------+
1 row in set (0.655 sec)
```
---
be/CMakeLists.txt | 9 ++-
be/cmake/thirdparty.cmake | 8 +-
be/src/glibc-compatibility/CMakeLists.txt | 18 ++++-
be/src/glibc-compatibility/lance_symbol_versions.c | 92 ++++++++++++++++++++++
4 files changed, 122 insertions(+), 5 deletions(-)
diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt
index 0dc2196dc81..55f8166b200 100644
--- a/be/CMakeLists.txt
+++ b/be/CMakeLists.txt
@@ -901,7 +901,14 @@ endif()
# NOTE(amos): This should come before -lc -lm to interpose symbols correctly.
if (GLIBC_COMPATIBILITY)
add_subdirectory(${SRC_DIR}/glibc-compatibility)
- set(DORIS_LINK_LIBS ${DORIS_LINK_LIBS} glibc-compatibility-explicit
glibc-compatibility)
+ # Keep lance_c here instead of COMMON_THIRDPARTY: placing its required
libm there
+ # would resolve -lm symbol before Doris compatibility is scanned,
preventing
+ # the linker from selecting Doris' optimized implementations.
+ set(DORIS_LINK_LIBS ${DORIS_LINK_LIBS}
+ glibc-compatibility-explicit
+ glibc-compatibility
+ -lm
+ lance_c)
endif()
if (NOT OS_MACOSX)
diff --git a/be/cmake/thirdparty.cmake b/be/cmake/thirdparty.cmake
index f3bd9867ee0..72da7afe1f3 100644
--- a/be/cmake/thirdparty.cmake
+++ b/be/cmake/thirdparty.cmake
@@ -113,9 +113,13 @@ add_thirdparty(arrow_acero LIB64)
add_thirdparty(adbc_driver_manager LIB64)
add_thirdparty(parquet LIB64)
# liblance_c.a contains compiler_builtins cbrt symbols. Place libm before it
-# so the final linker resolves C math symbols from the system library first.
+# so the final linker resolves C math symbols from the system library first
add_thirdparty(lance_c LIB64 NOTADD)
-list(APPEND COMMON_THIRDPARTY m lance_c)
+# liblance_c.a contains compiler_builtins cbrt symbols. Place libm before it
+# so the final linker resolves C math symbols from the system library first.
+if (NOT GLIBC_COMPATIBILITY)
+ list(APPEND COMMON_THIRDPARTY m lance_c)
+endif()
add_thirdparty(brpc LIB64)
add_thirdparty(rocksdb)
add_thirdparty(cyrus-sasl LIBNAME "lib/libsasl2.a")
diff --git a/be/src/glibc-compatibility/CMakeLists.txt
b/be/src/glibc-compatibility/CMakeLists.txt
index 370d7346691..116e0636893 100644
--- a/be/src/glibc-compatibility/CMakeLists.txt
+++ b/be/src/glibc-compatibility/CMakeLists.txt
@@ -49,6 +49,13 @@ if (GLIBC_COMPATIBILITY)
list(APPEND glibc_compatibility_sources musl/getentropy.c)
endif()
+ # lance_c is linked after this archive and introduces these libc references
+ # too late for another archive scan. Keep the hidden version adapters in
the
+ # explicit object target so the final -lc does not pull in the toolchain's
+ # monolithic glibc-compatibility object and conflict with Doris'
definitions.
+ set(lance_compatibility_source lance_symbol_versions.c)
+ list(REMOVE_ITEM glibc_compatibility_sources ${lance_compatibility_source})
+
# Need to omit frame pointers to match the performance of glibc
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer")
@@ -65,9 +72,16 @@ if (GLIBC_COMPATIBILITY)
# before ASAN shadow memory is initialized, causing SIGSEGV. Skip custom
memcpy in
# this case and fall back to glibc's memcpy.
if (ARCH_ARM AND (CMAKE_BUILD_TYPE STREQUAL "ASAN_UT" OR CMAKE_BUILD_TYPE
STREQUAL "ASAN"))
- add_library(glibc-compatibility-explicit OBJECT musl/getrandom.c)
+ add_library(glibc-compatibility-explicit OBJECT
+ musl/getrandom.c
+ ${lance_compatibility_source}
+ )
else()
- add_library(glibc-compatibility-explicit OBJECT musl/getrandom.c
${MEMCPY_SOURCE})
+ add_library(glibc-compatibility-explicit OBJECT
+ musl/getrandom.c
+ ${MEMCPY_SOURCE}
+ ${lance_compatibility_source}
+ )
endif()
target_compile_options(glibc-compatibility-explicit PRIVATE -fPIC)
add_library(glibc-compatibility STATIC ${glibc_compatibility_sources})
diff --git a/be/src/glibc-compatibility/lance_symbol_versions.c
b/be/src/glibc-compatibility/lance_symbol_versions.c
new file mode 100644
index 00000000000..b0594dce06b
--- /dev/null
+++ b/be/src/glibc-compatibility/lance_symbol_versions.c
@@ -0,0 +1,92 @@
+// 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.
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <spawn.h>
+#include <sys/uio.h>
+
+#if defined(__x86_64__)
+#define DORIS_GLIBC_BASE_VERSION "GLIBC_2.2.5"
+#define DORIS_GLIBC_PREADV_VERSION "GLIBC_2.10"
+#define DORIS_GLIBC_SPLICE_VERSION "GLIBC_2.5"
+#elif defined(__aarch64__)
+#define DORIS_GLIBC_BASE_VERSION "GLIBC_2.17"
+#define DORIS_GLIBC_PREADV_VERSION "GLIBC_2.17"
+#define DORIS_GLIBC_SPLICE_VERSION "GLIBC_2.17"
+#else
+#error Unsupported architecture for Lance libc symbol version adapters.
+#endif
+
+#define DORIS_GLIBC_SYMVER(alias, symbol, version) \
+ __asm__(".symver " #alias "," #symbol "@" version)
+
+// Resolve late libc references from the static lance_c archive without
exporting
+// process-wide interposers. Each wrapper forwards to an explicitly versioned
+// glibc symbol, so it cannot recurse back into the hidden wrapper.
+#define DORIS_HIDDEN __attribute__((visibility("hidden")))
+
+extern __typeof__(posix_spawnp) __doris_old_posix_spawnp;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawnp, posix_spawnp,
DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_init)
__doris_old_posix_spawn_file_actions_init;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_init,
posix_spawn_file_actions_init,
+ DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_destroy)
__doris_old_posix_spawn_file_actions_destroy;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_destroy,
posix_spawn_file_actions_destroy,
+ DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_adddup2)
__doris_old_posix_spawn_file_actions_adddup2;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_adddup2,
+ posix_spawn_file_actions_adddup2, DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(preadv) __doris_old_preadv;
+DORIS_GLIBC_SYMVER(__doris_old_preadv, preadv, DORIS_GLIBC_PREADV_VERSION);
+
+extern __typeof__(splice) __doris_old_splice;
+DORIS_GLIBC_SYMVER(__doris_old_splice, splice, DORIS_GLIBC_SPLICE_VERSION);
+
+DORIS_HIDDEN int posix_spawnp(pid_t* pid, const char* file,
+ const posix_spawn_file_actions_t* file_actions,
+ const posix_spawnattr_t* attr, char* const
argv[],
+ char* const envp[]) {
+ return __doris_old_posix_spawnp(pid, file, file_actions, attr, argv, envp);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_init(posix_spawn_file_actions_t*
file_actions) {
+ return __doris_old_posix_spawn_file_actions_init(file_actions);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t*
file_actions) {
+ return __doris_old_posix_spawn_file_actions_destroy(file_actions);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t*
file_actions, int fd,
+ int new_fd) {
+ return __doris_old_posix_spawn_file_actions_adddup2(file_actions, fd,
new_fd);
+}
+
+DORIS_HIDDEN ssize_t preadv(int fd, const struct iovec* iov, int iov_count,
off_t offset) {
+ return __doris_old_preadv(fd, iov, iov_count, offset);
+}
+
+DORIS_HIDDEN ssize_t splice(int fd_in, off64_t* offset_in, int fd_out,
off64_t* offset_out,
+ size_t length, unsigned int flags) {
+ return __doris_old_splice(fd_in, offset_in, fd_out, offset_out, length,
flags);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]