mirror of
https://github.com/mudler/LocalAI.git
synced 2026-09-12 22:33:54 -04:00
Fixes #11895 Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
206 lines
7.3 KiB
Bash
Executable File
206 lines
7.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Exercise the real diffusers launcher with versioned ELF libraries, no torch,
|
|
# downloads, venv creation or GPU required.
|
|
set -euo pipefail
|
|
|
|
if [ "$(uname -s)" != "Linux" ]; then
|
|
echo "SKIP: Intel Python runtime regression requires Linux ELF loading"
|
|
exit 0
|
|
fi
|
|
for tool in gcc ldd python3; do
|
|
if ! command -v "$tool" >/dev/null 2>&1; then
|
|
echo "SKIP: $tool not available"
|
|
exit 0
|
|
fi
|
|
done
|
|
if ! ldd --version 2>&1 | grep -qi 'glibc\|GNU libc'; then
|
|
echo "SKIP: versioned ELF regression requires glibc"
|
|
exit 0
|
|
fi
|
|
|
|
REPO_ROOT=$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")
|
|
WORK=$(mktemp -d)
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
export TEST_SYSTEM_PYTHON
|
|
TEST_SYSTEM_PYTHON=$(command -v python3)
|
|
unset ENV_DIR BACKEND_FILE VIRTUAL_ENV PYTHONHOME LD_LIBRARY_PATH
|
|
export PORTABLE_PYTHON=false BUILD_TYPE=cpu
|
|
|
|
# Fail immediately if startup attempts to provision anything.
|
|
mkdir -p "$WORK/bin" "$WORK/good" "$WORK/bad" "$WORK/host" "$WORK/cwd"
|
|
for tool in uv pip pip3 curl wget; do
|
|
printf '#!/bin/bash\necho "Unexpected provisioning command" >&2\nexit 99\n' > "$WORK/bin/$tool"
|
|
chmod +x "$WORK/bin/$tool"
|
|
done
|
|
export PATH="$WORK/bin:$PATH"
|
|
|
|
cat > "$WORK/loader.c" <<'C'
|
|
int urFixtureOrigin(void) { return ORIGIN; }
|
|
#ifdef MATCHING
|
|
int urDeviceWaitExp(void) { return 42; }
|
|
#else
|
|
int urOldFunction(void) { return 0; }
|
|
#endif
|
|
C
|
|
cat > "$WORK/loader.map" <<'MAP'
|
|
LIBUR_LOADER_0.12 { global: ur*; local: *; };
|
|
MAP
|
|
cat > "$WORK/sycl.c" <<'C'
|
|
int urDeviceWaitExp(void);
|
|
int syclFixture(void) { return urDeviceWaitExp(); }
|
|
C
|
|
echo 'int adapterFixture(void) { return ORIGIN; }' > "$WORK/adapter.c"
|
|
|
|
# All loaders have the same SONAME and version namespace, but only the venv
|
|
# copy exports the required versioned symbol (the reported failure class).
|
|
for kind in good bad host; do
|
|
flags=()
|
|
case "$kind" in
|
|
good) flags=(-DMATCHING -DORIGIN=1) ;;
|
|
bad) flags=(-DORIGIN=2) ;;
|
|
host) flags=(-DORIGIN=3) ;;
|
|
esac
|
|
gcc -shared -fPIC "${flags[@]}" "$WORK/loader.c" \
|
|
-Wl,-soname,libur_loader.so.0 -Wl,--version-script,"$WORK/loader.map" \
|
|
-o "$WORK/$kind/libur_loader.so.0"
|
|
gcc -shared -fPIC "${flags[@]}" "$WORK/adapter.c" \
|
|
-o "$WORK/$kind/libur_adapter_level_zero.so.0"
|
|
done
|
|
# The ELF loader expands $ORIGIN relative to the loaded library.
|
|
# shellcheck disable=SC2016
|
|
gcc -shared -fPIC "$WORK/sycl.c" -L"$WORK/good" -l:libur_loader.so.0 \
|
|
-Wl,-soname,libsycl.so.9 -Wl,-rpath,'$ORIGIN' \
|
|
-o "$WORK/good/libsycl.so.9"
|
|
|
|
cat > "$WORK/backend.py" <<'PY'
|
|
import ctypes
|
|
import os
|
|
import sys
|
|
|
|
assert sys.argv[1:] == ["--fixture"], sys.argv
|
|
assert os.environ.get("LD_LIBRARY_PATH") == os.environ.get("EXPECTED_PATH"), (
|
|
os.environ.get("LD_LIBRARY_PATH"), os.environ.get("EXPECTED_PATH")
|
|
)
|
|
if os.environ.get("LOAD_SYCL") == "1":
|
|
sycl = ctypes.CDLL(os.path.join(os.environ["VIRTUAL_ENV"], "lib", "libsycl.so.9"))
|
|
assert sycl.syclFixture() == 42
|
|
if "EXPECTED_ORIGIN" in os.environ:
|
|
expected = int(os.environ["EXPECTED_ORIGIN"])
|
|
loader = ctypes.CDLL("libur_loader.so.0")
|
|
assert loader.urFixtureOrigin() == expected
|
|
adapter = ctypes.CDLL("libur_adapter_level_zero.so.0")
|
|
assert adapter.adapterFixture() == expected
|
|
print("fixture passed")
|
|
PY
|
|
|
|
make_backend() {
|
|
local dir="$1" env_dir="${2:-$1}"
|
|
mkdir -p "$dir/common" "$env_dir/venv/bin" "$env_dir/venv/lib" "$env_dir/lib"
|
|
cp "$REPO_ROOT/backend/python/diffusers/run.sh" "$dir/run.sh"
|
|
cp "$REPO_ROOT/backend/python/common/libbackend.sh" "$dir/common/libbackend.sh"
|
|
cp "$WORK/backend.py" "$dir/backend.py"
|
|
cat > "$env_dir/venv/bin/python" <<'SH'
|
|
#!/bin/bash
|
|
exec "$TEST_SYSTEM_PYTHON" "$@"
|
|
SH
|
|
chmod +x "$env_dir/venv/bin/python"
|
|
cp "$WORK/good/"* "$env_dir/venv/lib/"
|
|
cp "$WORK/bad/"* "$env_dir/lib/"
|
|
}
|
|
|
|
launch() {
|
|
(cd "$WORK/cwd"; bash "$1/run.sh" --fixture)
|
|
}
|
|
|
|
expect_failure() {
|
|
if "$@" > "$WORK/failure.log" 2>&1; then
|
|
echo "FAIL: incompatible loader unexpectedly succeeded"
|
|
exit 1
|
|
fi
|
|
# A path assertion or launcher error must not count as the expected failure.
|
|
if ! grep -q 'undefined symbol: urDeviceWaitExp, version LIBUR_LOADER_0.12' "$WORK/failure.log"; then
|
|
cat "$WORK/failure.log"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
backend="$WORK/built/diffusers"
|
|
make_backend "$backend"
|
|
mv "$WORK/built" "$WORK/relocated"
|
|
backend="$WORK/relocated/diffusers"
|
|
export LOAD_SYCL=1 EXPECTED_ORIGIN=1
|
|
|
|
# Reproduce the old ordering using the same venv Python shim and backend file.
|
|
export LD_LIBRARY_PATH="$backend/lib:$WORK/host"
|
|
export EXPECTED_PATH="$LD_LIBRARY_PATH" VIRTUAL_ENV="$backend/venv"
|
|
expect_failure "$backend/venv/bin/python" "$backend/backend.py" --fixture
|
|
unset VIRTUAL_ENV
|
|
|
|
# Both inherited and packaged conflicts lose to the venv runtime.
|
|
export LD_LIBRARY_PATH="$WORK/host" EXPECTED_PATH="$backend/venv/lib:$backend/lib:$WORK/host"
|
|
launch "$backend"
|
|
|
|
# Every startBackend exec branch must receive the same search path.
|
|
export BACKEND_FILE="$backend/backend.py"
|
|
launch "$backend"
|
|
unset BACKEND_FILE
|
|
mv "$backend/backend.py" "$backend/server.py"
|
|
launch "$backend"
|
|
# BACKEND_NAME currently derives from the caller's working directory.
|
|
mv "$backend/server.py" "$backend/cwd.py"
|
|
launch "$backend"
|
|
mv "$backend/cwd.py" "$backend/backend.py"
|
|
|
|
unset LD_LIBRARY_PATH
|
|
export EXPECTED_PATH="$backend/venv/lib:$backend/lib:"
|
|
launch "$backend"
|
|
|
|
# No packaged directory: the venv still takes precedence, with no empty entry
|
|
# introduced when the inherited path is unset.
|
|
mv "$backend/lib" "$backend/packaged"
|
|
export EXPECTED_PATH="$backend/venv/lib"
|
|
launch "$backend"
|
|
export LD_LIBRARY_PATH="$WORK/host" EXPECTED_PATH="$backend/venv/lib:$WORK/host"
|
|
launch "$backend"
|
|
mv "$backend/packaged" "$backend/lib"
|
|
|
|
# The launcher accepts a relative path when its parent directory has spaces;
|
|
# its existing unquoted $0 handling does not accept absolute paths with spaces.
|
|
spaced="$WORK/relocated with spaces"
|
|
make_backend "$spaced/diffusers"
|
|
mkdir -p "$spaced/cwd"
|
|
export EXPECTED_PATH="$spaced/diffusers/venv/lib:$spaced/diffusers/lib:$WORK/host"
|
|
(cd "$spaced/cwd"; bash ../diffusers/run.sh --fixture)
|
|
|
|
separate="$WORK/separate environment"
|
|
make_backend "$WORK/external" "$separate"
|
|
export ENV_DIR="$separate" EXPECTED_PATH="$separate/venv/lib:$separate/lib:$WORK/host"
|
|
launch "$WORK/external"
|
|
unset ENV_DIR
|
|
|
|
# Missing and incompatible venv loaders must still fail, even though the venv
|
|
# directory and SYCL library exist. Presence is not an ABI compatibility check.
|
|
export EXPECTED_PATH="$backend/venv/lib:$backend/lib:$WORK/host"
|
|
rm "$backend/venv/lib/libur_loader.so.0"
|
|
expect_failure launch "$backend"
|
|
cp "$WORK/bad/libur_loader.so.0" "$backend/venv/lib/"
|
|
expect_failure launch "$backend"
|
|
|
|
# Without a SYCL library, unrelated CPU/CUDA files (or even a directory named
|
|
# libsycl.so) must not change the existing library search order.
|
|
rm "$backend/venv/lib/libsycl.so.9"
|
|
mkdir "$backend/venv/lib/libsycl.so"
|
|
touch "$backend/venv/lib/libcublas.so.12" "$backend/venv/lib/libcpu.so"
|
|
export LOAD_SYCL=0 EXPECTED_ORIGIN=2 EXPECTED_PATH="$backend/lib:$WORK/host"
|
|
launch "$backend"
|
|
unset LD_LIBRARY_PATH
|
|
export EXPECTED_PATH="$backend/lib:"
|
|
launch "$backend"
|
|
rm -rf "${backend:?}/lib"
|
|
export LD_LIBRARY_PATH="$WORK/host" EXPECTED_PATH="$WORK/host" EXPECTED_ORIGIN=3
|
|
launch "$backend"
|
|
unset LD_LIBRARY_PATH EXPECTED_PATH EXPECTED_ORIGIN
|
|
launch "$backend"
|
|
|
|
echo "PASS: Intel Python runtime precedence, relocation, fallback and import errors"
|