HPCメモ

HPC(High Performance Computing)に関連したりしなかったりすることのメモ書き

Macの初期設定&備忘録

私事ながら、昨年末で5年ちょっと勤めた某社を退職し、自分で会社を立ち上げました。
というわけで、「あーこのネタをブログに書きたいけど会社の人にバレたら困るなー」みたいな制約が無くなりましたんで、今年からはもっと記事を書く頻度を上げていきたいと思います。*1

最初の記事ですが、この機に長年使い慣れたWindowsを捨ててマカーになったので自分用の備忘録として、初期設定などでやったことをまとめておきます。

HHKの設定変更

dipスイッチの1,2をonにしないとコマンドキーが送出されないので、これを変更しておく。
この変更を有効にするとFn+Tabがcaps lockとして機能するようになるので注意!

キーボードの設定変更

[システム環境設定] -> [キーボード] -> [キーボード] と進んで"キーのリピート"と"リピート入力認識までの時間"のスライダーを一番右へ設定する。
f:id:n_so5:20170111105532p:plain

マウスの設定変更

[システム環境設定] -> [マウス] と進んで"スクロールの方向: ナチュラル"のチェックボックスを外し"軌跡の速さ"と"スクロールの速さ"を調整
f:id:n_so5:20170111105548p:plain

dockの設定

ドックにもともと登録されているアプリはごみ箱へdrag&dropすれば削除できる。
逆に新規にアプリを登録する時は[Finder] -> [アプリケーション]と進むと一覧が表示されるので、そこからdrag&drop

コピペ

copy/cut/pasteはWindowsだとControl+C/X/Vだけど、macではCommand+C/X/Vが割り当てられている。
修飾キーが違うだけなんで、システム環境設定のキーボードのところでControlとCommandを入れ替えるというのがメジャーな方法らしいですが、これをやると全てのショートカットキーに影響が出るので、始めて使う機能(最初に書いたスクリーンショットとか)をググって調べながら使う時に支障がでそうです。
でも、Control+C/X/Vを有効にするだけだったら、こちらの方法でOK
d.hatena.ne.jp


うちの場合シンプルにこの3項目だけを書いています。

$ cat ~/Library/KeyBindings/DefaultKeyBinding.dict 
{
  "^c" = "copy:";
  "^v" = "paste:";
  "^x" = "cut:";
}

ディレクトリ名はKeyBinding**s**なのにファイル名はKeyBinding.dictなのに気付かずに1時間くらいはまってたので、ご注意を・・・orz

あと、この方法だとfirefox上では表示されているHTMLに対しては無効だけど、アドレスバーやtext area内のドキュメントに対しては有効という謎の状態になるようです。
ま、command+C/X/Vも有効なままなのでControlで反応すればCommandを使えば良いだけの話ですが。

==== 追記 ====

skkのインストール&設定

skkAquaSKKをこちらからダウンロードしてインストールします。
github.com
このままだと、ターミナル上でC-jを入力してもかなモードに切り替わらないので、こちらのコメントにあるようにkeymapにC-7/C-8/C-9あたりを追加しておきます。*2
github.com

あとhome brew, macvim, vagrant, virtualboxあたりもインストールしてますが単純に入れただけなので省いてます。

*1:年明けにこういうことを書くblogってのは大抵更新されないもんだけど・・・

*2:C-jを入力して効かなかった時に、右手の人差し指を適当に上の方に動かせばOKというキーアサインです

python3でtrelloに登録したカードを読み出す(その2)

前回作ったプログラムですが、実行に10秒ほどかかっていて、これならブラウザで複数プロジェクトのボードを全部開いてまわってもたいして効率が変わらない感じです。
おそらく遅い原因はボード一覧の取得->ボード毎にリスト一覧の取得->リスト毎にカード一覧の取得という一連の流れの中で、毎回O(N)相当のhttpリクエストを投げてるところだろうと思います。なんとか早くする方法が無いかと思って調べてたんですが、trelloのAPIリファレンスのページを見てると、こういう複数リクエストをまとめて投げるAPIがありました。
https://developers.trello.com/advanced-reference/batch
これを使えばこのプログラムのhttpリクエストは次の3回までに減らすことができます。

  1. ボード一覧の取得
  2. ボード内のリスト一覧の取得
  3. 所定のリスト(WIPとかToDoとか)内のカード一覧の取得

さっそく、前回てきとーに作ったTrelloClientクラスにbatch_fetch関数を追加してみます。

class TrelloClient:
    def __init__(self, api_key, token):
        self.api_key=api_key
        self.token=token
        self.base_url="https://api.trello.com/1"
    def fetch(self, category, api, target_id, option=""):
        url='{}/{}/{}/{}?key={}&token={}{}'.format(self.base_url,category,target_id,api,self.api_key,self.token,option)
        with  urllib.request.urlopen(url) as r:
            return json.loads(r.read().decode('utf-8'))
    def batch_fetch(self, category, api, target_ids, option=""):
        batch_url=""
        for target_id in target_ids:
            batch_url += "/{}/{}/{}/{},".format(category, id, api,option)
        batch_url=urllib.parse.quote(batch_url.rstrip(','))
        url="{}/batch/?urls={}&key={}&token={}".format(self.base_url, batch_url, self.api_key, self.token)
        with  urllib.request.urlopen(url) as r:
            return json.loads(r.read().decode('utf-8'))

これを使って全ボード内のリストの一覧を取得するとこんな感じのコードになります。

tc=TrelloClient(trello_api_key, trello_token)
boards=tc.fetch(category="member", api="boards", target_id="me", option="&filter=open&fields=name")
board_ids=[board['id'] for board in boards]
lists=tc.batch_fetch(category="boards", api="lists", target_ids=board_ids, option="?filter=open&fields=name&fields=idBoard")

今の時点のコードはこんな感じになってます。
n_so5 / TaskReporter / commit / 7197ec9bb6da — Bitbucket


新旧バージョンで実行時間を比較してみると

elapsed time for first version = 1.22e+01 sec
elapsed time for second version = 1.32e+00 sec

10倍早くなってますね。

python3でtrelloに登録したtask(=カード)を読み出す

googleカレンダーのお気に入りの機能のひとつに、「毎日指定した時間にその日の予定をメールで送ってくる」というのがあります。
気分的には、オフィスのエレベーターを降りて自席まで歩いている間に、クリップボードを持った秘書さんが付いてきて今日の予定を読み上げてくって感じ*1なんですが、
残念ながら我々エンジニアはカレンダーに入っているスケジュール済タスクだけをチェックしていると、色々と破綻します。

私の場合は、カレンダーの他にプロジェクト毎の課題管理のためにtrelloを使っていて案件毎に個別のボードにカンバン方式でタスクを登録しています。
ところが、trelloでボードをまたいでカードを見ようとすると自分にアサイン済のカード一覧を見るしかないので、BacklogからTodoへ(もしくはWIPへ)カードを移動させては自分へアサインし、Doneリストへ移動させてはアサインを外すという面倒なことをやっていました。
しばらくはこの方式で頑張ってたんですが、割り込みタスクのカードを作ったりすると徐々に破綻していって、今となっては自分にアサインされたカードの一覧を見ても入っていないタスクの方が多い有様です。

というわけで、一念発起して自分の担当案件のうち、作業中のタスクとToDo項目をtrelloから取得して表示するプログラムを作ってみました。

基本方針

  • python3で作成
  • urllibで頑張る(requestは使わない)
  • 出力先はとりあえずコンソール

trelloのカードを取得する準備

trelloのカードを取得するためには、APIキーとTokenを用意する必要があります。
まずは、次のURLへアクセスします。
https://trello.com/app-key
一番上に「キー:」と書かれた下に文字列があるので、これをメモっておきます。
続いて、「Token:」と書かれたセクションに"Token"というリンクがあるので、ここをクリックするといつもの認証画面に遷移します。
f:id:n_so5:20160906212740p:plain
ここで許可とすると

You have granted access to your Trello information.

To complete the process, please give this token:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

という形でトークンの文字列が表示されるので、最後の行の文字列をメモっておきます。
以降のスクリプトでは、鍵をtrello_api_keyという変数に、トークンをtrello_tokenという変数に保存している前提で書きます。

ボードの一覧を取得

ボードの一覧を取得するには、次のAPIを呼びます。
https://developers.trello.com/advanced-reference/member#get-1-members-idmember-or-username-boards

コードで書くとこんな感じになります。

import urllib.request
import json

boards=[]
with  urllib.request.urlopen("https://api.trello.com/1/members/me/boards?key={}&token={}&filter=open&fields=name".format(trello_api_key, trello_token)) as r:
    tmp=r.read().decode('utf-8')
    boards=json.loads(tmp)

optionとして渡している文字列のうち、filter=openはOpenなボードのみ取得することを、fields=nameはボードの名前とidのみを取得することを意味しています。
これで、boardsには各ボードのidと名前を格納した辞書のリストが入ります。

次に進む前に、trelloのAPIを叩いて返ってきたjsonpythonのオブジェクトに変換して返すところまでをクラスにしておきましょう。

class TrelloClient:
    def __init__(self, api_key, token):
        self.api_key=api_key
        self.token=token
        self.base_url="https://api.trello.com/1"
    def fetch(self, category, api, target_id, option=""):
        url='{}/{}/{}/{}?key={}&token={}{}'.format(self.base_url,category,target_id,api,self.api_key,self.token,option)
        with  urllib.request.urlopen(url) as r:
            return json.loads(r.read().decode('utf-8'))

tc=TrelloClient(trello_api_key, trello_token)
boards=tc.fetch(category="member", api="boards", target_id="me", option="&filter=open&fields=name")

Taskの取得

ここまででボードのID(と名前)の一覧が取得できたので、次は各ボードに対してこちらのAPIを使ってリストの一覧を取得します。
https://developers.trello.com/advanced-reference/board#get-1-boards-board-id-lists
この時オプション引数のcardsとcard_fieldsを使うと、各リストに含まれるカードの一覧も取得できるので、これを使ってまとめてボード内のカードを取得します。ただし、この方法で取得すると全てのリストに入っているカードが返ってきてるので、TodoかWIPのリストに入っているカードだけを後から抽出する必要があります。
コードはこんな感じになります。(前のコードの続きです。)

todo={}
wip={}
for board in boards:
    lists=tc.fetch(category="boards", target_id=board["id"], api="lists", option="&filter=open&fields=name&cards=open&card_fields=name")
    for list in lists:
        if len(list['cards']) > 0:
            if list["name"] in ("ToDo", "todo", "Todo", "To do", "to do"):
                    todo[board["name"]]=list['cards']
            if list["name"] in ("WIP", "W.I.P.", "W.I.P", "Doing", "doing"):
                    wip[board["name"]]=list['cards']

リスト名の表記ゆれを考慮して一応それっぽい名前のものは全部対象のリストとみなすようにしてあります。

出力

こんな感じで取得したTodoとWIPのカード名を順にprintしていきます。

print("現在作業中のタスク")
for project, tasks in wip.items():
    print(project,":")
    for task in tasks:
        print("  -",task['name'])
    print("")

print("Todo項目")
for project, tasks in todo.items():
    print(project,":")
    for task in tasks:
        print("  -",task['name'])
    print("")

おまけ

このコードでは、ボード内の全カードを取得してから、不要な(対象外のリストに入っている)カードの除いていますが、trello APIで同時に取得できるアイテムの上限は1000なので1000以上のカードが入っているボードがあると全部のtaskを拾うことができません。こういう状況が起き得る場合は、ボード内のリストを取得する時に以下のように一旦リスト名の一覧を取得してから、必要なリストのカードを改めて取得する必要があります。

for board in boards:
    lists=tc.fetch(category="boards", target_id=board["id"], api="lists", option="&filter=open&fields=name)
    for list in lists:
        cards=tc.fetch(category="lists", target_id=list["id"], api="cards", option="&filter=open&fields=name")

私の環境だと、こっちの方がだいたい倍くらい遅かったんですが、もともと6~7秒で終わっていたのが10秒程度に伸びるくらいの感覚なので今のところこっちを使っています。

*1:洋画とかでよくやってるイメージ

pythonのwebbrowserモジュール

2年ほど前に、「へび年だからpythonの勉強でもするか」とかいう冗談みたいな理由でpythonを使い始めたんですが、今日初めてこんな素敵なモジュールがあることを知りました。

21.1. webbrowser — 便利なウェブブラウザコントローラー — Python 3.5.2 ドキュメント

このモジュール、名前が示すとおりの挙動で、URLを受け取ると標準のブラウザで開くというものです。

うちの環境だと、コマンドプロンプトから

> python -m webbrowser -t "http://www.python.org"

とやると、firefoxが立ち上がって(あるいは、新しいタブを開いて)python.orgのトップページを表示してくれます。







じゃ、cygwinでやるとどうなるかというと
f:id:n_so5:20160711163329p:plain
とりあえず、テキストブラウザが立ち上がりました。Bとか反応しないのでw3mじゃないのは確かだけど、このソフト何かなーと思いながら、qを押すと
f:id:n_so5:20160711164003p:plain
linksだったようです。
Links - Wikipedia


これは、cygwinのデフォルトブラウザがlinksになっているというわけじゃなくて、単にwebbrowserモジュールが持っているブラウザリストの中から、探していって見つかったものを呼んでるだけでしょうかね?


しかし、これでスクリプトからブラウザを開かせたりできるので大変便利そうです。
#アプリ連携の認証とか使える・・・?

MPIライブラリ毎のプロセスマッピング指定方法

さっき、ひさびさにIntelMPIを使ってて、プロセスマッピングの指定ってどうやるんだっけと小一時間悩んでしまったので、自分用メモとして残しときます。

IntelMPIの場合、プロセスマッピングを指定するには以下の環境変数を使います。

  • I_MPI_PIN
  • I_MPI_PIN_MODE
  • I_MPI_PIN_RESPECT_CPUSET
  • I_MPI_PIN_RESPECT_HCA
  • I_MPI_PIN_CELL
  • I_MPI_PIN_DOMAIN
  • I_MPI_PIN_ORDER
  • I_MPI_PIN_PROCESSOR_LIST

といってもI_MPI_PINからI_MPI_PIN_RESPECT_HCAまでは通常はデフォルト値のままで良いので、指定するのは後半の4つのみです。

I_MPI_PIN_CELLに指定可能な値は"unit"か"core"のどちらかで、前者は論理コア後者は物理コア単位での割り当てを行うことを指定します。
HyperThreadingが有効な時に、なるべく1rankが使うコアを狭めたいけど同じ物理コアで2rank動かれるのは困る、なんて時にはcoreを指定すれば良さそうです。*1


I_MPI_PIN_DOMAINは1rankが使うコア数を指定するものです。
1ノード16コアの環境で、ノードあたり8プロセス実行とかだったら16/8で2と指定すれば良いのですが、autoに指定しておくとこれと同様な計算を自動的にやってくれます。また、OMP_NUM_THREADSの値と合わせるompというキーワードも使えます。
他にもsocket/core/nodeといった指定もできますし(それぞれ1ソケット/1コア/1ノードあたり1rankを割り当てる)cacheという値を指定すれば、cacheを共有している範囲をdomainとしてその範囲内には1プロセスしか割り当てません。
ただし -n オプションで指定されたプロセス数が、使うノードの範囲内に納まらなかった場合は1domain内に複数のrankが割り当てられることもあります。(その場合はrank0から順に各domainに1rankづつ割り当てて、余ったらまたdomain0から順に割り当ててといった感じになるはず)
それから、auto/ompもしくは明示的なdomainのサイズを指定した場合は続けて :layout という形でdomainのレイアウト方法を指定できます。
これは、compact/scatter/platformの3つの値が指定できて、compactだと同一domainがなるべく近いコアに、scatterだとなるべく遠いコアに割り当てられます。platformにすると単純にBIOSレベルでのcore id順(たぶん/proc/cpuinfoで見える順番)で割り当てられます。

まぁ、色々書いたけど ハイブリッドプログラムなら omp:compactでflat MPIのプログラムなら core にしておけばたいてい大丈夫でしょう。
ハイブリッドプログラムで非privateな領域にやたらとアクセスしてスラッシングが酷いとかなら、omp:scatterも有効かもしれませんが、そもそもそんなプログラムは書き換えるべk


I_MPI_PIN_ORDERはI_MPI_PIN_DOMAINで指定した各ドメインを実際に割り当てる時の順番を指定します。
指定できる値は、compact/scatter/spread/bunchの4つです。
reference manualに非常に分かりやすい解説があったので、詳細は省きますが、たぶんcompactしか使わない。


I_MPI_PIN_PROCESSOR_LISTは、DomainとOrderの組み合わせでは指定できないような面倒なパターンを指定する時に使えます。
例えばrank0から3は同一ソケット上の連続した3つの物理コアを使ってrank4は同じノードの別ソケットを使うとか。
これで細かく指定するのは、コアを余らせて実行するような時なので、普段はあんあり出番は無いです。(ベンチマークとる時はそこそこ使う)

最後に、この辺のプロセスマッピングの状況を出力させるには

export I_MPI_DEBUG=4

を指定しておけばOKです。(正確に4じゃなくても4以上の値ならOK)

*1:でも、そもそもHPC用途だと大抵HT切ってるから使ったこと無いw

Alces Flight

starclusterだのcfnclusterだのをいじっていたら、なんかまた新しいサービスが始まってたようです。

Alces Flight: Effortless HPC is Born (Finally)

AWS marketplaceから起動できるので、これはこれで便利そうですね。


こちらは、starclusterやcfnclusterと違ってアプリのインストール手段を提供しているというのが特長らしくこんな感じの長いソフトの一覧が用意されています。*1

Alces Gridware Software Applications — flight-appliance-docs 1.0 documentation


個人的には興味無しだけど、プログラムをいじらずにひたすら計算する人*2には良いサービスかもしれませんね。


しかし、なぜかスケジューラはOpen grid schedulerが入っているそうで・・・なんでみんなそんなにSGE系のスケジューラが好きなんだろうか。

*1:なんかカテゴリに偏りがある気が・・・

*2:まるで学生時代の私だ:p

starcluster と cfncluster その2

続いてcfnclusterを使ってPCクラスタを作ってみます。starclusterと条件を合わせるために、c3.largeの4ノード構成でやってみます。

インストール(windows native版)

記事を分けたついでに、windows nativeのpythonでもインストールしてみます。

>python -m virtualenv --python=C:\Python27\python.exe cfncluster
>cd cfncluster
>Scripts\activate
>pip install cfncluster
Collecting cfncluster
  Downloading cfncluster-1.2.1.tar.gz
Collecting boto>=2.39 (from cfncluster)
  Using cached boto-2.40.0-py2.py3-none-any.whl
Collecting awscli>=1.10.13 (from cfncluster)
  Downloading awscli-1.10.34-py2.py3-none-any.whl (938kB)
    100% |################################| 942kB 450kB/s
Collecting s3transfer==0.0.1 (from awscli>=1.10.13->cfncluster)
  Downloading s3transfer-0.0.1-py2.py3-none-any.whl
Collecting colorama<=0.3.3,>=0.2.5 (from awscli>=1.10.13->cfncluster)
  Downloading colorama-0.3.3.tar.gz
Collecting rsa<=3.5.0,>=3.1.2 (from awscli>=1.10.13->cfncluster)
  Downloading rsa-3.4.2-py2.py3-none-any.whl (46kB)
    100% |################################| 49kB 1.5MB/s
Collecting botocore==1.4.24 (from awscli>=1.10.13->cfncluster)
  Downloading botocore-1.4.24-py2.py3-none-any.whl (2.3MB)
    100% |################################| 2.3MB 185kB/s
Collecting docutils>=0.10 (from awscli>=1.10.13->cfncluster)
  Downloading docutils-0.12.tar.gz (1.6MB)
    100% |################################| 1.6MB 269kB/s
Collecting futures<4.0.0,>=2.2.0 (from s3transfer==0.0.1->awscli>=1.10.13->cfncluster)
  Downloading futures-3.0.5-py2-none-any.whl
Collecting pyasn1>=0.1.3 (from rsa<=3.5.0,>=3.1.2->awscli>=1.10.13->cfncluster)
  Using cached pyasn1-0.1.9-py2.py3-none-any.whl
Collecting jmespath<1.0.0,>=0.7.1 (from botocore==1.4.24->awscli>=1.10.13->cfncluster)
  Downloading jmespath-0.9.0-py2.py3-none-any.whl
Collecting python-dateutil<3.0.0,>=2.1 (from botocore==1.4.24->awscli>=1.10.13->cfncluster)
  Downloading python_dateutil-2.5.3-py2.py3-none-any.whl (201kB)
    100% |################################| 204kB 1.6MB/s
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore==1.4.24->awscli>=1.10.13->cfncluster)
  Using cached six-1.10.0-py2.py3-none-any.whl
Building wheels for collected packages: cfncluster, colorama, docutils
  Running setup.py bdist_wheel for cfncluster ... done
  Stored in directory: C:\Users\n_so5\AppData\Local\pip\Cache\wheels\26\c8\b0\3cf98bf7d72a9a63a358cbf094a50092641a70843de01ca155
  Running setup.py bdist_wheel for colorama ... done
  Stored in directory: C:\Users\n_so5\AppData\Local\pip\Cache\wheels\21\c5\cf\63fb92293f3ad402644ccaf882903cacdb8fe87c80b62c84df
  Running setup.py bdist_wheel for docutils ... done
  Stored in directory: C:\Users\n_so5\AppData\Local\pip\Cache\wheels\db\de\bd\b99b1e12d321fbc950766c58894c6576b1a73ae3131b29a151
Successfully built cfncluster colorama docutils
Installing collected packages: boto, futures, jmespath, six, python-dateutil, docutils, botocore, s3transfer, colorama, pyasn1, rsa, awscli, cfncluster
Successfully installed awscli-1.10.34 boto-2.40.0 botocore-1.4.24 cfncluster-1.2.1 colorama-0.3.3 docutils-0.12 futures-3.0.5 jmespath-0.9.0 pyasn1-0.1.9 python-dateutil-2.5.3 rsa-3.4.2 s3transfer-0.0.1 six-1.10.0
You are using pip version 8.0.2, however version 8.1.2 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

あっさりインストールできました。

クラスタの起動

こちらは、cfnclusterを使う前に鍵を作っておく必要があります。
以下のURLへアクセスして「キーペアを作成」というボタンを押します。
https://ap-northeast-1.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#KeyPairs:sort=keyFingerprint
名前を付けると、あとは自動的にpemファイルのダウンロードが始まるので、保存しておきます。

続いて、cfnclusterから設定を作成します。cfncluster configureと入力すると、CLI上でウィザードが始まるので、質問に答えていきます。

>cfncluster configure
Cluster Template [default]:
AWS Access Key ID []: QWERTYUIOP{}
AWS Secret Access Key ID []: ASDFGHJKL:"
Acceptable Values for AWS Region ID:
    us-east-1
    cn-north-1
    ap-northeast-1
    ap-southeast-2
    sa-east-1
    ap-southeast-1
    ap-northeast-2
    us-west-2
    us-gov-west-1
    us-west-1
    eu-central-1
    eu-west-1
AWS Region ID []:ap-northeast-1
VPC Name [public]:
Acceptable Values for Key Name:
    CfnClusterTest
Key Name []: CfnClusterTest
Acceptable Values for VPC ID:
    vpc-123n456
VPC ID []: vpc-123n456
Acceptable Values for Master Subnet ID:
    subnet-987f6543
    subnet-12345678
Master Subnet ID []:subnet-987f654

リージョン、鍵ペア、VPC、サブネットIDなどを指定するんですが、それぞれ設定可能な値が選択肢として表示されるので、ここからコピペすればOKです。また、1回選択した内容は保存されているようなので、再度cfncluster configureを実行すると、デフォルトの値として前回使った値が表示されます。

これで、$HOME/.cfncluster/config以下に設定ファイルが作成されるんですが、starclusterと違って上記で入力した値しか書かれていません。
後は、ここのドキュメントを見ながら必要な設定を追記していきます。
Configuration — CfnCluster 1.2.1

今回追記したのは全て[cluster default]セクションの中で、以下の5項目です。
この設定で、4ノード構成のクラスタが立ち上がり、用が無くなったら勝手に落としてくれるはず。
schedulerはデフォルトでは、starclusterと同じくSGEですが、openlava, torque, slurmも使えるとのことなので、慣れてるslurmで試してみることにします。

 compute_instance_type = c3.large
 master_instance_type = c3.large
 initial_queue_size = 4
 max_queue_size = 4
 scheduler = slurm

もし、まったくジョブが流れてなくても何ノードかは常に立ち上げておきたいという時は、initial_queue_sizeに必要なノード数を設定し、

maintain_initial_size = true

という設定を追加します。これで、Autoscalingの設定が変わって、最小ノード数以下まで下げることは無くなるとのこと。



続けてクラスタを起動します。

> cfncluster create mycluster

驚くほど遅いので、一服しながら待ちましょう。今回の構成だと、だいたい15分くらいかかりました。
$HOME/.cfncluster/cfncluster-cli.logにログが吐かれてますが、何か特別時間がかかる処理があるわけではなく、満遍無く遅いようです・・・。
起動が完了したら、次のようにMasterノードのIPアドレスとGangliaのURLが表示されます。

Output:"MasterPrivateIP"="172.31.13.62"
Output:"MasterPublicIP"="52.196.251.236"
Output:"GangliaPrivateURL"="http://172.31.13.62/ganglia/"
Output:"GangliaPublicURL"="http://52.196.251.236/ganglia/"

最初に作ったkeypairを使ってログインしてみましょう。

> ssh ec2-user@52.196.251.236 -i CfnClusterTest.pem

とりあえず、何が入っているのか分からんので適当に試してみたところ、こんな感じでした。

>$ gcc --version
gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ mpirun --version
-bash: mpirun: command not found
$ sbatch --version
-bash: sbatch: command not found
$ which qsub
/opt/sge/bin/lx-amd64/qsub

わざわざスケジューラにslurmを指定したのに、そもそも全部入ってたようです・・・

$ /opt/slurm/bin/sinfo
sinfo: error: s_p_parse_file: unable to status file /opt/slurm/etc/slurm.conf: No such file or directory, retrying in 1sec up to 60sec
$ qconf -sel
ip-172-31-15-101.ap-northeast-1.compute.internal
ip-172-31-15-102.ap-northeast-1.compute.internal
ip-172-31-15-103.ap-northeast-1.compute.internal
ip-172-31-15-104.ap-northeast-1.compute.internal

そして、sinfo(slurmの情報表示コマンド)は使えないのに、qconf(SGEの設定コマンド)は正常に動作するという・・・

MPIの方はどうかというと

$ yum list installed |grep -i mpi
mpich.x86_64                   3.0.4-4.5.amzn1                 @amzn-main
mpich-devel.x86_64             3.0.4-4.5.amzn1                 @amzn-main
openmpi.x86_64                 1.6.4-5.29.amzn1                @amzn-main
openmpi-devel.x86_64           1.6.4-5.29.amzn1                @amzn-main

インストール済なんだけどPATHは通ってないようです。

$ rpm -ql openmpi.x86_64
/etc/openmpi-x86_64
/etc/openmpi-x86_64/openmpi-default-hostfile
/etc/openmpi-x86_64/openmpi-mca-params.conf
/etc/openmpi-x86_64/openmpi-totalview.tcl
/etc/profile.d/openmpi.sh
/usr/lib64/gfortran/modules/openmpi-x86_64
/usr/lib64/openmpi
/usr/lib64/openmpi/bin
/usr/lib64/openmpi/bin/mpiexec
/usr/lib64/openmpi/bin/mpirun
/usr/lib64/openmpi/bin/ompi-clean
・
・
・
$ cat /etc/profile.d/openmpi.sh
function set_openmpi {
    MPI_HOME=/usr/lib64/openmpi
    MPI_BIN=$MPI_HOME/bin
    MPI_LIB=$MPI_HOME/lib
    MPI_MAN=/usr/share/man/openmpi-x86_64
    MPI_INCLUDE=/usr/include/openmpi-x86_64
    MPI_SYSCONFIG=/etc/openmpi-x86_64
    MPI_COMPILER=openmpi-x86_64
    MPI_SUFFIX=_openmpi
    MPI_PYTHON_SITEARCH=/usr/lib64/python2.6/dist-packages/openmpi
    MPI_FORTRAN_MOD_DIR=/usr/lib64/gfortran/modules/openmpi-x86_64
}

function load_openmpi {
    set_openmpi

    export PATH=$MPI_BIN:$PATH
    export LD_LIBRARY_PATH=$MPI_LIB:$LD_LIBRARY_PATH
    export MANPATH=$MPI_MAN:$MANPATH

    export MPI_HOME MPI_BIN MPI_LIB MPI_MAN MPI_INCLUDE MPI_SYSCONFIG
    export MPI_COMPILER MPI_SUFFIX MPI_PYTHON_SITEARCH MPI_FORTRAN_MOD_DIR
}

function unload_openmpi {
    set_openmpi

    export PATH=$(echo $PATH | tr : '\n' | egrep -v "^$MPI_BIN$" | tr '\n' :)
    export LD_LIBRARY_PATH=$(echo $LD_LIBRARY_PATH | tr : '\n' | egrep -v "^$MPI_LIB$" | tr '\n' :)
    export MANPATH=$(echo $MANPATH | tr : '\n' | egrep -v "^$MPI_MAN$" | tr '\n' :)

    unset MPI_HOME MPI_BIN MPI_LIB MPI_MAN MPI_INCLUDE MPI_SYSCONFIG
    unset MPI_COMPILER MPI_SUFFIX MPI_PYTHON_SITEARCH MPI_FORTRAN_MOD_DIR
}

えーっと・・・これmodule経由で使うものなんでは。
というわけで、.bashrcの末尾に以下の一行を追記します。

load_openmpi

でもって、再度ログインすると

$ mpirun --version
mpirun (Open MPI) 1.6.4

Report bugs to http://www.open-mpi.org/community/help/

正常にmpi関連のコマンドが動くようになりました。

一応こっちも一応HPLを流してみましょう。
staclusterの時の残念な結果があるので、まずはBLASの確認

$ yum list installed |grep blas
blas.x86_64                    3.5.0-8.6.amzn1                 @amzn-main
blas-devel.x86_64              3.5.0-8.6.amzn1                 @amzn-main
$ rpm -qi blas.x86_64
Name        : blas
Version     : 3.5.0
Release     : 8.6.amzn1
Architecture: x86_64
Install Date: Wed 23 Mar 2016 11:50:31 PM UTC
Group       : System Environment/Libraries
Size        : 782395
License     : BSD
Signature   : RSA/SHA256, Thu 18 Sep 2014 01:36:21 AM UTC, Key ID bcb4a85b21c0f39f
Source RPM  : lapack-3.5.0-8.6.amzn1.src.rpm
Build Date  : Wed 17 Sep 2014 09:15:24 PM UTC
Build Host  : build-64001.build
Relocations : (not relocatable)
Packager    : Amazon.com, Inc. <http://aws.amazon.com>
Vendor      : Amazon.com
URL         : http://www.netlib.org/lapack/
Summary     : The Basic Linear Algebra Subprograms library
Description :
BLAS (Basic Linear Algebra Subprograms) is a standard library which
provides a number of basic algorithms for numerical algebra.

えーっと・・・Netlib版のBLASなのか・・・
これはさすがにありえんので、OpenBLASをインストールします。

$ sudo yum install openblas -y
Loaded plugins: priorities, update-motd, upgrade-helper
956 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package openblas.x86_64 0:0.2.16-3.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=============================================================================================================================================================================
 Package                                   Arch                                    Version                                       Repository                             Size
=============================================================================================================================================================================
Installing:
 openblas                                  x86_64                                  0.2.16-3.el6                                  epel                                  5.5 M

Transaction Summary
=============================================================================================================================================================================
Install  1 Package

Total download size: 5.5 M
Installed size: 32 M
Downloading packages:
warning: /var/cache/yum/x86_64/2016.03/epel/packages/openblas-0.2.16-3.el6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Public key for openblas-0.2.16-3.el6.x86_64.rpm is not installed
openblas-0.2.16-3.el6.x86_64.rpm                                                                                                                      | 5.5 MB     00:00
Retrieving key from http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6
Importing GPG key 0x0608B895:
 Userid     : "EPEL (6) <epel@fedoraproject.org>"
 Fingerprint: 8c3b e96a f230 9184 da5c 0dae 3b49 df2a 0608 b895
 From       : http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : openblas-0.2.16-3.el6.x86_64                                                                                                                              1/1
  Verifying  : openblas-0.2.16-3.el6.x86_64                                                                                                                              1/1

Installed:
  openblas.x86_64 0:0.2.16-3.el6

Complete!
[ec2-user@ip-172-31-13-62 ~]$ sudo yum install openblas-devel -y
Loaded plugins: priorities, update-motd, upgrade-helper
956 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package openblas-devel.x86_64 0:0.2.16-3.el6 will be installed
--> Processing Dependency: openblas-threads(x86-64) = 0.2.16-3.el6 for package: openblas-devel-0.2.16-3.el6.x86_64
--> Processing Dependency: openblas-openmp(x86-64) = 0.2.16-3.el6 for package: openblas-devel-0.2.16-3.el6.x86_64
--> Processing Dependency: libopenblasp.so.0()(64bit) for package: openblas-devel-0.2.16-3.el6.x86_64
--> Processing Dependency: libopenblaso.so.0()(64bit) for package: openblas-devel-0.2.16-3.el6.x86_64
--> Running transaction check
---> Package openblas-openmp.x86_64 0:0.2.16-3.el6 will be installed
---> Package openblas-threads.x86_64 0:0.2.16-3.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=============================================================================================================================================================================
 Package                                         Arch                                  Version                                     Repository                           Size
=============================================================================================================================================================================
Installing:
 openblas-devel                                  x86_64                                0.2.16-3.el6                                epel                                 88 k
Installing for dependencies:
 openblas-openmp                                 x86_64                                0.2.16-3.el6                                epel                                5.6 M
 openblas-threads                                x86_64                                0.2.16-3.el6                                epel                                5.6 M

Transaction Summary
=============================================================================================================================================================================
Install  1 Package (+2 Dependent packages)

Total download size: 11 M
Installed size: 68 M
Downloading packages:
(1/3): openblas-devel-0.2.16-3.el6.x86_64.rpm                                                                                                         |  88 kB     00:00
(2/3): openblas-openmp-0.2.16-3.el6.x86_64.rpm                                                                                                        | 5.6 MB     00:00
(3/3): openblas-threads-0.2.16-3.el6.x86_64.rpm                                                                                                       | 5.6 MB     00:00
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                         15 MB/s |  11 MB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : openblas-threads-0.2.16-3.el6.x86_64                                                                                                                      1/3
  Installing : openblas-openmp-0.2.16-3.el6.x86_64                                                                                                                       2/3
  Installing : openblas-devel-0.2.16-3.el6.x86_64                                                                                                                        3/3
  Verifying  : openblas-devel-0.2.16-3.el6.x86_64                                                                                                                        1/3
  Verifying  : openblas-openmp-0.2.16-3.el6.x86_64                                                                                                                       2/3
  Verifying  : openblas-threads-0.2.16-3.el6.x86_64                                                                                                                      3/3

Installed:
  openblas-devel.x86_64 0:0.2.16-3.el6

Dependency Installed:
  openblas-openmp.x86_64 0:0.2.16-3.el6                                                openblas-threads.x86_64 0:0.2.16-3.el6

Complete!

あとは、staclusterの時と同じようにHPLのソースをダウンロードしてきて、ビルド&実行します。

$ wget http://www.netlib.org/benchmark/hpl/hpl-2.2.tar.gz
--2016-05-31 14:13:01--  http://www.netlib.org/benchmark/hpl/hpl-2.2.tar.gz
Resolving www.netlib.org (www.netlib.org)... 160.36.131.221
Connecting to www.netlib.org (www.netlib.org)|160.36.131.221|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 539979 (527K) [application/x-gzip]
Saving to: ‘hpl-2.2.tar.gz’

hpl-2.2.tar.gz                              100%[========================================================================================>] 527.32K   598KB/s    in 0.9s

2016-05-31 14:13:03 (598 KB/s) - ‘hpl-2.2.tar.gz’ saved [539979/539979]

$ tar xfz hpl-2.2.tar.gz
$ cd hpl-2.2
$ cp setup/Make.Linux_PII_FBLAS ./

staclusterの時と同じくMake.Linux_PII_FBLASを編集します。(LAdir, LAlibの設定はちょっと変わっています。)

TOPdir       = $(HOME)/hpl-2.2
MPdir, MPinc, MPlib  ->コメントアウト
LAdir=/usr/lib64
LAlib= -L$(LAdir) -lopenblas
CC=mpicc
LINKER=mpicc

そして、makeします。

$ make arch=Linux_PII_FBLAS 2>&1 |tee makelog

HPL.datをstarclusterの時と同様に編集したらジョブ投入

> qsub -cwd -pe mpi 8 -b y mpirun ./xhpl

ところが、こんなエラーを吐いて終了します。

$ cat mpirun.e2
-sh: mpirun: command not found

エラーメッセージから察するに、bashじゃなくてsh経由でジョブを投げようとしているようなので、シェルスクリプトを作ってこっち経由で投げます。

$ cat run.sh
#!/bin/bash
mpirun ./xhpl
$ qsub -cwd -pe mpi 8 run.sh
Unable to run job: warning: ec2-user's job is not allowed to run in any queue

あれ・・・?

$ qconf -sel
no execution host defined

あ、アイドル状態が長すぎて計算ノードが落とされてますね・・・
EC2のマネジメントコンソールを見ると、確かに"Compute"と書かれたインスタンスがterminatedになっています。時間的にも起動して1時間くらい経過していたので、きちんと機能していますね!最大の問題は、この状態から計算ノードを起動する方法が分からんあたり・・・

仕方が無いので、一旦削除してもう一度作り直してみます。
ついでにopenblasのインストールは計算ノード側でもやらないと駄目だったことにも気付いたので改めて作業内容をまとめておきます。

>cfncluster create mycluster
Starting: mycluster
Status: cfncluster-mycluster - CREATE_COMPLETE                                  Output:"MasterPrivateIP"="172.31.6.163"
Output:"MasterPublicIP"="52.192.191.47"
Output:"GangliaPrivateURL"="http://172.31.6.163/ganglia/"
Output:"GangliaPublicURL"="http://52.192.191.47/ganglia/"

>ssh  ec2-user@52.192.191.47 -i CfnClusterTest.pem
$ for i in `qconf -sel`;do ssh $i "sudo yum install openblas openblas-devel -y"
$ wget http://www.netlib.org/benchmark/hpl/hpl-2.2.tar.gz
$ tar xfz hpl-2.2.tar.gz
$ cd hpl-2.2
$ cp setup/Make.Linux_PII_FBLAS ./
$ make CC=mpicc LINKER=mpicc TOPdir=`pwd` MPdir="" MPinc="" MPlib="" LAlib="-L/usr/lib64 -lopenblas" arch=Linux_PII_FBLAS 2>&1 |tee makelog

でもって、さっきと同じようにHPL.datを編集したらジョブを投げます。ただし、load_openmpiはrun.shの中で実行するように変更しました。

$  cat run.sh
#!/bin/bash
load_openmpi
mpirun ./xhpl
$ qsub -cwd -pe mpi 8 run.sh
Your job 1 ("run.sh") has been submitted

ジョブが完走したら、run.sh.o2に結果が出力されます。

$ cat run.sh.o2
================================================================================
HPLinpack 2.2  --  High-Performance Linpack benchmark  --   February 24, 2016
Written by A. Petitet and R. Clint Whaley,  Innovative Computing Laboratory, UTK
Modified by Piotr Luszczek, Innovative Computing Laboratory, UTK
Modified by Julien Langou, University of Colorado Denver
================================================================================

An explanation of the input/output parameters follows:
T/V    : Wall time / encoded variant.
N      : The order of the coefficient matrix A.
NB     : The partitioning blocking factor.
P      : The number of process rows.
Q      : The number of process columns.
Time   : Time in seconds to solve the linear system.
Gflops : Rate of execution for solving the linear system.

The following parameter values will be used:

N      :   40000
NB     :      64
PMAP   : Row-major process mapping
P      :       4
Q      :       2
PFACT  :    Left
NBMIN  :       2
NDIV   :       2
RFACT  :    Left
BCAST  :   1ring
DEPTH  :       0
SWAP   : Mix (threshold = 64)
L1     : transposed form
U      : transposed form
EQUIL  : yes
ALIGN  : 8 double precision words

--------------------------------------------------------------------------------

- The matrix A is randomly generated for each test.
- The following scaled residual check will be computed:
      ||Ax-b||_oo / ( eps * ( || x ||_oo * || A ||_oo + || b ||_oo ) * N )
- The relative machine precision (eps) is taken to be               1.110223e-16
- Computational tests pass if scaled residuals are less than                16.0

================================================================================
T/V                N    NB     P     Q               Time                 Gflops
--------------------------------------------------------------------------------
WR00L2L2       40000    64     4     2             542.05              7.872e+01
HPL_pdgesv() start time Tue May 31 15:30:31 2016

HPL_pdgesv() end time   Tue May 31 15:39:33 2016

--------------------------------------------------------------------------------
||Ax-b||_oo/(eps*(||A||_oo*||x||_oo+||b||_oo)*N)=        0.0043542 ...... PASSED
================================================================================

Finished      1 tests with the following results:
              1 tests completed and passed residual checks,
              0 tests completed and failed residual checks,
              0 tests skipped because of illegal input values.
--------------------------------------------------------------------------------

End of Tests.
================================================================================

78.72Gflopsなので、実行効率にして45.5%ですね。starclusterの時と比べると約3倍になってますが、ちょっともの足りない数字です。
まだサイズを増やせば性能が上がる可能性もありますが、c3.largeだとメモリの制約が厳しいので、これより大きいサイズで測定するのは厳しそうです。
あと、OpenBLASの方がAtlasよりは性能が高いとは思いますが、DGEMM単体での性能を測定したわけではないので、まだBLASの性能が不足しているという可能性もありそうです。この辺はそのうち再検証してみましょう。

では、最後にクラスタを削除します。

>cfncluster delete  mycluster