|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -uo pipefail |
| 4 | + |
| 5 | +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" |
| 6 | +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" |
| 7 | + |
| 8 | +SRC_ROOT="${SRC_ROOT:-${PTOAS_OUT_DIR:-${REPO_ROOT}/build/output}}" |
| 9 | +OUTPUT_ROOT="${OUTPUT_ROOT:-${REPO_ROOT}/build/output_npu_validation}" |
| 10 | +LOG_ROOT="${LOG_ROOT:-${REPO_ROOT}/build/output_npu_validation_log}" |
| 11 | +PYTHON_BIN="${PYTHON_BIN:-python3}" |
| 12 | +RUN_MODE="${RUN_MODE:-npu}" |
| 13 | +SOC_VERSION="${SOC_VERSION:-Ascend950}" |
| 14 | +CASE_FILTER="${CASE_FILTER:-}" |
| 15 | +SAMPLE_FILTER="${SAMPLE_FILTER:-}" |
| 16 | + |
| 17 | +usage() { |
| 18 | + cat <<EOF |
| 19 | +顺序执行 runop.sh 生成的 output 目录下所有 case 的上板验证,并实时打印结果。 |
| 20 | +
|
| 21 | +用法: |
| 22 | + $0 [--src-root <dir>] [--output-root <dir>] [--log-root <dir>] |
| 23 | + [--python <python>] [--run-mode <npu|sim>] [--soc-version <soc>] |
| 24 | + [--sample <sample>] [--case <case>] |
| 25 | +
|
| 26 | +参数: |
| 27 | + --src-root 输入 .cpp 根目录,默认: \$PTOAS_OUT_DIR 或 ${REPO_ROOT}/build/output |
| 28 | + --output-root generate_testcase.py 输出目录,默认: ${REPO_ROOT}/build/output_npu_validation |
| 29 | + --log-root 每个 case 的日志目录,默认: ${REPO_ROOT}/build/output_npu_validation_log |
| 30 | + --python Python 解释器,默认: python3 |
| 31 | + --run-mode 传给 generate_testcase.py 的运行模式,默认: npu |
| 32 | + --soc-version 传给 generate_testcase.py / run.sh 的 SoC,默认: Ascend910B1 |
| 33 | + --sample 仅运行指定 sample 目录,例如 Abs |
| 34 | + --case 仅运行指定 case 名,例如 abs 或 abs-pto |
| 35 | + -h, --help 显示帮助 |
| 36 | +
|
| 37 | +示例: |
| 38 | + $0 |
| 39 | + $0 --sample Abs |
| 40 | + $0 --case abs |
| 41 | + $0 --run-mode sim --soc-version Ascend910 |
| 42 | +EOF |
| 43 | +} |
| 44 | + |
| 45 | +log() { |
| 46 | + printf '[%s] %s\n' "$(date +'%F %T')" "$*" |
| 47 | +} |
| 48 | + |
| 49 | +normalize_case_name() { |
| 50 | + local name="$1" |
| 51 | + name="${name%.cpp}" |
| 52 | + name="${name%-pto}" |
| 53 | + name="${name%_pto}" |
| 54 | + printf '%s\n' "${name}" |
| 55 | +} |
| 56 | + |
| 57 | +matches_filter() { |
| 58 | + local value="$1" |
| 59 | + local filter="$2" |
| 60 | + [[ -z "${filter}" ]] && return 0 |
| 61 | + [[ "${value}" == "${filter}" ]] |
| 62 | +} |
| 63 | + |
| 64 | +while [[ $# -gt 0 ]]; do |
| 65 | + case "$1" in |
| 66 | + --src-root) |
| 67 | + [[ $# -ge 2 ]] || { echo "[ERROR] --src-root 缺少参数" >&2; exit 2; } |
| 68 | + SRC_ROOT="$2" |
| 69 | + shift 2 |
| 70 | + ;; |
| 71 | + --output-root) |
| 72 | + [[ $# -ge 2 ]] || { echo "[ERROR] --output-root 缺少参数" >&2; exit 2; } |
| 73 | + OUTPUT_ROOT="$2" |
| 74 | + shift 2 |
| 75 | + ;; |
| 76 | + --log-root) |
| 77 | + [[ $# -ge 2 ]] || { echo "[ERROR] --log-root 缺少参数" >&2; exit 2; } |
| 78 | + LOG_ROOT="$2" |
| 79 | + shift 2 |
| 80 | + ;; |
| 81 | + --python) |
| 82 | + [[ $# -ge 2 ]] || { echo "[ERROR] --python 缺少参数" >&2; exit 2; } |
| 83 | + PYTHON_BIN="$2" |
| 84 | + shift 2 |
| 85 | + ;; |
| 86 | + --run-mode) |
| 87 | + [[ $# -ge 2 ]] || { echo "[ERROR] --run-mode 缺少参数" >&2; exit 2; } |
| 88 | + RUN_MODE="$2" |
| 89 | + shift 2 |
| 90 | + ;; |
| 91 | + --soc-version) |
| 92 | + [[ $# -ge 2 ]] || { echo "[ERROR] --soc-version 缺少参数" >&2; exit 2; } |
| 93 | + SOC_VERSION="$2" |
| 94 | + shift 2 |
| 95 | + ;; |
| 96 | + --sample) |
| 97 | + [[ $# -ge 2 ]] || { echo "[ERROR] --sample 缺少参数" >&2; exit 2; } |
| 98 | + SAMPLE_FILTER="$2" |
| 99 | + shift 2 |
| 100 | + ;; |
| 101 | + --case) |
| 102 | + [[ $# -ge 2 ]] || { echo "[ERROR] --case 缺少参数" >&2; exit 2; } |
| 103 | + CASE_FILTER="$2" |
| 104 | + shift 2 |
| 105 | + ;; |
| 106 | + -h|--help) |
| 107 | + usage |
| 108 | + exit 0 |
| 109 | + ;; |
| 110 | + *) |
| 111 | + echo "[ERROR] 未知参数: $1" >&2 |
| 112 | + usage >&2 |
| 113 | + exit 2 |
| 114 | + ;; |
| 115 | + esac |
| 116 | +done |
| 117 | + |
| 118 | +[[ -d "${SRC_ROOT}" ]] || { echo "[ERROR] 输入目录不存在: ${SRC_ROOT}" >&2; exit 1; } |
| 119 | +command -v "${PYTHON_BIN}" >/dev/null 2>&1 || { echo "[ERROR] Python 不可用: ${PYTHON_BIN}" >&2; exit 1; } |
| 120 | + |
| 121 | +mkdir -p "${OUTPUT_ROOT}" "${LOG_ROOT}" || { echo "[ERROR] 创建输出目录失败" >&2; exit 1; } |
| 122 | + |
| 123 | +declare -a CPP_FILES=() |
| 124 | +while IFS= read -r -d '' file; do |
| 125 | + [[ "$(basename -- "${file}")" == ._* ]] && continue |
| 126 | + sample_name="$(basename -- "$(dirname -- "${file}")")" |
| 127 | + case_base_name="$(basename -- "${file}" .cpp)" |
| 128 | + case_name="$(normalize_case_name "$(basename -- "${file}")")" |
| 129 | + matches_filter "${sample_name}" "${SAMPLE_FILTER}" || continue |
| 130 | + if [[ -n "${CASE_FILTER}" ]] && [[ "${case_name}" != "${CASE_FILTER}" ]] && [[ "${case_base_name}" != "${CASE_FILTER}" ]]; then |
| 131 | + continue |
| 132 | + fi |
| 133 | + CPP_FILES+=("${file}") |
| 134 | +done < <(find "${SRC_ROOT}" -type f -name "*.cpp" -print0 | sort -z) |
| 135 | + |
| 136 | +TOTAL_COUNT="${#CPP_FILES[@]}" |
| 137 | +if [[ "${TOTAL_COUNT}" -eq 0 ]]; then |
| 138 | + echo "[ERROR] 未找到可执行的 .cpp case: ${SRC_ROOT}" >&2 |
| 139 | + exit 1 |
| 140 | +fi |
| 141 | + |
| 142 | +log "SRC_ROOT=${SRC_ROOT}" |
| 143 | +log "OUTPUT_ROOT=${OUTPUT_ROOT}" |
| 144 | +log "LOG_ROOT=${LOG_ROOT}" |
| 145 | +log "RUN_MODE=${RUN_MODE}" |
| 146 | +log "SOC_VERSION=${SOC_VERSION}" |
| 147 | +log "TOTAL_CASES=${TOTAL_COUNT}" |
| 148 | + |
| 149 | +status_file="$(mktemp -t output_npu_validation.XXXXXX)" |
| 150 | +trap 'rm -f "${status_file}"' EXIT |
| 151 | + |
| 152 | +ok_count=0 |
| 153 | +fail_count=0 |
| 154 | +idx=0 |
| 155 | + |
| 156 | +for cpp in "${CPP_FILES[@]}"; do |
| 157 | + idx=$((idx + 1)) |
| 158 | + sample_name="$(basename -- "$(dirname -- "${cpp}")")" |
| 159 | + case_base="$(basename -- "${cpp}")" |
| 160 | + testcase="$(normalize_case_name "${case_base}")" |
| 161 | + case_output_dir="${OUTPUT_ROOT}/${sample_name}/${testcase}" |
| 162 | + case_log_dir="${LOG_ROOT}/${sample_name}" |
| 163 | + case_log_path="${case_log_dir}/${testcase}.log" |
| 164 | + |
| 165 | + mkdir -p "${case_log_dir}" || { |
| 166 | + printf '%s\t%s\t%s\n' "FAIL" "${sample_name}/${testcase}" "mkdir log dir failed" >> "${status_file}" |
| 167 | + fail_count=$((fail_count + 1)) |
| 168 | + continue |
| 169 | + } |
| 170 | + |
| 171 | + echo |
| 172 | + log "[${idx}/${TOTAL_COUNT}] CASE ${sample_name}/${testcase}" |
| 173 | + log "INPUT=${cpp}" |
| 174 | + log "LOG=${case_log_path}" |
| 175 | + |
| 176 | + { |
| 177 | + echo "[INFO] generate_testcase: ${cpp}" |
| 178 | + "${PYTHON_BIN}" "${REPO_ROOT}/test/npu_validation/scripts/generate_testcase.py" \ |
| 179 | + --input "${cpp}" \ |
| 180 | + --testcase "${testcase}" \ |
| 181 | + --output-root "${OUTPUT_ROOT}" \ |
| 182 | + --run-mode "${RUN_MODE}" \ |
| 183 | + --soc-version "${SOC_VERSION}" |
| 184 | + } 2>&1 | tee "${case_log_path}" |
| 185 | + gen_rc=${PIPESTATUS[0]} |
| 186 | + |
| 187 | + if [[ ${gen_rc} -ne 0 ]]; then |
| 188 | + log "FAIL generate_testcase: ${sample_name}/${testcase} (exit=${gen_rc})" |
| 189 | + printf '%s\t%s\t%s\n' "FAIL" "${sample_name}/${testcase}" "${case_log_path}" >> "${status_file}" |
| 190 | + fail_count=$((fail_count + 1)) |
| 191 | + continue |
| 192 | + fi |
| 193 | + |
| 194 | + if [[ ! -x "${case_output_dir}/run.sh" ]]; then |
| 195 | + echo "[ERROR] run.sh 未生成: ${case_output_dir}/run.sh" | tee -a "${case_log_path}" |
| 196 | + printf '%s\t%s\t%s\n' "FAIL" "${sample_name}/${testcase}" "${case_log_path}" >> "${status_file}" |
| 197 | + fail_count=$((fail_count + 1)) |
| 198 | + continue |
| 199 | + fi |
| 200 | + |
| 201 | + ( |
| 202 | + cd "${case_output_dir}" || exit 1 |
| 203 | + env RUN_MODE="${RUN_MODE}" SOC_VERSION="${SOC_VERSION}" ./run.sh |
| 204 | + ) 2>&1 | tee -a "${case_log_path}" |
| 205 | + run_rc=${PIPESTATUS[0]} |
| 206 | + |
| 207 | + if [[ ${run_rc} -eq 0 ]]; then |
| 208 | + log "OK ${sample_name}/${testcase}" |
| 209 | + printf '%s\t%s\t%s\n' "OK" "${sample_name}/${testcase}" "${case_log_path}" >> "${status_file}" |
| 210 | + ok_count=$((ok_count + 1)) |
| 211 | + else |
| 212 | + log "FAIL run.sh: ${sample_name}/${testcase} (exit=${run_rc})" |
| 213 | + printf '%s\t%s\t%s\n' "FAIL" "${sample_name}/${testcase}" "${case_log_path}" >> "${status_file}" |
| 214 | + fail_count=$((fail_count + 1)) |
| 215 | + fi |
| 216 | +done |
| 217 | + |
| 218 | +echo |
| 219 | +echo "========== NPU VALIDATION SUMMARY ==========" |
| 220 | +echo "TOTAL=${TOTAL_COUNT} OK=${ok_count} FAIL=${fail_count}" |
| 221 | + |
| 222 | +if [[ ${fail_count} -gt 0 ]]; then |
| 223 | + echo "---------- FAIL CASES ----------" |
| 224 | + while IFS=$'\t' read -r st case_name log_path; do |
| 225 | + [[ "${st}" == "FAIL" ]] || continue |
| 226 | + echo "${case_name} FAIL" |
| 227 | + echo "log: ${log_path}" |
| 228 | + done < "${status_file}" |
| 229 | + exit 1 |
| 230 | +fi |
| 231 | + |
| 232 | +echo "All cases passed." |
| 233 | +exit 0 |
0 commit comments