rustc-wrapper(linker)解决cargo并行链接OOM问题
·
Table of Contents
包转linker的方式
ld_wrapper.sh 并没有验证通过ORZ?
#!/bin/bash
# 通用链接器包装器 - ld_generic_wrapper.sh
PRESSURE_THRESHOLD="0.10" # 内存压力阈值(10%)
MAX_WAIT_TIME=600 # 最大等待时间(秒)
MIN_WAIT_TIME=5 # 最小等待时间(秒)
MAX_RETRIES=100 # 最大重试次数
PRESSURE_FILE="/sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.pressure"
REAL_LD="/usr/bin/ld" # 真实链接器路径,可根据需要修改
LOG_FILE="/tmp/linker_wrapper.log" # 日志文件路径
# 检测真实链接器
detect_real_linker() {
local wrapper_name=$(basename "$0")
case "$wrapper_name" in
*ld*)
REAL_LD="/usr/bin/ld"
;;
*lld*)
REAL_LD="/usr/bin/lld"
;;
*gold*)
REAL_LD="/usr/bin/gold"
;;
*)
REAL_LD="/usr/bin/ld"
;;
esac
# 检查链接器是否存在
if [[ ! -x "$REAL_LD" ]]; then
# 尝试在PATH中查找
REAL_LD=$(which "${wrapper_name#wrapper_}") || REAL_LD="/usr/bin/ld"
fi
}
# 日志函数
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
# 其余函数与之前相同...
get_some_avg10() {
local pressure_file=$1
if [[ -f "$pressure_file" ]]; then
local line=$(grep "^some" "$pressure_file")
if [[ $line =~ avg10=([0-9.]+) ]]; then
echo "${BASH_REMATCH[1]}"
return 0
fi
fi
echo "0.00"
}
wait_for_low_memory_pressure() {
local retry_count=0
local current_pressure
while [[ $retry_count -lt $MAX_RETRIES ]]; do
current_pressure=$(get_some_avg10 "$PRESSURE_FILE")
# 使用bc进行浮点数比较
if command -v bc >/dev/null 2>&1; then
# 如果有bc,进行精确比较
if (( $(echo "$current_pressure < $PRESSURE_THRESHOLD" | bc -l) )); then
log_message "内存压力正常 ($current_pressure < $PRESSURE_THRESHOLD),开始执行链接"
return 0
fi
else
# 如果没有bc,使用bash内置的数值比较(假设压力值小于10)
if (( $(echo "${current_pressure} < ${PRESSURE_THRESHOLD}" | tr -d '.' | head -c3) < $(echo "${PRESSURE_THRESHOLD}" | tr -d '.' | head -c3) )); then
log_message "内存压力正常 ($current_pressure < $PRESSURE_THRESHOLD),开始执行链接"
return 0
fi
fi
# 计算随机等待时间
local wait_time=$(( MIN_WAIT_TIME + RANDOM % (MAX_WAIT_TIME - MIN_WAIT_TIME + 1) ))
log_message "内存压力过高: $current_pressure (阈值: $PRESSURE_THRESHOLD), 等待 ${wait_time}秒后重试 (尝试: $((retry_count + 1))/$MAX_RETRIES)"
# 等待
sleep $wait_time
((retry_count++))
done
log_message "错误: 达到最大重试次数 ($MAX_RETRIES),内存压力仍过高: $current_pressure"
return 1
}
main() {
log_message "链接器包装器被调用,参数: $*"
detect_real_linker
log_message "$(date) - 链接器包装器调用: $REAL_LD, 参数: $*" >> "$LOG_FILE"
if ! wait_for_low_memory_pressure; then
log_message "错误: 内存压力持续过高" >&2
return 1
fi
log_message "执行真实链接器: $REAL_LD $*"
exec "$REAL_LD" "$@"
}
main "$@"
修改cargo编译使用的链接器
# 临时生效: 使脚本可执行
chmod +x /path/to/ld_wrapper.sh
# 配置RUSTFLAGS环境变量
export RUSTFLAGS="-C link-arg=-fuse-ld=/path/to/ld_wrapper.sh"
cargo build
# 或者配置
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=$(realpath /path/to/wrap-ld.sh)
# 创建符号链接
ln -s /path/to/ld_generic_wrapper.sh /path/to/wrapper_ld
ln -s /path/to/ld_generic_wrapper.sh /path/to/wrapper_lld
ln -s /path/to/ld_generic_wrapper.sh /path/to/wrapper_gold
# 在cargo配置中使用
[target.x86_64-unknown-linux-gnu]
linker = "/path/to/wrapper_ld"
# 实时查看日志
tail -f /tmp/ld_wrapper.log
# 监控内存压力变化
watch -n 1 'cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.pressure'
# 检查链接进程
ps aux | grep ld_wrapper
包装rustc进行编译
使用rustc-wrapper.sh
#!/bin/bash
RUSTC_BIN="$1"
shift
PRESSURE_THRESHOLD="0.10"
MAX_WAIT_TIME=60
MIN_WAIT_TIME=5
MAX_RETRIES=60
PRESSURE_FILE="/sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.pressure"
get_some_avg10() {
if [[ -f "$PRESSURE_FILE" ]]; then
local line=$(grep "^some" "$PRESSURE_FILE")
if [[ $line =~ avg10=([0-9.]+) ]]; then
echo "${BASH_REMATCH[1]}"
return 0
fi
fi
# 默认返回 0.00,表示没有压力
echo "0.00"
}
# 检查是否为链接阶段:包含 --crate-type=bin 或 cdylib,且不包含 --print(避免干扰 Cargo 查询)
if [[ "$*" == *"--crate-type bin"* || "$*" == *"--crate-type cdylib"* ]] && [[ "$*" != *"--print"* ]]; then
echo '****************Linker stage ...****************'
retry_count=0
while [[ $retry_count -lt 100 ]]; do
current_pressure=$(get_some_avg10 "$PRESSURE_FILE")
# 使用bc进行浮点数比较
if command -v bc >/dev/null 2>&1; then
if (( $(echo "$current_pressure < $PRESSURE_THRESHOLD" | bc -l) )); then
echo "****************内存压力正常 ($current_pressure < $PRESSURE_THRESHOLD),开始执行 rustc****************"
break
fi
else
echo "****************必须安装bc工具计算浮点运算****************"
exit 1
fi
# 计算随机等待时间
wait_time=$(( MIN_WAIT_TIME + RANDOM % (MAX_WAIT_TIME - MIN_WAIT_TIME + 1) ))
echo "****************内存压力过高: $current_pressure (阈值: $PRESSURE_THRESHOLD), 等待 ${wait_time}秒后重试 (尝试: $((retry_count + 1))/$MAX_RETRIES)****************"
sleep $wait_time
((retry_count++))
done
fi
exec "$RUSTC_BIN" "$@"