
LA 계산을 파고들고 있어요. 그래서 제가 찾은 내용은 다음과 같습니다.
LA는 5초마다 지수 이동 평균을 계산합니다.
LA(t) = LA(t-1) + EXP_R * (n(t) - LA(t-1))
어디
- LA(t-1) - 마지막 반복에서 기록된 LA입니다.
- EXP_R - 1분, 5분, 15분에 대해 미리 정의된 세 가지 상수입니다.
- n(t) - 시스템의
R
(실행 중) 또는 (중단 불가능한) 프로세스 수D
다음은 이러한 작업(및 일부 부동 소수점 마술)을 수행하는 커널 코드입니다.
unsigned long avenrun[3]; static inline void calc_load(unsigned long ticks) { unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; if (count < 0) { count += LOAD_FREQ; active_tasks = count_active_tasks(); CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); } } static unsigned long count_active_tasks(void) { struct task_struct *p; unsigned long nr = 0; read_lock(&tasklist_lock); for_each_task(p) { if ((p->state == TASK_RUNNING || (p->state & TASK_UNINTERRUPTIBLE))) nr += FIXED_1; } read_unlock(&tasklist_lock); return nr; } #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */ #define LOAD_FREQ (5*HZ) /* 5 sec intervals */ #define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */ #define EXP_5 2014 /* 1/exp(5sec/5min) */ #define EXP_15 2037 /* 1/exp(5sec/15min) */ #define CALC_LOAD(load,exp,n) \ load *= exp; \ load += n*(FIXED_1-exp); \ load >>= FSHIFT;
동일한 작업을 수행하기 위해 간단한 bash 스크립트를 작성했습니다.
#!/usr/bin/env bash set -euo pipefail LA_1=0 LA_5=0 LA_15=0 EXP_1=0.0800 EXP_5=0.0165 EXP_15=0.0055 count() { echo $(ps -eostat | grep -E "R|D" | wc -l) } echo "1 min 5 min 15 min" while true; do n=$(($(count) - 1)) # -1 to eliminate `ps` from the result LA_1=$(bc -l <<<"$LA_1 + $EXP_1 * ($n - $LA_1)") LA_5=$(bc -l <<<"$LA_5 + $EXP_5 * ($n - $LA_5)") LA_15=$(bc -l <<<"$LA_15 + $EXP_15 * ($n - $LA_15)") echo -ne "$LA_1 $LA_5 $LA_15\r" sleep 5 done
하지만 내 대본의 결과는 실제 로스앤젤레스와는 거리가 멀었다. 주요 차이점은 커널이 호출 count_active_tasks()
하고 스크립트가 간단한 ps
.
Bash에서 보다 정확한 활성 작업 수를 얻을 수 있나요? 아니면 제가 다른 곳에서 뭔가 잘못하고 있는 걸까요?
UPD: 잠시 동안 스크립트를 실행했는데 결과는 다음과 같습니다.
1 min 5 min 15 min
.42342580723140551985 .53553677285166903835 .35305247755440928285
실제 로스앤젤레스는 다음과 같습니다.
load average: 0.80, 1.63, 1.54
커널 소스 코드는 LA를 설명하는 이 기사에서 가져왔습니다.https://wiki.nix-pro.com/view/Load_average_explained
UPD: 내 스크립트의 EXP_R 정의는 커널 소스의 정의와 다릅니다. 내 스크립트에서는 실제로 1 - exp_kernel입니다(여기서 exp_kernel은 커널 소스의 정의입니다). 최종 요소는 동일하게 유지되므로 최종 결과에는 영향을 미치지 않습니다.
답변1
내가 사용하고 있던 공식의 오류를 잡아준 @muru에게 감사드립니다. 이는 정확하며 결과는 매우 정확합니다.
#!/usr/bin/env bash
set -euo pipefail
LA_1=0
LA_5=0
LA_15=0
EXP_1=0.9200
EXP_5=0.9835
EXP_15=0.9945
count() {
echo $(ps -eostat | grep -E "R|D" | wc -l)
}
echo "1 min 5 min 15 min"
while true; do
n=$(($(count) - 1))
LA_1=$(bc -l <<<"$LA_1 * $EXP_1 + $n * (1 - $EXP_1)")
LA_5=$(bc -l <<<"$LA_5 * $EXP_5 + $n * (1 - $EXP_5)")
LA_15=$(bc -l <<<"$LA_15 * $EXP_15 + $n * (1 - $EXP_15)")
echo -ne "$LA_1 $LA_5 $LA_15\r"
sleep 5
done