프로세스 보기: ps, top, htop
실행 중인 프로그램 하나하나를 프로세스라고 한다. 프로세스마다 PID라는 번호가 붙고, 멈추거나 상태를 볼 때 이 번호를 쓴다.
ps는 지금 터미널에서 띄운 프로세스를 보여 준다.
$ ps
PID TTY TIME CMD
454500 pts/3 00:00:00 bash
454505 pts/3 00:00:00 sleep
454506 pts/3 00:00:00 ps
내 프로세스 전체를 보려면 ps -u $USER, 시스템 전체는 ps aux다. 이름으로 찾을 때는 grep과 잇는다.
$ ps aux | grep orca
top은 CPU를 많이 쓰는 순서로 프로세스를 실시간으로 보여 준다. q로 나간다.
htop은 색과 코어별 막대가 있어 읽기 쉬운 버전인데, 설치되어 있지 않을 수 있다(sudo apt install htop).
top - 00:13:21 up 11:37, 1 user, load average: 9.72, 9.24, 5.89
Tasks: 392 total, 2 running, 389 sleeping, 0 stopped, 1 zombie
%Cpu(s): 23.6 us, 2.2 sy, 0.0 ni, 73.0 id, 1.1 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 30962.3 total, 2806.1 free, 12789.0 used, 16344.9 buff/cache
MiB Swap: 8192.0 total, 8190.8 free, 1.2 used. 18173.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
| 항목 | 뜻 |
|---|---|
load average | 최근 1, 5, 15분 동안 CPU를 기다리거나 쓰던 프로세스 수의 평균. 코어 수(nproc)보다 크면 과부하다. |
%CPU | 코어 하나를 100%로 친 사용률. 8코어로 도는 프로그램은 800% 가까이 나온다. |
RES | 실제로 차지한 메모리 |
S | 상태. R 실행 중, S 대기, T 멈춤, Z 좀비 |
ORCA를 병렬로 돌리면 orca_scf_mpi 같은 프로세스가 코어 수만큼 보인다. 계산이 도는데 %CPU가 100% 근처에서만 머문다면
병렬 설정이 제대로 안 먹은 것이다.
클러스터에 ssh로 접속하면 처음 도착하는 곳은 로그인 노드다. 수백 명이 같이 쓰는 기계라 여기서 무거운 계산을 돌리면
모두가 느려지고, 관리자가 프로세스를 강제로 끝내거나 계정에 경고를 보낸다. 계산은 스케줄러(PBS의 qsub 등)로
계산 노드에 보낸다(09장). 파일 정리, 편집, 짧은 grep 정도만 로그인 노드에서 한다.
멈추기: Ctrl+C와 kill
앞에서 돌고 있는 명령은 Ctrl+C로 중단한다. 다른 터미널에서 돌고 있거나 화면이 굳은 프로그램은 PID를 알아내 kill로 끝낸다.
$ kill 454505 # 종료 요청 (SIGTERM)
$ kill -9 454505 # 강제 종료 (SIGKILL)
그냥 kill은 프로그램에 정리하고 끝내라는 신호를 보낸다. 대부분 이것으로 끝난다.
kill -9는 프로그램이 거부할 수 없는 강제 종료라 임시 파일이 남을 수 있다. 먼저 kill을 쓰고, 안 들으면 -9를 쓴다.
다른 사람의 프로세스는 끝낼 수 없다. 스케줄러로 제출한 계산은 kill이 아니라 qdel <작업 번호>(PBS)로 취소한다.
백그라운드 실행
명령 끝에 &를 붙이면 백그라운드에서 돌고 프롬프트가 바로 돌아온다. 이미 앞에서 돌고 있는 명령은 Ctrl+Z로 일시 정지한 뒤
bg로 백그라운드에 보낸다. 아래 예제는 긴 계산 대신 sleep(지정한 초만큼 기다리는 명령)을 썼다.
$ sleep 600 &
[1] 453276
$ sleep 900 &
[2] 453277
$ jobs
[1]- Running sleep 600 &
[2]+ Running sleep 900 &
$ kill %1
$ jobs
[1]- Terminated sleep 600
[2]+ Running sleep 900 &
| 명령 | 하는 일 |
|---|---|
cmd & | 백그라운드에서 실행 |
Ctrl+Z | 앞에서 도는 명령을 일시 정지 |
bg | 정지한 명령을 백그라운드에서 계속 |
fg | 백그라운드 명령을 앞으로 가져오기 (fg %2) |
jobs | 이 터미널의 백그라운드 작업 목록 |
kill %1 | 작업 번호 1 종료 |
터미널을 닫아도 계속 돌게: nohup
&만 붙인 프로그램은 터미널을 닫거나 ssh 접속이 끊기면 같이 죽을 수 있다. nohup을 앞에 붙이면 끊겨도 계속 돈다.
출력은 파일로 받아 둔다.
$ cd ~/proj/h2o-opt
$ nohup orca water.inp > water.out 2>&1 &
출력을 따로 지정하지 않으면 nohup: ignoring input and appending output to 'nohup.out'이라는 메시지와 함께 nohup.out에 쓴다.
WSL이나 개인 워크스테이션에서 짧은 계산을 돌릴 때 쓰는 방법이다. 클러스터에서는 스케줄러를 쓰고, 긴 대화형 작업은 tmux에서 한다.
환경 변수
셸은 설정값을 이름 붙은 변수로 들고 있다. $를 붙여 값을 꺼낸다. 이 중 자식 프로세스(셸이 실행하는 프로그램)에게까지 전달되는 것을
환경 변수라고 한다.
$ echo $HOME
/home/kim
$ echo $USER
kim
$ name=water
$ echo $name
water
$ bash -c 'echo child sees: [$name]'
child sees: []
$ export name
$ bash -c 'echo child sees: [$name]'
child sees: [water]
= 앞뒤에 공백을 넣으면 안 된다(name = water는 name이라는 명령을 실행하려 한다).
그냥 만든 변수는 지금 셸 안에서만 보이고, export를 해야 그 셸이 실행하는 프로그램에도 전달된다.
ORCA나 xtb가 읽는 설정은 모두 export된 환경 변수여야 한다. env나 printenv는 환경 변수 전체를 출력한다.
변수와 따옴표를 스크립트에서 쓰는 법은 셸 가이드에서 자세히 다룬다.
PATH와 which
ls라고 치면 셸은 PATH 변수에 적힌 디렉터리들을 앞에서부터 차례로 뒤져 ls라는 실행 파일을 찾는다.
command not found는 이 디렉터리들 어디에도 없다는 뜻이다.
$ echo $PATH | tr ':' '\n'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/snap/bin
$ which grep
/usr/bin/grep
$ command -v cd
cd
WSL에서는 이 뒤에 /mnt/c/...로 시작하는 Windows 경로가 줄줄이 붙어 있다. Windows 프로그램을 WSL에서 부를 수 있게 해 둔 것이다.
which와 command -v는 실제로 실행될 프로그램의 위치를 알려 준다. command -v는 cd 같은 셸 내장 명령도 찾으므로 스크립트에서는 이쪽을 쓴다.
프로그램을 홈에 설치했다면 그 디렉터리를 PATH 앞에 붙인다.
export PATH=$HOME/orca:$PATH
기존 $PATH를 빼고 export PATH=$HOME/orca라고 쓰면 ls조차 찾지 못하게 된다. 그럴 때는 터미널을 새로 열면 복구된다.
Ubuntu 데스크톱에서 which orca를 치면 /usr/bin/orca가 나올 수 있다. 이것은 GNOME 화면 낭독기이고 양자화학 프로그램 ORCA가 아니다.
ORCA 디렉터리를 PATH 맨 앞에 두고, 병렬 계산에서는 ORCA를 전체 경로($HOME/orca/orca water.inp)로 부른다.
.bashrc와 .bash_profile
export한 변수는 터미널을 닫으면 사라진다. 매번 쓸 설정은 bash가 시작할 때 읽는 파일에 적는다.
| 파일 | 읽는 때 |
|---|---|
~/.bashrc | 대화형 셸을 열 때마다. 터미널 새 탭, WSL 창 등 |
~/.bash_profile (없으면 ~/.profile) | 로그인할 때 한 번. ssh 접속 등 |
두 파일을 나눠 관리하면 헷갈리므로, 설정은 ~/.bashrc에 모으고 ~/.bash_profile이 그것을 읽게 하는 방식이 흔하다.
Ubuntu의 기본 ~/.profile은 이미 ~/.bashrc를 읽는다. 클러스터에서는 ~/.bash_profile에 아래 줄이 있는지 확인한다.
# ~/.bash_profile
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
~/.bashrc를 고친 뒤 새 터미널을 열거나 source ~/.bashrc를 치면 반영된다. source는 파일 내용을 지금 셸에서 그대로 실행한다.
macOS의 zsh는 ~/.zshrc를 읽는다.
alias
자주 치는 긴 명령에 짧은 이름을 붙인다. ~/.bashrc에 적어 두면 매번 쓸 수 있다.
# ~/.bashrc
alias ll='ls -lh'
alias rm='rm -i'
alias e='grep "FINAL SINGLE POINT ENERGY"'
이렇게 두면 e water.out이 grep "FINAL SINGLE POINT ENERGY" water.out으로 펼쳐진다. alias는 대화형 셸에서만 동작하고 스크립트 안에서는 펼쳐지지 않는다.
계산에서 쓰는 환경 변수
계산 프로그램은 코어 수나 메모리 같은 설정을 환경 변수로 받는 경우가 많다.
| 변수 / 명령 | 하는 일 |
|---|---|
OMP_NUM_THREADS | OpenMP 프로그램(xtb, CREST, 수치 라이브러리 등)이 쓸 스레드 수 |
OMP_STACKSIZE | 스레드마다 쓸 스택 메모리. xtb는 4G 정도를 권한다. |
ulimit -s unlimited | 셸이 허용하는 스택 크기 제한을 푼다. 기본은 8192 KB |
$ export OMP_NUM_THREADS=4
$ echo $OMP_NUM_THREADS
4
$ ulimit -s
8192
$ ulimit -s unlimited
$ ulimit -s
unlimited
OMP_NUM_THREADS를 정하지 않으면 프로그램이 기계의 코어를 전부 쓰려 한다. 노트북에서는 다른 작업이 멈추고,
클러스터에서는 요청한 코어보다 많이 쓰게 되어 문제가 된다. 작업 스크립트에서는 요청한 코어 수와 맞춘다.
스택 크기가 작으면 xtb가 큰 분자에서 이유 없이 segfault를 낸다. 구체적인 설정은 xtb 가이드에 있다.