Skip to content

Instantly share code, notes, and snippets.

@junetech
Created August 1, 2025 04:05
Show Gist options
  • Save junetech/2b5529940dbdb4389f0c5ce226302079 to your computer and use it in GitHub Desktop.
Save junetech/2b5529940dbdb4389f0c5ce226302079 to your computer and use it in GitHub Desktop.
Linux stress test using stress-ng
#!/usr/bin/env bash
set -euo pipefail
# ====================================================================
# stress_ng_test.sh: 자동으로 Idle/Load 상태 측정, 로그 수집 및 요약
# Usage: bash stress_ng_test.sh (권한 필요 시 sudo)
# ====================================================================
# --- 온도 추출 함수 ---
get_temp() {
local file="$1" temp
# Tctl 등 신뢰할 수 있는 온도 라벨만 정확히 지정해서 찾음
# 이렇게 하면 NVMe의 high limit 같은 관련 없는 값은 무시됨
temp=$(grep -iE 'Tctl:' "$file" | grep -oE '[0-9]+(\.[0-9]+)?' | sort -nr | head -n1 || true)
if [[ -n "$temp" && "$temp" != "N/A" ]]; then
# 온도가 1000을 넘으면 millidegree로 간주하고 1000으로 나눔 (예: 85000 -> 85.0)
if command -v bc &>/dev/null && (( $(echo "$temp > 1000" | bc -l) )); then
temp=$(echo "scale=1; $temp / 1000" | bc -l)
fi
printf "%.1f" "$temp"
else
printf "N/A"
fi
}
# --- 사용자 설정 ---
DURATION=120 # 부하시 실행 시간(초)
ALL_CPU_COUNT=$(nproc) # CPU 코어 수 자동 탐지
CUSTOM_CPU_COUNT=16 # 사용자 지정 CPU 코어 수 (0은 자동 탐지)
if [[ "$CUSTOM_CPU_COUNT" -gt 0 && "$CUSTOM_CPU_COUNT" -le "$ALL_CPU_COUNT" ]]; then
CPU_COUNT=$(( CUSTOM_CPU_COUNT < ALL_CPU_COUNT ? CUSTOM_CPU_COUNT : ALL_CPU_COUNT ))
else
CPU_COUNT="$ALL_CPU_COUNT"
fi
HOSTNAME=$(hostname)
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# --- 출력 파일명 정의 ---
IDLE_SENSORS="idle_sensors_${HOSTNAME}_${TIMESTAMP}.log"
IDLE_IPMI="idle_ipmi_${HOSTNAME}_${TIMESTAMP}.log"
IDLE_ENERGY="idle_energy_${HOSTNAME}_${TIMESTAMP}.log"
IDLE_FREQ="idle_freq_${HOSTNAME}_${TIMESTAMP}.log"
LOAD_SENSORS="load_sensors_${HOSTNAME}_${TIMESTAMP}.log"
LOAD_IPMI="load_ipmi_${HOSTNAME}_${TIMESTAMP}.log"
LOAD_ENERGY="load_energy_${HOSTNAME}_${TIMESTAMP}.log"
LOAD_FREQ="load_freq_${HOSTNAME}_${TIMESTAMP}.log"
THROTTLE_LOG="throttle_${HOSTNAME}_${TIMESTAMP}.log"
# --- 필수 도구 확인 (ipmitool과 dmesg는 optional) ---
for cmd in sensors stress-ng; do
if ! command -v "$cmd" &>/dev/null; then
echo "Error: '$cmd' 명령을 찾을 수 없습니다. 설치 후 재실행하세요." >&2
exit 1
fi
done
# ipmitool 유무 체크
USE_IPMITOOL=true
if ! command -v ipmitool &>/dev/null; then
echo "Warning: 'ipmitool' 명령을 찾을 수 없습니다. IPMI 로그 생략" >&2
USE_IPMITOOL=false
fi
# dmesg 접근 가능 여부 체크
USE_DMESG=true
if ! dmesg &>/dev/null; then
echo "Warning: dmesg 접근 권한이 없습니다. Thermal 이벤트 로깅 생략" >&2
USE_DMESG=false
fi
# --- Idle 상태 측정 ---
echo "[1/4] Idle 상태 측정..."
sensors > "$IDLE_SENSORS"
if $USE_IPMITOOL; then ipmitool sensor > "$IDLE_IPMI"; else echo "N/A" > "$IDLE_IPMI"; fi
if [[ -r /sys/class/powercap/intel-rapl:0/energy_uj ]]; then cat /sys/class/powercap/intel-rapl:0/energy_uj > "$IDLE_ENERGY"; else echo "N/A" > "$IDLE_ENERGY"; fi
if [[ -r /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq ]]; then cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq > "$IDLE_FREQ"; else echo "N/A" > "$IDLE_FREQ"; fi
echo " -> Idle 로그 생성"
# --- CPU 부하 실행 ---
trap 'echo "Interrupted"; kill -TERM "$STRESS_PID" &>/dev/null; exit 1' INT TERM
echo "[2/4] CPU 부하 시작: stress-ng --cpu $CPU_COUNT --timeout ${DURATION}s"
stress-ng --cpu "$CPU_COUNT" --timeout "${DURATION}s" --metrics-brief &
STRESS_PID=$!
wait "$STRESS_PID"
echo " -> 부하 완료"
# --- Load 상태 측정 ---
echo "[3/4] Load 상태 측정..."
sensors > "$LOAD_SENSORS"
if $USE_IPMITOOL; then ipmitool sensor > "$LOAD_IPMI"; else echo "N/A" > "$LOAD_IPMI"; fi
if [[ -r /sys/class/powercap/intel-rapl:0/energy_uj ]]; then cat /sys/class/powercap/intel-rapl:0/energy_uj > "$LOAD_ENERGY"; else echo "N/A" > "$LOAD_ENERGY"; fi
if [[ -r /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq ]]; then cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq > "$LOAD_FREQ"; else echo "N/A" > "$LOAD_FREQ"; fi
if $USE_DMESG; then dmesg | grep -iE "thermal|throttl" > "$THROTTLE_LOG" || true; else echo "N/A" > "$THROTTLE_LOG"; fi
echo " -> Load 로그 생성"
# --- 결과 요약 ---
echo "[4/4] 결과 요약"
IDLE_TEMP=$(get_temp "$IDLE_SENSORS")
MAX_TEMP=$(get_temp "$LOAD_SENSORS")
# 수정된 코드 (더욱 안정적인 방식으로 쓰로틀 카운트)
if [[ -f "$THROTTLE_LOG" ]]; then
THROTTLE_COUNT=$(grep -c -iE 'thermal|throttl' "$THROTTLE_LOG")
else
THROTTLE_COUNT=0
fi
echo " - Idle 온도: ${IDLE_TEMP}°C"
echo " - 부하 최대 온도: ${MAX_TEMP}°C"
echo " - 쓰로틀 이벤트 수: ${THROTTLE_COUNT}"
# 평균 전력 계산
if command -v bc &>/dev/null && [[ -f "$IDLE_ENERGY" && -f "$LOAD_ENERGY" ]]; then
E_IDLE=$(cat "$IDLE_ENERGY") E_LOAD=$(cat "$LOAD_ENERGY")
if [[ "$E_IDLE" != "N/A" && "$E_LOAD" != "N/A" ]]; then
AVG_PWR=$(echo "scale=2;($E_LOAD-$E_IDLE)/($DURATION*1000000)" | bc -l)
echo " - 평균 전력: ${AVG_PWR} W"
fi
fi
# 워크로드 분류 (수정된 구문)
if command -v bc &>/dev/null && [[ "$MAX_TEMP" != "N/A" ]]; then
# bc를 사용하여 조건을 확인하고 결과를 변수에 저장 (1=참, 0=거짓)
IS_OVER_95=$(echo "$MAX_TEMP>=95" | bc -l)
IS_UNDER_90=$(echo "$MAX_TEMP<90" | bc -l)
# 표준 [[...]] 구문을 사용하여 명확하게 논리 검사
if [[ "$IS_OVER_95" -eq 1 || "$THROTTLE_COUNT" -gt 0 ]]; then
CLASS="Thermal limit 워크로드"
elif [[ "$IS_UNDER_90" -eq 1 ]]; then
CLASS="안전 워크로드"
else
CLASS="주의 워크로드"
fi
echo " - 분류: $CLASS"
fi
echo -e "\n로그 파일 목록:"
printf '%s\n' "$IDLE_SENSORS" "$IDLE_IPMI" "$IDLE_ENERGY" "$IDLE_FREQ" \
"$LOAD_SENSORS" "$LOAD_IPMI" "$LOAD_ENERGY" "$LOAD_FREQ" "$THROTTLE_LOG"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment