SGE 스케줄러를 통해 array 형 작업 수행하기

DRM에서의 Serial 프로그램 실행하기
많은 수의 job들을 실행하기 위해서는 어떻게 해야 할까? 1,000개의 데이터셋이 있고, 이것을 하나의 프로그램이 실행한다고 한다면, 모두 1,000개의 Shell 스크립트를 작성해서 queue에 넣어야 할것이다. 바로 이러한 자잘한? 문제를 해결하기 위해서 Grid Engine에서는 Array job이라는 해결책을 제시해 주고 있다.
-i 옵션의 인자를 입력으로 받고, -o 인자의 파일에 program의 수행결과를 쓰는 프로그램을 Grid Engine을 통해 제출한다고 하면 아래와 같은 형식의 job 제출 스크립트를 사용할 것이다.
#!sh
#$ -S /bin/bash
~/programs/program -i ~/data/input -o ~/results/output
그런데, 여기서 input1, input2, … input.1000의 총 1,000개의 input이 존재한다면, 각각의 1,000개의 스크립트를 vi를 통해 작성하거나, 좀 배운 사람은 perl이나 python 스크립트를 통해 1,000 개의 별도의 스크립트를 자동으로 생성해주는 스크립트를 만들어 사용할 것이다. ^^
Array job을 이용한 Serial job 수행
그러나, Grid Engine의 Arry jobs를 이용하면 간단하게 한줄의 추가로 이러한 작업을 모두 해결해 줄 수 있다.
#!sh
#$ -S /bin/bash
#$ -t 1-1000
~/programs/program -i ~/data/input.$SGE_TASK_ID -o ~/results/output.$SGE_TASK_ID
Grid Engine의 -t start-end 옵션을 통해서 간단히 1,000개의 개별적인 job을 한번에 수행할 수가 있다. 별도의 작업 없이도 말이다. ^^ -t 를 통해 수행할 Array job의 갯수를 지정하면, 각각의 job은 -t에서 지정한 갯수로 나뉘면서 각 노드에 할당되고 각 노드는 현재 자신이 몇번째 작업을 수행하는지를 $SGE_TASK_ID 변수에 가지고 있어, 이를 통해 Grid Engine이 할당해 준 array를 수행하고 결과를 내게 된다.
이것만으로도 serial 한 job들을 손쉽게 수행할 수 있지만, 좀 더 응용해서 복잡한 문제들을 해결해 보도록 하자.
#!sh
#$ -S /bin/bash
#$ -t 1-1000
if [ ! -e ~/results/output.$SGE_TASK_ID ]
then
~/programs/program -i ~/data/input.$SGE_TASK_ID -o ~/results/output.$SGE_TASK_ID
fi
bash shell의 if를 통해서 job을 할당받은 노드는 결과 파일의 유무를 확인하고 program을 수행하게 된다. 이렇게 스크립트를 통해 해당 결과가 없을때 수행하게 한다면, 후에 하나의 노드를 통해 해당 program을 수행하거나 하는 경우나 실수로 엔터를 잘못 눌러 다시 수행될때( 있으려나 ^^)에 어느 정도 유연성을 줄 수가 있다.
이처럼 아주 간단한 -t 옵션과 $SGE_TASK_ID이지만, bash shell과 만나면서 더욱더 다양하게 응용될 수 있다. 이제 하나씩 살펴 보도록 하자.
각 프로그램마다 옵션을 달리하고자 하는 경우
위의 예제와는 달리 각 실행되는 프로그램마다 옵션을 달리해야 하는 일이 발생한다면 어떻게 해야 할까? cat과 head, tail이 그 문제의 해답이다. 먼저 각 옵션만을 별도의 파일로 작성한다. simulation이라는 프로그램이 있고, 여기서 -s 옵션의 인자를 각각 달리 해주고 싶다면,  SEEDFILE을 하나 만들어서 각각의 라인에는 옵션의 값들을 적어준다.
seeds 파일
=======================
45
90
.
.
.
1,000번째의 옵션값
=======================
#!/bin/sh
#$ -S /bin/bash -t 1-1000
SEEDFILE=~/data/seeds
SEED=$(sed -n -e “$SGE_TASK_ID p” $SEEDFILE)
~/programs/simulation -s $SEED -o ~/results/output.$SGE_TASK_ID
이렇게 되면 -s의 값으로는 45, 90…의 값들이 각각 들어가게 되어 하나의 프로그램이지만 인자가 서로 다른 프로그램들이 Grid Engine을 통해서 실행되게 된다.
파일의 순서가 1이 아닌 0부터 시작한다면, Array job 설정시 -t 0-999 이거~ 안된단다,, 0을 인식 못한단다. 그렇다고 기존에 0부터 매겨진 파일이름을 1부터 시작하도록 바꿔야 하는것인가?
아니다. 간단한 bash로 0부터 시작해 보자.
#!sh
#$ -S /bin/bash
#$ -t 1-1000
let i=$SGE_TASK_ID-1
if [ ! -e ~/results/output.$i ]
then
~/programs/program -i ~/data/input.$i -o ~/results/output.$i
fi
R과 같은 대화형 프로그램을 수행하고자 한다면
-1만 해주면 되는것을,,, ^^ 그럼 이제 마지막으로 좀 더 고급스럽게 array job을 사용해 보도록 하자. R과 같은 대화형? 프로그램을 사용하고자 하는 경우에는 어떻게 처리해야할까? 이런 경우 R을 실행한 후 “EOF”, “/dev/null” 등을 사용해서 각 파일의 값을 R에서 읽고 결과 파일을 생성해 보자.
#!sh
#$ -S /bin/bash
#$ -t 1-10
WORKDIR=/Users/jl566/testing
INFILE=$WORKDIR/data.$SGE_TASK_ID
OUTFILE=$WORKDIR/data.$SGE_TASK_ID.out
# R 실행파일의 경로를 PATHTOR에 지정해준다.
PATHTOR=/common/bin
if [ -e $OUTFILE ]
then
rm -f $OUTFILE
fi
# “EOF” 사이에 원하는 R 커맨드를 입력하고 그 결과 파일을 OUTFILE에 쓴다.
$PATHTOR/R –quiet –no-save > /dev/null <<EOF
x<-read.table(“$INFILE”)
write(mean(x\$V1),”$OUTFILE”)
EOF
여러가지 상황에 대해서 Grid Engine의 Array job을 이용해서 serial job을 간단하게 수행하여, 생산성을 높일 수가 있다. 비록 Grid Engine에 국한되어서 설명되어 있지만, 각각의 상황들은 손쉽게 다른 DRM(PBS, OpenPBS, Torque, LoadLeveler)들에 응용되어 사용될 수 있다.
발췌 : http://hongiiv.tistory.com/428
원본 : http://wiki.gridengine.info/wiki/index.php/Simple-Job-Array-Howto
 

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

1 Response

  1. 서진우 말해보세요:

    매우 유용한 기능인듯 보입니다. 응용분야가 많을듯..특히 바이오쪽과 랜더링쪽의 작업 분산에 적합하겠네요.

페이스북/트위트/구글 계정으로 댓글 가능합니다.