Environment modules는 사용자로 하여금 유닉스/리눅스의 환경(environment) 설정을 쉽게 수정할 수 있도록 한다. 예를 들어 응용 프로그램을 두 개의 다른 버전으로 설치하였다고 하자. 응용 프로그램의 실행 파일이름은 runme, 버전은 1.0과 2.0 이라고 하고, 각각의 실행 파일은 아래와 같이 다른 디렉토리에 위치한다고 하자. 

/usr/local/응용프로그램-v1.0/bin/runme
/usr/local/응용프로그램-v2.0/bin/runme

일반적으로는 실행 파일(runme)이 있는 bin 디렉토리를 환경 변수인 경로(PATH)에 등록하여, 사용자가 명령어 창에서 runme만 입력하여도 자동으로 그 실행파일이 있는 디렉토리를 찾아서 해당 프로그램을 실행시키기 마련이다. 그러나, 위 경우에 다른 버전의 두 디렉토리를 모두 등록시켰다가는 항상 먼저 등록된 버전의 runme만 실행된다. 그렇다고 하나만 등록한다고 하면, 다른 버전을 사용할 때마다 매번 경로(PATH)를 수정해야 한다. 게다가 bin 디렉토리 뿐만 아니라 라이브러리 파일이 있는 lib 디렉토리마저도 버전마다 다르게 불러와야 할 경우는 상당히 골치가 아프다. 

Environment modules는 모듈 파일을 이용하여 이런 번거로움을 쉽게 해결해 준다. 예를 들어, 응용프로그램-v1.0과 관련된 설정을 하나의 모듈 파일로, 그리고 응용프로그램-v2.0과 관련된 설정을 다른 모듈 파일로 저장한다. 그리고 필요할 때마다 해당 모듈 파일을 불러오는 것으로 문제 해결이다. 이 글에서는 이미 environment modules가 설치되었다고 가정하고, 아래의 몇 가지 예를 통해서 사용법만 알아 보고자 한다. (설치하려면 소스포지 사이트에서 소스 코드를 다운받아 압축을 푼 후, 그 안에 있는 INSTALL이란 파일에서 2.2 Building and Installing Modules 부분을 참조한다.)

우선 어떤 모듈이 올라와 있는지 보자. (List loaded module files.)
[user@localhost ~]$ module list
No Modulefiles Currently Loaded.
현재로서는 올라와 있는 모듈이 없음을 알 수 있다. 

어떤 모듈들을 불러올 수 있는 확인하려면, 아래와 같다. (List available modules.)
[user@localhost ~]$ module avail
-------------------------------- /opt/modules/Modules/versions ---------------------------------
3.2.6
-------------------------------- /share/apps/modules/modulefiles --------------------------------
abinit/abinit-5.8.4p     intel/intel-9             mvapich/mvapich-1.1-intel-10   openmpi/openmpi-1.3.1-intel-11
fluent/fluent-12-beta   mvapich/mvapich-1.0-intel-10   mvapich/mvapich-1.1-intel-11   pgi/pgi-8.0
intel/intel-10              mvapich/mvapich-1.0-intel-11   mvapich/mvapich-1.1-intel-9    vasp/vasp-4.6
intel/intel-11              mvapich/mvapich-1.0-intel-9    mvapich/mvapich-1.1-pgi-8.0    vasp/vasp-5.2
위에 따르면 환경 모듈의 버전은 3.2.6이고, 그 아래에 불러올 수 있는 모듈들이 나열되어 있다. 

나열된 모듈들 중에 intel/intel-9 과 mvapich/mvapich-1.0-intel-9 를 불러오려면 module load를 이용한다.  
[user@localhost ~]$ module load intel/intel-9 mvapich/mvapich-1.0-intel-9

다음으로 intel/intel-9이란 모듈의 정보를 확인해 보자. (Show/display module information.)
[user@localhost ~]$ module show intel/intel-9       
-------------------------------------------------------------------
/share/apps/modules/modulefiles/intel/intel-9:

conflict         intel 
module-whatis    Provides Intel 9 C and Fortran Compilers 
prepend-path     PATH /opt/intel/cce/9.1.053/bin:/opt/intel/fce/9.1.052/bin:/opt/intel/idbe/9.1.053/bin 
prepend-path     LD_LIBRARY_PATH /opt/intel/fce/9.1.052/lib:/opt/intel/cce/9.1.053/lib 
-------------------------------------------------------------------
위에서 "module-whiatis"를 보면 intel/intel-9 모듈은 인텔 C와 포트란 컴파일러 (버전9)를 위한 환경 설정과 관련되어 있음을 알 수 있다. 그리고, 이 intel/intel-9 모듈 파일이 /share/apps/modules/modulefiles 디렉토리에 위치함을 알 수 있다. 이 모듈은 환경 변수인 PATH와 LD_LIBRARY_PATH에 추가적으로 관련 디렉토리들을 등록함을 알 수 있다. conflict에 대해서는 조금 있다가 설명하겠다.  


인텔 컴파일러 버전 9 대신에 버전 10 모듈을 불러올려면 module switch를 이용한다. (Switch modules.)
[user@localhost ~]$ which icc
/opt/intel/cce/9.1.053/bin/icc
[user@localhost ~]$ module switch intel/intel-9 intel/intel-10
[user@localhost ~]$ which icc
/opt/intel/cce/10.1.022/bin/icc
"module switch 모듈파일1 모듈파일2"라고 입력하면, 올라와 있는 모듈 1을 모듈 2로 바꾼다. 위의 예에서 보듯이 module switch 전후로 인텔 컴파일러 실행 파일인 icc가 다른 버전으로 변환되었음을 알 수 있다. 

만약 switch 대신에 unload/load를 사용할 수도 있다. (Load/unload modulefiles.)
[user@localhost ~]$ module unload intel/intel-10
[user@localhost ~]$ module load intel/intel-9
위 예에서는 intel-9을 불러 오기 전에 intel-10을 먼저 내렸음을 알 수 있다. 

만약 unload를 하지 않으면 어떤 문제가 생기는지 보자. 
[user@localhost ~]$ module load intel/intel-10
intel/intel-10(12):ERROR:150: Module 'intel/intel-10' conflicts with the currently loaded module(s) 'intel/intel-9'
intel/intel-10(12):ERROR:102: Tcl command execution failed: conflict intel
모듈간에 충돌이 생기면서 에러가 생기는데, 이는 intel/intel-9 모듈파일에서 지정한 conflict intel과 연관이 있다. conflict 다음에 하나 또는 그 이상의 모듈파일이 지정되어 있다면, 그 중에 어느 파일과도 동시에 불러올 수 없게 한다. 상기의 예에서는 conflict 다음에 intel이라는 디렉토리를 지정하여 그 디렉토리 안에 있는 모듈 파일들은 동시에 볼러올 수 없도록 한 것이다. 모듈파일 명령어 중에서 conflct처럼 불러오는 모듈파일 사이의 관계를 지정하는 또 다른 명령어로는 prereq이 있다. prereq에 대한 상세한 내용은 

불러온 다수의 모듈파일을 모두 다 내릴려면 purge를 이용한다. (Unload all loaded module files.)
[user@localhost ~]$ module purge
[user@localhost ~]$ module list
No Modulefiles Currently Loaded.

매번 로그인할 때마다 특정 모듈을 불러오기 귀찮다면, 쉘 초기화 파일에 module load를 추가한다. 본인의 경우에는 bash_profile 파일을 아래와 같이 편집하였다.
[user@localhost ~]$ cat >> ~/.bash_profile
module load intel/intel-9 mvapich/mvapich-1.0-intel-9
Ctrl + D
[user@localhost ~]$ source ~/.bash_profile


참조 사이트 1. http://modules.sourceforge.net/
                 2. module manual page
                 3. modulefile manual page
                 4. http://www.cpd.wm.edu/modules.php
Posted by 참향그늘
,
병렬 컴퓨터에서 작업을 하다 보면, 별다른 이유없이 프로그램이 실행되지 않으며 아래와 같은 에러 메시지를 출력할 때가 있다. 

p4_error: OOPS: semop lock failed: -1

대개의 경우, 이는 더 이상의 가용 세마포어 (semaphore, 깃발 신호)가 남아 있지 않아서이다. 이에 대한 해결책을 제시하기에 앞서, 우선 세마포어가 무엇인지부터 간략하게 알아보자.  

세마포어 (semaphore) 란?

복수의 프로세스 (process) 들이 하나의 또는 제한된 공동 자원 (common resources, or shared resources)에 접속을 할 때, 동시 접속을 방지하는 것에 관여하는 메모리 변수를 지칭한다. 메모리 변수라는 점에서 일반 프로그램 변수와 비슷하나, 차이점은 프로그램 변수는 그 프로그램 안에서만 다루어지는데 비하여 semaphore 데이타는 다른 프로세스들에 의해서도 사용된다는 점이다. (출처: The Linux Tutorial

[binary semaphore 의 예]
예를 들어, 하나의 데이타 파일에 접속할 수 있는 프로세스들이 여러 개 있는 상황을 가정하자. 한 프로세스가 파일을 편집하고 있는 상황에서 다른 프로세스의 접속을 허용하면, 데이터 파일이 뒤죽박죽되기 마련이다. 이를 막기 위해서, semaphore 의 값이 on (또는 참값) 이면 접근을 허용하고 그 반대의 경우는 불허하게 정한다. 처음으로 접근하는 프로세스가 semaphore 의 값을 off (또는 거짓값) 으로 바꾸고, 파일 작업이 끝나면 semaphore 의 값을 원래대로 돌린다. 다음에 오는 프로세스들은 이 값이 거짓이면 참이 될 때가지 기다리게 된다. 비유를 하자면 공용 화장실이 하나 밖에 없는데, 사람들이 줄서서 기다리는 상황과 비슷하다. 한 명이 들어가서 문을 잠구면(locked), 나머지는 문이 열릴(unlocked) 때까지 기다리는 수 밖에 없다. (Toilet example

[counting semaphore 의 예]
다른 예로서 식당의 비유 (출처: wiki)를 드는데, 이 비유에서 식당의 자리는 공동 자원에, 찾아오는 손님은 프로세스에 해당한다. 자리의 수는 제한되어 있으므로 찾아오는 손님마다 다 앉힐 수는 없는 노릇이다. 이 경우 식당에 안내하는 사람이 있어서, 자리가 다 차면 손님을 기다리게 하고 자리가 나면 우선 순위의 손님부터 받아들이는 등의 조정을 할 것이다. 이 안내자의 역할이 semaphore 에 해당하는 것이다. 

세마포어에 대해 좀 더 자세히 알고 싶다면 Vikram Shukla 가 쓴 "Semaphores in Linux" 란 웹문서를 추천한다.

이 semaphore 를 포함한 IPC (Inter-Process Communication)들의 크기나 개수는 시스템이 정한 제한이 있다. (출처:Vinay's Tech Stuff

병렬 프로그램들이 비정상적으로 종료한 경우, semaphore가 여전히 그 프로그램에 의해서 사용되고 있는 것으로 남아서 제한된 가용 semaphore을 잠식한다. semop locked failed error 는 이러한 상황에서 연유한다. 그러므로, 사용되지 않는 semaphore array를 지우면 문제가 해결된다. 먼저, 아래의 명령어로 어떤 semaphore가 남아 있는지 알아 보자. 

[user@linuxcluster ~]$ ipcs -s

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 10485790   user   777        1
0x00000000 10518559   user   777        1
0x00000000 10551328   user   777        1
0x00000000 10584097   user   777        1
0x00000000 10616866   user   777        1
0x00000000 10649635   user   777        1
0x00000000 10682404   user   777        1
0x00000000 10715173   user   777        1
0x00000000 10747942   user   777        1
0x00000000 10780711   user   777        1
0x00000000 10813480   user   777        1
0x00000000 10846249   user   777        1
0x00000000 10879018   user   777        1
0x00000000 10911787   user   777        1
0x00000000 10944556   user   777        1
0x00000000 10977325   user   777        1
0x00000000 11010094   user   777        1
0x00000000 11042863   user   777        1
0x00000000 11075632   user   777        1
0x00000000 11108401   user   777        1
0x00000000 11141170   user   777        1
0x00000000 11173939   user   777        1
0x00000000 11206708   user   777        1
0x00000000 11239477   user   777        1
0x00000000 11272246   user   777        1
0x00000000 11305015   user   777        1
0x00000000 11337784   user   777        1

이는 header node에 남아 있는 semaphore array만 보여준다. 모든 node 에 남아 있는 semaphore array를 볼려면 cluster-fork 라는 명령어를 이용한다. 이 때, node의 숫자에 따라 출력문이 길 수도 있으므로 파일( semaphore-list.txt) 로 받는게 더 좋다.

[user@linuxcluster ~]$ cluster-fork ipcs -s > semaphore-list.txt 

확인된 semaphore array 의 소유자 (owner)가 자신이면 ipcrm -s <SEMID> 란 명령어로 지울 수 있다. 예를 들어, 이런 식이다. 

[user@linuxcluster ~]$ ipcrm -s 11337784

위 명령어는 오직 지정된 ID의 semaphore array만 삭제한다. 모든 sem array를 지우고 싶다면, cleanipcs란 명령어를 이용한다. cleanipcs는 보통 관리자 권한에서만 실행되므로 일반 사용자는 실행할 수 없다. 관리자에게 부탁해서 자신의 로컬 디렉토리에 복사해서 사용한다. (본인은 ~/bin 디렉토리에 저장해서 사용한다.) 이 경우, 타인에게 권한이 있는 sem array는 삭제할 수 없다. 타인의 sem array는 해당 사용자에게 지워줄 것을 부탁해야 한다. 모든 node에서 자신의 sem array를 지울려면 다음과 같이 cluster-fork를 이용하여 cleanipcs를 실행한다. 

[user@linuxcluster ~]$ cluster-fork ~/bin/cleanipcs

만약에 cleanipcs를 구할 수 없으면, 차선책으로 다음의 쉘 스크립트 (shell script) 파일을 만들어서 실행한다. 

[user@linuxcluster ~]$ cat > rmsem.i686.sh 
#!/bin/sh
ipcs | cut -f 2 -d ' ' | xargs ipcrm shm
ipcs | cut -f 2 -d ' ' | xargs ipcrm sem
ipcs
ctrl + D
[user@linuxcluster ~]$ chmod 744 rmsem.i686.sh
[user@linuxcluster ~]$ cluster-fork rmsem.i686.sh

이제 좀비(zombie) semaphore array를 깨끗하게 지웠으니, 프로그램이 문제없이 실행될 것이다. 
Posted by 참향그늘
,
일반적으로 리눅스 컴퓨터에서 새 프로그램을 설치할 경우, yum을 이용하는 것이 간단하고도 빠른 방법이 되겠다. 예를 들어, Octave를 설치한다면 다음과 같이 입력하면 된다.

[root@localhost ~]# yum install octave

그러나, 자신이 쓰고 있는 리눅스 배포판이 Centos (Community ENTerprise Operating System) 인 경우, 아래와 같은 메시지만 보게 되고, 설치가 되지 않는다. 

[root@localhost ~]# yum install octave
Loading "priorities" plugin
Loading "fastestmirror" plugin
Determining fastest mirrors
0 packages excluded due to repository priority protections

이러한 이유는 Octave 프로그램이 RHEL (Red Hat Enterprise Linux) 에 포함되지 않으면서, 자동적으로 Centos 에서도 배제되었기 때문이다. 하지만, 다행히도 EPEL (Extra Packages for Enterprise Linux) 로부터 Octave를 내려받을 수 있다. 이를 위해서, 우선 yum의 저장소 목록(repository list)에 EPEL을 추가하여야 한다.[각주:1] [각주:2]

현 저장소 목록에 등록되어 있는 저장소(repository)들을 확인해 보자.
[root@localhost ~]# yum repolist
Loading "priorities" plugin
Loading "fastestmirror" plugin
repo id                  repo name                                          status
addons                 CentOS-5 - Addons                             enabled
base                    CentOS-5 - Base                                 enabled
extras                   CentOS-5 - Extras                               enabled
updates                CentOS-5 - Updates                             enabled

그리고, 아래의 명령어로 yum 의 repo list 에 EPEL repository를 추가한다. 
[root@localhost ~]# rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
Retrieving http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
warning: /var/tmp/rpm-xfer.n5lIiD: Header V3 DSA signature: NOKEY, key ID 217521f6
Preparing...                ########################################### [100%]
   1:epel-release         ########################################### [100%]

이제 다시금 yum의 repo list 를 확인해 보면 epel 이란 ID로 EPEL repository가 추가되었음을 알 수 있다. 
[root@localhost ~]# yum repolist
Loading "priorities" plugin
Loading "fastestmirror" plugin
repo id                  repo name                                          status
addons                 CentOS-5 - Addons                             enabled
base                    CentOS-5 - Base                                 enabled
epel                     Extra Packages for Enterprise Linux 5 -   enabled
extras                   CentOS-5 - Extras                               enabled
updates                CentOS-5 - Updates                             enabled

실제로 하드 공간을 살펴보면, /etc/yum.repos.d 디렉토리 아래에 기존에 있던 CentOS-Base.repo 파일 외에 새로 epel.repo 생성되었음을 확인할 수 있다.
 
[root@localhost ~]# cat /etc/yum.repos.d/epel.repo

[epel]
name=Extra Packages for Enterprise Linux 5 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/5/$basearch
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
...

이제 yum을 이용해서 Octave를 설치하자. yum install octave라고 아래와 같이 명령어를 친 후, Is this ok [y/N]를 보면 y를 입력하여 설치를 진행한다.

[root@meso src]# yum install octave
Loading "priorities" plugin
Loading "fastestmirror" plugin
Loading mirror speeds from cached hostfile
0 packages excluded due to repository priority protections
Setting up Install Process
Parsing package install arguments
Resolving Dependencies
--> Running transaction check
---> Package octave.i386 6:3.0.5-1.el5 set to be updated
--> Processing Dependency: libglpk.so.0 for package: octave
--> Processing Dependency: libcolamd.so.2 for package: octave
--> Processing Dependency: libccolamd.so.2 for package: octave
--> Processing Dependency: libcholmod.so.1 for package: octave
--> Processing Dependency: libhdf5.so.0 for package: octave
--> Processing Dependency: libfftw3.so.3 for package: octave
--> Processing Dependency: libqhull.so.5 for package: octave
--> Processing Dependency: libcamd.so.2 for package: octave
--> Processing Dependency: libumfpack.so.5 for package: octave
--> Processing Dependency: libamd.so.2 for package: octave
--> Processing Dependency: libcxsparse.so.2 for package: octave
--> Running transaction check
---> Package fftw3.i386 0:3.2.2-3.el5 set to be updated
---> Package glpk.i386 0:4.20-2.el5 set to be updated
---> Package suitesparse.i386 0:3.1.0-1.el5 set to be updated
---> Package hdf5.i386 0:1.6.10-1.el5 set to be updated
---> Package qhull.i386 0:2003.1-8.el5 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

============================================================================
 Package              Arch       Version          Repository        Size 
=============================================================================
Installing:
 octave                  i386       6:3.0.5-1.el5    epel               12 M
Installing for dependencies:
 fftw3                     i386       3.2.2-3.el5       epel              1.3 M
 glpk                      i386       4.20-2.el5        epel              737 k
 hdf5                      i386       1.6.10-1.el5     epel              4.6 M
 qhull                     i386       2003.1-8.el5     epel              380 k
 suitesparse             i386       3.1.0-1.el5      epel             931 k

Transaction Summary
=============================================================================
Install      6 Package(s)         
Update       0 Package(s)         
Remove       0 Package(s)         

Total download size: 20 M
Is this ok [y/N]: 

옥타브 설치를 완료하였다.
  1. http://jamesreubenknowles.com/how-to-install-octave-on-centos-5-using-yum-757 [본문으로]
  2. http://fedoraproject.org/wiki/EPEL/FAQ#howtouse [본문으로]
Posted by 참향그늘
,