Repository navigation
Expand file tree
/
Copy pathjob.sh
More file actions
109 lines (96 loc) · 4.16 KB
/
Copy pathjob.sh
File metadata and controls
109 lines (96 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/bin/bash
# QKV-Bench 单次评测 job —— 一个实现 × 一个测试组,拉起一对全新容器。
#
# 硬约束(不要为省时间破坏):
# 1. 每个 job = 1 个被测服务容器 + 1 个专属压测端容器,用完即销毁
# 2. 一个容器只跑一个测试组,绝不复用
# 3. 同一测试组内,所有实现的服务端与压测端规格字面相同
# 4. 服务端 4 核 / 3G,压测端 8 核 / 6G,两者 cpuset 不重叠
# 5. agent 目录只读挂载,绝不写回
#
# bash job.sh <agent> <G1..G6>
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE="${QKV_IMAGE:-qkv-bench:1}"
export MSYS_NO_PATHCONV=1
AGENT="${1:?usage: job.sh <agent> <group>}"
GROUP="${2:?usage: job.sh <agent> <group>}"
# ---- 规格常量:同组内所有实现必须完全一致 -------------------------------
SRV_CPUSET="0-3" # 被测服务端:4 核
LG_CPUSET="4-11" # 压测端:8 核,与服务端不重叠
SRV_MEM="3g"
LG_MEM="6g"
SRV_PIDS="128"
NOFILE="65536"
PORT="7777"
SRV="qkv-job-srv"
LG="qkv-job-lg"
DIR="$ROOT/arena/agents/$AGENT"
OUTDIR="${QKV_OUT:-$ROOT/results}/$AGENT"
winpath() { command -v cygpath >/dev/null 2>&1 && cygpath -m "$1" || printf '%s' "$1"; }
wait_name_free() {
for _ in $(seq 1 40); do
docker inspect "$1" >/dev/null 2>&1 || return 0
sleep 0.5
done
}
teardown() {
docker rm -f "$LG" "$SRV" >/dev/null 2>&1 || true
wait_name_free "$LG"; wait_name_free "$SRV"
}
trap teardown EXIT
[ -d "$DIR" ] || { echo "!! 目录不存在: $DIR"; exit 1; }
[ -f "$DIR/run.sh" ] || { echo "!! $AGENT 没有 run.sh"; exit 1; }
mkdir -p "$OUTDIR"
teardown
echo "[$AGENT/$GROUP] srv=$SRV_CPUSET/$SRV_MEM lg=$LG_CPUSET/$LG_MEM image=$IMAGE"
# ---- 被测服务端容器 ------------------------------------------------------
docker run -d --name "$SRV" --hostname "$AGENT" \
--cpuset-cpus "$SRV_CPUSET" --memory "$SRV_MEM" \
--pids-limit "$SRV_PIDS" --ulimit "nofile=$NOFILE:$NOFILE" \
--cap-drop ALL --cap-add SYS_PTRACE \
--network none \
-e "QKV_PORT=$PORT" \
-v "$(winpath "$DIR"):/src:ro" \
"$IMAGE" bash -c 'cp -r /src /work && cd /work && bash build.sh && exec bash run.sh' >/dev/null || {
echo "!! [$AGENT/$GROUP] 服务端容器启动失败"; exit 1; }
# 编译 + 启动可能耗时,轮询监听端口最多 5 分钟(编译) + 20 秒(启动)
listeners=0
for _ in $(seq 1 640); do
listeners=$(docker exec "$SRV" bash -c "ss -ltn 2>/dev/null | grep -c ':$PORT'" 2>/dev/null || echo 0)
[ "$listeners" -ge 1 ] && break
docker inspect -f '{{.State.Running}}' "$SRV" 2>/dev/null | grep -q true || {
echo "!! [$AGENT/$GROUP] 服务端容器已退出(编译或启动失败)"
docker logs "$SRV" 2>&1 | tail -12; exit 1; }
sleep 0.5
done
if [ "$listeners" -lt 1 ]; then
echo "!! [$AGENT/$GROUP] 服务 5 分钟内未监听 $PORT"; docker logs "$SRV" 2>&1 | tail -12; exit 1
fi
# ---- 专属压测端容器(共享服务端 net+pid 命名空间以采集其资源)----------
docker run -d --name "$LG" \
--network "container:$SRV" --pid "container:$SRV" \
--cpuset-cpus "$LG_CPUSET" --memory "$LG_MEM" \
--ulimit "nofile=$NOFILE:$NOFILE" \
-v "$(winpath "$ROOT/harness"):/opt/qkvh:ro" \
"$IMAGE" bash -c 'cp -r /opt/qkvh /tmp/h && sleep infinity' >/dev/null || {
echo "!! [$AGENT/$GROUP] 压测端容器创建失败"; exit 1; }
for _ in $(seq 1 40); do
[ "$(docker inspect -f '{{.State.Status}}' "$LG" 2>/dev/null)" = "running" ] && break
sleep 0.5
done
# 编译压测器
docker exec "$LG" bash -c '
set -e
cd /tmp/h/loadgen/qkvload && cargo build --release --offline >/dev/null 2>&1
cp target/release/qkvload /tmp/qkvload
' || { echo "!! [$AGENT/$GROUP] 压测器编译失败"; exit 1; }
# ---- 跑指定的一组 --------------------------------------------------------
docker exec "$LG" bash -c \
"cd /tmp/h && QKV_PORT=$PORT python3 loadgen/suite.py --loadgen /tmp/qkvload --label $AGENT --only $GROUP --out /tmp/$GROUP.json" \
| tee "$OUTDIR/$GROUP.txt"
if docker cp "$LG:/tmp/$GROUP.json" "$(winpath "$OUTDIR")/$GROUP.json" >/dev/null 2>&1; then
echo "[$AGENT/$GROUP] -> results/$AGENT/$GROUP.json"
else
echo "!! [$AGENT/$GROUP] 结果 JSON 拷出失败"; exit 1
fi