char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Max Krasnyanskysnapdragon: ci updates to use new run script (#28293)d30500b83

char/aliceai-t5-moe
6.7 KiB234 linesraw
1#!/bin/bash
2# llama.cpp Hexagon test entry script for QDC Linux IoT (BASH framework).
3#
4# Placeholders substituted by run_qdc_jobs.py (--platform linux) before upload:
5#   {MODEL_URL}   direct URL to a .gguf model file
6#   {TEST_MODE}   bench | backend-ops | all
7#
8# QDC extracts the artifact zip to /data/local/tmp/TestContent/ and invokes
9# this script via: /bin/bash /data/local/tmp/TestContent/run_linux.sh
10# Any files written under /data/local/tmp/QDC_logs/ are auto-uploaded.
11
12set +e
13umask 022
14
15LOG_DIR=/data/local/tmp/QDC_logs
16BUNDLE_DIR=/data/local/tmp/TestContent/llama_cpp_bundle
17MODEL_DIR=/data/local/tmp/gguf
18MODEL_PATH="$MODEL_DIR/model.gguf"
19RESULTS_XML="$LOG_DIR/results.xml"
20
21mkdir -p "$LOG_DIR" "$MODEL_DIR"
22# Redirect all parent-shell output to script.log so QDC auto-uploads it;
23# per-case runs still capture their own stdout/stderr into dedicated logs.
24exec > "$LOG_DIR/script.log" 2>&1
25
26echo "=== env ==="
27date -u
28uname -a
29pwd
30
31mount -o rw,remount / 2>/dev/null || true
32
33cd "$BUNDLE_DIR" || { echo "FATAL: bundle missing at $BUNDLE_DIR"; exit 1; }
34chmod +x bin/* 2>/dev/null
35export LD_LIBRARY_PATH="$BUNDLE_DIR/lib:$LD_LIBRARY_PATH"
36export ADSP_LIBRARY_PATH="$BUNDLE_DIR/lib"
37export GGML_HEXAGON_EXPERIMENTAL=1
38
39echo "=== download model ==="
40MODEL_URL="{MODEL_URL}"
41if [ -z "$MODEL_URL" ]; then
42  echo "No model URL provided, skipping download"
43elif [ ! -f "$MODEL_PATH" ]; then
44  curl -L -fS --retry 3 --retry-delay 5 -o "$MODEL_PATH" "$MODEL_URL"
45  curl_rc=$?
46  if [ $curl_rc -ne 0 ]; then
47    echo "FATAL: model download failed (rc=$curl_rc)"
48    exit 1
49  fi
50  ls -la "$MODEL_PATH"
51fi
52
53# ---------------------------------------------------------------------------
54# JUnit XML helpers
55# ---------------------------------------------------------------------------
56
57xml_open() {
58  printf '%s\n' \
59    '<?xml version="1.0" encoding="utf-8"?>' \
60    "<testsuites>" \
61    "<testsuite name=\"llama_cpp_linux\">" \
62    > "$RESULTS_XML"
63}
64
65xml_close() {
66  printf '%s\n' '</testsuite>' '</testsuites>' >> "$RESULTS_XML"
67}
68
69xml_case_pass() {
70  local classname=$1 name=$2
71  printf '<testcase classname="%s" name="%s"/>\n' "$classname" "$name" >> "$RESULTS_XML"
72}
73
74xml_case_fail() {
75  local classname=$1 name=$2 rc=$3 logfile=$4
76  {
77    printf '<testcase classname="%s" name="%s">\n' "$classname" "$name"
78    printf '<failure message="exit %s"><![CDATA[\n' "$rc"
79    tail -c 4096 "$logfile" 2>/dev/null | sed 's/]]>/]] >/g'
80    printf '\n]]></failure>\n</testcase>\n'
81  } >> "$RESULTS_XML"
82}
83
84# Map backend name -> "NDEV --device" pair. "none" means no offload (CPU).
85backend_env() {
86  case "$1" in
87    cpu) echo "0 none" ;;
88    gpu) echo "0 GPUOpenCL" ;;
89    npu) echo "1 HTP0" ;;
90  esac
91}
92
93backend_log_name() {
94  case "$1" in
95    cpu) echo "cpu" ;;
96    gpu) echo "gpu" ;;
97    npu) echo "htp" ;;
98  esac
99}
100
101
102backend_device_name() {
103  case "$1" in
104    cpu) echo "none" ;;
105    gpu) echo "GPUOpenCL" ;;
106    npu) echo "HTP0" ;;
107  esac
108}
109
110# Append a diagnostic block when a per-case `timeout N` fires (rc=124). The
111# naked log file at that point usually just ends mid-OpenCL-init with no
112# stderr, which is hard to read in CI summaries.
113note_timeout_if_triggered() {
114  local rc=$1 budget=$2 log=$3
115  [ "$rc" -eq 124 ] || return 0
116  {
117    printf '\n'
118    printf '=== TIMEOUT after %ss ===\n' "$budget"
119    printf 'uptime: '; uptime 2>/dev/null
120    printf 'free -m:\n'; free -m 2>/dev/null
121    printf 'loadavg: '; cat /proc/loadavg 2>/dev/null
122  } >> "$log"
123}
124
125completion_extra_args() {
126  case "$1" in
127    cpu) echo "--device none --ctx-size 2048 -no-cnv -n 32 --seed 42" ;;
128    gpu) echo "--device GPUOpenCL --ctx-size 2048 -no-cnv -n 32 --seed 42" ;;
129    npu) echo "--device HTP0 --ctx-size 2048 -no-cnv -n 32 --seed 42 --ubatch-size 1024" ;;
130  esac
131}
132
133run_completion_case() {
134  local name=$1
135  local parts=($(backend_env "$name"))
136  local ndev=${parts[0]} device=${parts[1]}
137  local device_log_name=$(backend_device_name "$name")
138  local log="$LOG_DIR/llama_completion_${device_log_name}.log"
139  local prompt="$LOG_DIR/bench_prompt.txt"
140  echo 'What is the capital of France?' > "$prompt"
141  local extra
142  extra=$(completion_extra_args "$name")
143  echo "=== [completion:$name] llama-completion --device $device (NDEV=$ndev) ==="
144  timeout 600 env GGML_HEXAGON_NDEV=$ndev ./bin/llama-completion \
145      -m "$MODEL_PATH" \
146      -f "$prompt" \
147      $extra \
148      > "$log" 2>&1 < /dev/null
149  local rc=$?
150  note_timeout_if_triggered "$rc" 600 "$log"
151  if [ $rc -eq 0 ]; then
152    xml_case_pass "tests.test_bench_posix" "test_llama_completion[$name]"
153  else
154    xml_case_fail "tests.test_bench_posix" "test_llama_completion[$name]" "$rc" "$log"
155  fi
156}
157
158run_bench_case() {
159  local name=$1
160  local parts=($(backend_env "$name"))
161  local ndev=${parts[0]} device=${parts[1]}
162  local log_suffix=$(backend_log_name "$name")
163  local log="$LOG_DIR/llama_bench_${log_suffix}.log"
164  local ubatch_arg=""
165  [ "$name" = "npu" ] && ubatch_arg="--ubatch-size 1024"
166  echo "=== [bench:$name] llama-bench --device $device (NDEV=$ndev) ==="
167  timeout 600 env GGML_HEXAGON_NDEV=$ndev ./bin/llama-bench \
168      -m "$MODEL_PATH" \
169      --device "$device" \
170      -ngl 99 \
171      $ubatch_arg \
172      -t 4 \
173      -p 128 \
174      -n 32 \
175      > "$log" 2>&1
176  local rc=$?
177  note_timeout_if_triggered "$rc" 600 "$log"
178  if [ $rc -eq 0 ]; then
179    xml_case_pass "tests.test_bench_posix" "test_llama_bench[$name]"
180  else
181    xml_case_fail "tests.test_bench_posix" "test_llama_bench[$name]" "$rc" "$log"
182  fi
183}
184
185run_backend_ops_case() {
186  local dtype=$1
187  local log="$LOG_DIR/backend_ops_${dtype}.log"
188  local pattern
189  case "$dtype" in
190    q4_0)
191      # Matches Android: exclude a known-broken shape on NPU.
192      pattern='^(?=.*type_a=q4_0)(?!.*type_b=f32,m=576,n=512,k=576).*$'
193      ;;
194    *)
195      pattern="type_a=${dtype}"
196      ;;
197  esac
198  echo "=== [backend-ops:$dtype] test-backend-ops -b HTP0 -o MUL_MAT ==="
199  timeout 600 env GGML_HEXAGON_NDEV=1 GGML_HEXAGON_HOSTBUF=0 ./bin/test-backend-ops \
200      -b HTP0 -o MUL_MAT -p "$pattern" \
201      > "$log" 2>&1
202  local rc=$?
203  note_timeout_if_triggered "$rc" 600 "$log"
204  if [ $rc -eq 0 ]; then
205    xml_case_pass "tests.test_backend_ops_posix" "test_backend_ops_htp0[$dtype]"
206  else
207    xml_case_fail "tests.test_backend_ops_posix" "test_backend_ops_htp0[$dtype]" "$rc" "$log"
208  fi
209}
210
211xml_open
212
213case "{TEST_MODE}" in
214  bench)
215    for b in cpu gpu npu; do run_completion_case "$b"; done
216    for b in cpu gpu npu; do run_bench_case "$b"; done
217    ;;
218  backend-ops)
219    for d in mxfp4 fp16 q4_0; do run_backend_ops_case "$d"; done
220    ;;
221  all)
222    for b in cpu gpu npu; do run_completion_case "$b"; done
223    for b in cpu gpu npu; do run_bench_case "$b"; done
224    for d in mxfp4 fp16 q4_0; do run_backend_ops_case "$d"; done
225    ;;
226  *)
227    echo "FATAL: unsupported TEST_MODE={TEST_MODE}"
228    ;;
229esac
230
231xml_close
232echo "=== done ==="
233# Host parses results.xml to decide pass/fail.
234exit 0