Xcrypt Tutorial

平石 拓，安部 達也，三宅洋平
岩下 武史，中島 浩
京都大学 学術情報メディアセンター

1

2010/2/18

背景• スパコンにおけるシミュレーション– 創薬，車体設計，天気予報• パラメータスイープ，最適パラメータ探索
 同一のプログラムを多数の入力に対し繰り返し
適用=PDCAサイクル– Plan: 入力を生成– Do: ジョブ投入（タスク並列）– Check: 結果を処理– Action: 次の計算を検討の繰り返し• 自動化すべき– ワークフロー，出力から次の入力を生成
2

2010/2/18

階層的大規模並列処理• Capability/Capacity の2階層化
1000並列 x 1000並列 ＝ 100万並列
多数の並列プログラムを並列実行するためのスクリプトプログラム

下位層＝ capability型＝ OpenMP, MPI, ...,or XscalableMP

上位層＝capacity型＝並列スクリプト言語（Xcrypt）

3

2010/2/18

現状と目標••手動（非自動化）
ジョブの実装言語（FortranやC）で自動化– 「計算科学者」に親しみのある言語– 生産性が低い（特に，複雑なフローへの対応）•汎用のスクリプト言語– シェルスクリプト，Perl，Ruby，．．．
– 汎用性高，生産性も悪くない– ジョブ並列の記述には意外と面倒•••

非同期に実行されるジョブの管理とか
特に「計算科学」研究者にとって専用スクリプト言語 (DSL)：Xcrypt– タスク並列処理の記述を楽にする
言語機能・ライブラリを提供– 手軽な記述と汎用性を両立•

ワークフローツール– 手軽な記述（GUI-based）– 複雑なフローの記述は困難

4

2010/2/18

What is Xcrypt?
• バッチスケジューラ（NQS，SGE，Torque，...）
上のジョブ並列処理を記述するためのスクリプト言語• （大量の）ジョブの投入，待ち合わせ，結果解析などが簡単に書ける• Perlベースの手続き型記述– たとえば
入力準備→ジョブの投入→結果解析の繰り返しがwhileループで書ける5

2010/2/18

設計思想• 簡便性– 想定ユーザ ＝ 計算科学研究者（≠計算機科学研究者）– 典型的な処理を手軽に書ける• 簡単なパラメータスイープを10行前後– 既存のプログラムに手を加えなくてもよい– スクリプトに手を加えなくても様々な環境で動作（多様なバッチスケジューラに対応）• 柔軟性，拡張性– 複雑なことも書こうと思えば書ける– Perl "wizards" can add various helpful spells as modules• 可搬性– 既存のプログラムが改変なしに動く– 様々な環境（バッチスケジューラ，ファイルシステム）で動く

6

2010/2/18

Xcryptの設計・実装• Perlのライブラリ群として実装– 既存言語ベース→開発・習得が用意– 柔軟性が高い• eval関数，オブジェクトへの動的なメンバ追加– Ruby, Pythonよりは馴染みやすい？

• Perlのオブジェクト指向機能を利用– ジョブ ＝ オブジェクト– 拡張モジュール ＝ クラス拡張• 多重継承により複数のモジュールを同時適用– エンドユーザは「オブジェクト指向」は気にしなくてよい7

2010/2/18

想定する用途• パラメータスイープ– 異なる多数の入力ファイルに対して同一のプログラムを適用する• 最適パラメータ探索（二分法 etc.）
1. 入力ファイルを生成
2. ジョブを投入
3. 出力ファイルを解析
4. 結果が収束していなければ 1. に戻るの繰り返し• 単に，システムごとにジョブスクリプトを用意するのが面倒なのをどうにかしたい
82010/2/18

例：アンサンブルシミュレーション
 異なる多数の初期パラメータに対して同一の予測計算（1アンサンブル=1ジョブ） 最後に結果をまとめる
予測計算
入力データ読込
＆前処理

予測計算
予測計算

後処理
＆結果出力

予測計算
繰り返し
92010/2/18

動作要件• Perl 5.8以上（5.10以上を推奨）• バッチスケジューラが導入されたシステム– qsub，qstat，qdel相当のコマンドが動作• ログインノードと計算ノードが次のいずれかの方法で通信可能– TCP/IP• ポート番号は任意，デフォルトは9999– NFSによるファイル経由• ログインノードと計算ノードが同一絶対パス指定できる，ユーザ権限で読み書きできるディレクトリが存在すること

10

2010/2/18

動作要件（補足）• スクリプトの動作を確認してみたいだけなら，バッチスジューラがない環境（手元のノートPCなど）でも，一応動かせる– OSスケジューラモード
バッチスケジューラ

OSスケジューラ

qsubshqstat

psqdelkill

request ID

process ID• 現状Cygwinでは動きません（利用しているCPANパッケージが原因）
11

2010/2/18

インストール（SCore環境）• RPMパッケージが用意されている– score7-src/eScience/xcrypt– bininstallコマンドでインストール• SCoreはデフォルトのバッチスケジューラが用意されていないので，OSスケジューラモードでインストールされる– 自分でバッチスケジューラをインストールして，それを使うようにすることは可能（後述）12

2010/2/18

インストール（SCore以外）
1. 以下から .tar.gz をダウンロード，解凍（SCore版より新しいです）
http://super.para.media.kyoto-u.ac.jp/~tasuku/xcrypt/

2. xcrypt-x.x/source-me.sh の環境変数を編集
環境変数

設定値

XCRYPT

xcrypt-x.x/ の絶対パス

XCRJOBSCHED

利用するバッチスケジューラ–

デフォルトでサポートするXCRJOBSCHEDの値
••
•

–
13

TSUKUBA（T2K筑波，SGE），TOKYO（T2K東大，NQS），KYOTO（T2K京大，NQS）
SGE（普通にインストールしたSGE）sh（OSスケジューラモード）：設定ファイルの編集が必要？

これ以外の環境で動かすためには自分で設定ファイルを追加する必要がある（後述）
2010/2/18

インストール（SCore以外・続き）
3. 環境変数の設定を適用% cd xcrypt-x.x% source source-me.sh–

今後のログイン用にこのファイルの内容を .bashrc などに追加しておくとよい

4. CPANパッケージのインストール（xcryptのディレクトリ以下にインストールされる）% cd CPAN% ./do-install.sh
14

2010/2/18

ドキュメント• xcrypt-x.x/doc/Xcrypt̲manual.pdf– インストール，起動方法– 言語の機能– 実装内部の一部– 拡張モジュールの書き方などが一通り書いてあります15

2010/2/18

起動方法% xcrypt myscript.xcr options• 主なコマンドラインオプション

16オプション

意味

デフォルト--port num

XcryptプロセスとジョブがTCP/IPで通信するポート番号（0：NFS経由）

9999--localhost nameport>0 のとき，計算ノードからログインノードにアクセスするホスト名

hostnameコマ
ンドの出力結果--inventory-path./inv̲watch

pathname

各ジョブの状態をファイルとして保存する場所--verbose nverbosity0

2010/2/18

How to write an Xcrypt script
1. Preamble––

利用したいモジュールの指定
必要であればグローバル変数の定義 など

2. ジョブテンプレートの定義––

ジョブに関する情報を宣言的に記述1つのテンプレートからジョブ「列」を生成可能

3. ジョブオブジェクトの生成・投入・終了待ち処
理を手続き的に書く–––

prepare()：ジョブオブジェクト（列）生成
submit()：ジョブ投入
sync()：ジョブ終了待ち例1：1つだけジョブを投入する
use base qw (core);%template = (id => example ,ジョブには任意のジョブIDをつける
実行ファイル'exe' => './a.out',
arg0 => input ,コマンドライン引数（ここでは入出力ファイル名）
arg1 => output ,'copiedfile0' => 'a.out',
実行に必要なファイル（copy対象）'copiedfile1' => 'input',queue => ghxxxxx ,ジョブを投入するキュー
group => ghxxxxx ,（T2K京大ではグループ名も必要）)@jobs = prepare (%template); 作業ディレクトリ作成
submit(@jobs);
ジョブ投入
sync(@jobs);
ジョブ終了待ち18

2010/2/18

実行% xcrypt single.xcr
example <= active
example <= preparedexample <= submitted
example id <= 8011
example <= queued
example <= running
example <= done
example <= finishedcheck̲and̲write̲aborted:%
19

ジョブオブジェクト生成作業ディレクトリ準備終了
ジョブ投入実行（成否はまだ不明）
ジョブのリクエストID
ジョブ投入成功
プログラム実行開始
プログラム実行完了
ジョブ実行完了

2010/2/18

実行結果
% ls
a.out* example/ input inv̲watch/ single.xcr% cd example 作業ディレクトリ
% lsKYOTO.sh* a.out* input invwrite-sock.log
output request̲id stderr stdout

20

2010/2/18

ワーキングディレクトリの中身• KYOTO.sh– Xcryptが生成したジョブスクリプト• invwrite-sock.log– ジョブプロセスとxcryptプロセスの通信ログ• request̲id– qsubしたときのリクエストIDの番号• stdout, stderr– バッチスケジューラが生成した標準出力，標準エラー出力ファイル

21

2010/2/18

キュー指定に関する注意
queue => ghxxxxx ,group => ghxxxxx ,は，T2K京大でのキューの指定方法• 京大は，キュー名とグループ名の両方必須（利用手続きの形態による）• 東大は，キュー名のみ必須• 筑波は，グループ名のみ必須（ただし，ノード数および制限時間も要指定）
222010/2/18

例2a：複数の独立なジョブを投入
use base qw (core);%template = (id => example ,パラメータの範囲
RANGE0 => [1..5],'exe' => './a.out',ジョブごとに異なる値
arg0@ => input$R0 ,→ メンバ名の末尾に@
arg1@ => output$R0 ,→ $R0 が 1〜5 に置き換わる'copiedfile0' => 'a.out','copiedfile1@' => input$R0 ,queue => ghxxxxx ,group => ghxxxxx ,)@jobs = prepare (%template); 作業ディレクトリ作成
submit(@jobs);
ジョブ投入
sync(@jobs);
ジョブ終了待ち23

2010/2/18

例2b：複数の独立なジョブを投入（関数版）
use base qw (core);%template = (id => example ,パラメータの範囲
RANGE0 => [1..5],'exe' => './a.out',
arg0@ => sub { input$̲[0] },ジョブごとに異なる値
arg1@ => sub { output$̲[0] }, → メンバ名の末尾に@→ $_[0] が 1〜5 に置き換わる'copiedfile0' => 'a.out','copiedfile1@' => sub { input$̲[0] },queue => ghxxxxx ,group => ghxxxxx ,)@jobs = prepare (%template); 作業ディレクトリ作成
submit(@jobs);
ジョブ投入
sync(@jobs);
ジョブ終了待ち24

2010/2/18

実行% ls
a.out* input1 input2 input3 input4 input5psweep.xcr% xcrypt psweep.xcr
example̲1 <= active
example̲2 <= active
example̲3 <= active
example̲4 <= activeexample̲5 <= active
example̲1 <= preparedexample̲2 <= prepared...
example̲5 <= finished%25

2010/2/18

実行結果
% ls
example̲1/ example̲2/ ... example̲5/ ...
% cd example̲2% ls
KYOTO.sh a.out input2 output2 ...
%26

2010/2/18

追加モジュールを使う
use base qw (limit core);limitモジュール使用
limit::initialize(1);同時ジョブ投入数を1に制限%template = ('id' => 'example','RANGE0' => [1..5],'exe' => './a.out','arg0@' => '"input$R0"','arg1@' => '"output$R0"','copiedfile0' => 'a.out','copiedfile1@' => '"input$R0"','queue' => 'ghxxxxx','group' => 'ghxxxxx',)@jobs = prepare (%template); 作業ディレクトリ作成
submit(@jobs);
ジョブ投入
sync(@jobs);
ジョブ終了待ち27

2010/2/18

実行% xcrypt psweep-limit.xcr
example̲1 <= active...
example̲5 <= active
example̲1 <= prepared...
example̲5 <= preparedexample̲1 <= submitted
example̲1 <= running
example̲1 <= done
example̲1 <= finishedexample̲2 <= submitted...
example̲5 <= finished28

2010/2/18

例3：二分法による最適パラメータ探索
目的：衛星電圧Vを0とする最適放出電子電流値Iを求める→二分法を利用した最適値探索

衛星電圧V

Vの計算1回 ＝ 1ジョブ実行→ 収束するまで繰り返し投入

I+0

I-

29

I-new

放出電子電流I

If ( V[(I++I-) / 2 > 0] ) thenI+new = (I++I-) / 2
else if ( V[(I++I-) / 2 < 0] ) thenI-new = (I++I-) / 2
end if2010/2/18

テンプレート定義「計算科学者」にマニュアルだけを与えて書いてもらったコード%template = ('id' => 'job00','exe' => 'mpiexec','cpu' => '1', 'proc' => '64','arg0' => '-n', 'arg1' => '${QSUB̲VNODES}','arg2' => './mpikempo3D','arg3' => '4';, 'arg4' => '4', 'arg5' => '4', 'arg6' => '< plasma.inp','linkedfile0' => 'mpikempo3D','stdofile' => 'stdout','stdefile' => 'stderr','queue' => 'ghxxxxx','group' => 'ghxxxxx');30

2010/2/18

ジョブ投入の反復実行
my $wpe1 = 1.0; my $wpe2 = 1.5; my $wpem = 1.0; my $phi = 1;
until (abs($phi) < 0.1) { # 結果が誤差範囲内になるまで反復$wpem = ($wpe1+$wpe2)/2;$template{ id } = $template{ id } . + ; # ジョブ名が重複しないようにIDを変更
my @job = prepare(%template);
foreach (@job) { # 入力ファイルの作成（ネームリストplasma.inpのwp(3)の値のみ$wpemに変更）
my $generate = CF("$ENV{'PWD'}/plasma.inp","$ENV{'PWD'}/"."$̲->{id}");$generate -> KR("wp(3)", "$wpem");$generate -> do(); }@results = submit̲sync(@job), "¥n";foreach (@results) { # 出力ファイルの抽出（最終行3列目の値を$phiに代入）
my $phiext = EF("file:$ENV{PWD}/$̲->{id}/pbody");$phiext->ED('L/E'); $phiext->ED('C/3');
my @phis = $phiext->ER();$phi = $phis[0]; }print "Potential: ", $phi, "¥n";# $phiの正負に応じて左右どちらかから範囲を狭める
if ($phi < 0) { $wpe1 = $wpem; } else{ $wpe2 = $wpem; }}31

2010/2/18

T2K以外の環境で動かすには• xcrypt-x.x/lib/config/mysched.pm
を自分で定義して，環境変数
XCRJOBSCHED を mysched に設定する• 厳密な仕様は近日中に決定・公開予定• Perlに少し慣れている必要– システム管理者が書くことを想定• 既存の設定ファイルをベースにすればそれほど難しくはない？
• 「動くレベル」でよいなら世の中の多くのスケジューラに対応できると思われる
32

2010/2/18

例：T2K京大用の設定ファイル• xcrypt-x.x/lib/config/KYOTO.pm$jobsched::jobsched̲config{ KYOTO"} = {qsub̲command => "/thin/local/bin/qsub",qdel̲command => "/usr/bin/qdel -K",
qstat̲command => "/thin/local/bin/qstat",jobscript̲queue => '# @$-q ',jobscript̲stdout => '# @$-o ',jobscript̲stderr => '# @$-e ',jobscript̲proc => '# @$-lP ',jobscript̲cpu => '# @$-lp ',jobscript̲memory => '# @$-lm ',jobscript̲verbose => '# @$-oi',jobscript̲verbose̲node => '# @$-OI',
jobscript̲workdir => '$QSUB̲WORKDIR ,33

extract̲req̲id̲from̲qsub̲output => sub {my (@lines) = @̲;
if ($lines[0] =˜ /([0-9]*)¥.nqs/) {return $1;} else {return -1;}},extract̲req̲ids̲from̲qstat̲output => sub {my (@lines) = @̲;
my @ids = ();foreach (@lines) {if ($̲ =˜ /([0-9]+)¥.nqs/) {push (@ids, $1);}}
return @ids;},};

2010/2/18

最低限必要な設定• qsub/qdel/qstat-command– qsub，qstat，qdelコマンドへのパス• extract̲req̲id̲from̲qsub̲output– qsubの出力を受け取り，投入したジョブのrequest IDを返すPerl関数• extract̲req̲ids̲from̲qstat̲output– qstatの出力を受け取り，キューに存在するrequest IDのリストを返すPerl関数• jobscript̲workdir– ジョブスクリプトにおいて，作業ディレクトリのパスを獲得する手段– 計算ノードとログインノードで，作業ディレクトリを同一の絶対パスで指せない環境では必須

34

2010/2/18

自分で追加モジュールを作成する• 追加モジュール定義でできること– 独自のジョブのパラメータ（属性）を追加できる– prepare関数で作業ディレクトリを作るときの挙動を拡張，変更できる ← newメソッド– ジョブ投入直前の「フック」を追加できる ← beforeメソッド• 依存するジョブの完了を待ち合わせるなど– ジョブ投入処理の挙動を拡張，変更できる ← startメソッド• ある条件を満たすジョブはqsubをスキップするなど– ジョブ完了直後の「フック」を追加できる ← afterメソッド• 次のジョブを生成，投入する• 所望の結果が得られたら残りのジョブを殺す など– （予定）ジョブスクリプトの生成方法に手を加えられる• Perlのオブジェクト指向プログラミングにある程度慣れている人向け
35

2010/2/18

例：limitモジュールの定義
package limit;
use strict;use NEXT;
use Coro::Semaphore;
my $smph;# モジュールの利用者が最初に呼び出す関数（同時ジョブ投入数の上限設定）
sub initialize { $smph = Coro::Semaphore->new($̲); }sub new {my $class = shift;
my $self = $class->NEXT::new(@̲);
return bless $self, $class;}# ジョブ投入前のフック：セマフォ獲得
sub before {$smph->down;}# ジョブ完了後のフック：セマフォ解放
sub after {$smph->up;}36

2010/2/18

Xcryptの拡張モジュールの提供機構• ジョブオブジェクトはcoreクラスのインスタンス• 拡張モジュールの開発者は，– メンバ（⊃エンドユーザに提供するパラメータ）の追加– メソッドの拡張・追加
によりcoreクラスを拡張できる• 基本的にはオブジェクト指向Perlのクラス拡張のスタイル• 以下の名前のメソッドは特別な意味を持つ

37– new：コンストラクタ（prepare()時に実行される）– before：ジョブ投入直前の処理– start：ジョブ投入処理– after：ジョブ投入後の処理

2010/2/18

limit以外の拡張モジュール
xcrypt-x.x/lib/
以下のディレクトリにいくつか• dry.pm– 全てのジョブの実行を飛ばす（ドライ実行）• convergence.pm– 今回と前回とのジョブの結果の差が設定値以下に収束するまで実行を繰り返す• n̲section̲method.pm：n分法– successor.pm: ジョブの依存関係を宣言的に書けるようにする
38

2010/2/18

最後に• Xcryptで，通常のマルチスレッドプログラミングに近い感覚でジョブ並列処理が書ける• 基本的な機能は実装済み• 今後の機能追加予定– チェックポインティング– 手元のPCからのリモートジョブ投入• スパコン「利用者」側の視点でコメントをいただければ幸いです– 書き易さ，使い勝手– 機能追加要望– バグ報告39

2010/2/18