HPCメモ

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

windows(cygwin)でansible

ずいぶん前に、windows nativeなpythonに無理矢理ansibleをインストールしてみたら、pwdだのfcntlだのといったUnix固有の標準ライブラリに依存しまくってて、まったく歯が立たなかったので放置してたんですが、最近babunというcygwinの派生版を使い始めたのでこっちで試してみることにしました。

pipのインストール

現時点のbabunのpythonは2.7.10なので、pipのwebページによるとインストール済のはずですが、

pip is already installed if you're using Python 2 >=2.7.9 or Python 3 >=3.4 downloaded from

https://pip.pypa.io/en/stable/installing/

どうやらインストールされてないようでwhich pipするとwindows nativeのpython用のpipが返されます。

> which pip
/cygdrive/c/ProgramData/chocolatey/bin/pip


公式ページの英語版ドキュメントによると

The ensurepip package provides support for bootstrapping the pip installer into an existing Python installation or virtual environment. This bootstrapping approach reflects the fact that pip is an independent project with its own release cycle, and the latest available stable version is bundled with maintenance and feature releases of the CPython reference interpreter.

In most cases, end users of Python shouldn’t need to invoke this module directly (as pip should be bootstrapped by default), but it may be needed if installing pip was skipped when installing Python (or when creating a virtual environment) or after explicitly uninstalling pip.

https://docs.python.org/2.7/library/ensurepip.html

とのことなので、ensurepipを使ってインストールしましょう。

> which python
/usr/bin/python
> python -m ensurepip
Ignoring indexes: https://pypi.python.org/simple
Collecting setuptools
Collecting pip
Installing collected packages: setuptools, pip
Successfully installed pip-6.1.1 setuptools-15.2
> which pip
/usr/bin/pip
> pip install -U pip
You are using pip version 6.1.1, however version 8.1.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting pip
  Downloading pip-8.1.0-py2.py3-none-any.whl (1.2MB)
    100% |████████████████████████████████| 1.2MB 327kB/s
Installing collected packages: pip
  Found existing installation: pip 6.1.1
    Uninstalling pip-6.1.1:
      Successfully uninstalled pip-6.1.1
Successfully installed pip-8.1.0

virtualenvのインストール

以前書いたwindows版の記事を参考にpipでインストールします。
hpcmemo.hatenablog.com

> pip install virtualenv
Collecting virtualenv
  Downloading virtualenv-15.0.0-py2.py3-none-any.whl (1.8MB)
    100% |████████████████████████████████| 1.8MB 231kB/s
Installing collected packages: virtualenv
Successfully installed virtualenv-15.0.0

ansibleのインストール

virtualenvで環境を作って、ansibleをインストールします。

> virtualenv ansible
New python executable in /cygdrive/c/Users/n_so5/OneDrive/Python/ansible/bin/python2.7
Also creating executable in /cygdrive/c/Users/n_so5/OneDrive/Python/ansible/bin/python
Installing setuptools, pip, wheel...done.
> cd ansible
> . bin/activate
(ansible)>  pip install ansible
Collecting ansible
  Using cached ansible-2.0.1.0.tar.gz
Collecting paramiko (from ansible)
  Downloading paramiko-1.16.0-py2.py3-none-any.whl (169kB)
    100% |████████████████████████████████| 174kB 706kB/s
Collecting jinja2 (from ansible)
  Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB)
    100% |████████████████████████████████| 266kB 1.1MB/s
Collecting PyYAML (from ansible)
  Downloading PyYAML-3.11.tar.gz (248kB)
    100% |████████████████████████████████| 256kB 758kB/s
Requirement already satisfied (use --upgrade to upgrade): setuptools in /usr/lib/python2.7/site-packages (from ansible)
Collecting pycrypto>=2.6 (from ansible)
  Downloading pycrypto-2.6.1.tar.gz (446kB)
    100% |████████████████████████████████| 450kB 975kB/s
Collecting ecdsa>=0.11 (from paramiko->ansible)
  Downloading ecdsa-0.13-py2.py3-none-any.whl (86kB)
    100% |████████████████████████████████| 92kB 2.3MB/s
Collecting MarkupSafe (from jinja2->ansible)
  Downloading MarkupSafe-0.23.tar.gz
Installing collected packages: ecdsa, pycrypto, paramiko, MarkupSafe, jinja2, PyYAML, ansible
  Running setup.py install for pycrypto ... done
  Running setup.py install for MarkupSafe ... done
  Running setup.py install for PyYAML ... done
  Running setup.py install for ansible ... done
Successfully installed MarkupSafe-0.23 PyYAML-3.11 ansible-2.0.1.0 ecdsa-0.13 jinja2-2.8 paramiko-1.16.0 pycrypto-2.6.1

動作確認

とりあえずテストとしてpingでも打ってみます。

> echo hoge.huga.com > hosts
> ansible hoge.huga.com -m ping -i hosts
0 [main] python2.7 6852 child_info_fork::abort: address space needed by '_speedups.dll' (0x460000) is already occupied
ERROR! Unexpected Exception: 'NoneType' object has no attribute 'terminate'
to see the full traceback, use -vvv

_sppedups.dllってなんじゃと思ってfindしてみると

> find ./ -name _speedups.dll
./lib/python2.7/site-packages/markupsafe/_speedups.dll

さっきansibleを入れた時に一緒にインストールされたMarkupSafeに含まれるライブラリのようです。

おそらく、こちらの記事と同じ問題だろうと推測して、同じことをやってみます。
d.hatena.ne.jp

> find `pwd` -name '*.dll' -o -name '*.so' >~/rebase_list
一旦babunのターミナルを終了して、%USERPROFILE%\.babun\cygwin\bin\ash.exe を実行
$cd $HOME
$/bin/rebaseall -T rebase_list -v
(中略)
/usr/bin/cygattr-1.dll: new base = 6fe10000, new size = 10000
/usr/bin/cygatomic-1.dll: new base = 6fe20000, new size = 20000
/usr/bin/cygaspell-15.dll: new base = 6fe40000, new size = b0000
/usr/bin/cygarchive-13.dll: new base = 6fef0000, new size = b0000
/usr/bin/cygaprutil-1-0.dll: new base = 6ffa0000, new size = 30000
/usr/bin/cygapr-1-0.dll: new base = 6ffd0000, new size = 30000

再度babunを起動して、

> ansible hoge.huga.com -m ping -i hosts
hoge.huga.com | UNREACHABLE! => {
    "changed": false,
    "msg": "SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue",
    "unreachable": true
}

forkの問題は解消されたっぽいけどやっぱり接続できません。
とりあえず、-vvvvを付けて実行してみると、ログの最後の方で"Broken Pipe"というのが表示されていたのでぐぐってみたところ、こんな記事がひっかかりました。
blog.simonmetzger.de
しかし、ansible.cfgに書いたのでは-vvvvオプションを付けると、あいかわらずControlMaster=autoになっていたので、コマンドライン引数を追加して

> ansible hoge.huga.com -m ping -i hosts --ssh-extra-args="-o ControlMaster=no"

にしてみました。

それでもUNREACHABLEは変わらないので、さらにしばらくぐぐり続けたところ、こんなページがみつかりました。
serverfault.com
.sshの下のファイルのowner/groupを見たらgroupが"None"になっていたので、試しに

> chown ユーザ名:Users ~/.ssh/*

をしてみたところ、ようやく接続できました。

> ansible hoge.huga.com -m ping -i hosts --ssh-extra-args="-o ControlMaster=no"
hoge.huga.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

何回か再実行すると、時々FAILになったりするので、ちょっと実用にはほど遠いんですがとりあえずこの辺で一旦終了しときます。

これまでのまとめ

babun環境からansibleを使う時は

  • ansibleをインストールしたら、dllファイルのリストを作ってrebaseall
  • .ssh/ 以下のファイルのowner/groupを正しく設定する
  • --ssh-extra-args="-o ControlMaster=no"をつける

それでも、なんか失敗する時あり・・・orz

Intel版python

先日、VTuneのドキュメントを漁っていたら面白そうなものを見つけました。

Python* Distribution | Intel® Developer Zone

ドキュメントを見たところ、MKLとnumpy/scipyを同梱したpythonのようです。*1

ダウンロードするためには、Technical Previewへ参加する必要がありますが、これに参加するとついでにVTuneの最新版のTechnical Previewにも参加したことになるようです。

Python* Profiling | Intel® Developer Zone

これ、python専用の機能限定版じゃなくて、フル機能版みたいなので*2色々と楽しめそうです。


とりあえずpythonを入れるマシンを用意せんといかんなぁ

*1:enthoughtの有料版と一緒じゃねーか?

*2:会社のPCにこっそり入れようとしたら、"Newer version is already installed"とか言われたので・・・

git-hookを使ってコミット時にテスト

就職して以来CVS->subversion->gitと、かれこれ10年近くVCSを使ってきましたが、今だにcommitを忘れるという初歩的な問題が解決できません・・・

  1. ソース作成/修正
  2. ビルド
  3. テスト
  4. コミット

という順番で作業してると、ビルド&テストしてる間に時間が空いてしまって作業が止まるのが原因だろうと仮定してgit-hookを使ったポカヨケを作り込んでみました。

サンプルのプロジェクトとして、懐しのはろーわーるどをCで書いてみました。

#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("hello world!\n");
  return 0;
}

ビルド用のmakefileはこんな感じ

LM=hello
LINKER=$(CC)
LDFLAGS=$(CFLAGS)

SRCS_C=hello.c
OBJS_C=$(SRCS_C:%.c=%.o)

OBJS=$(OBJS_C)

all:$(LM)

$(LM):$(OBJS)
        $(LINKER) $(LDFLAGS) $(OBJS) -o $(LM)


.PHONY: clean

clean:
        -rm -rf *.o $(LM)

そして、テストスクリプトとして次のようなpythonスクリプトをtest.pyとして置いておきます。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import subprocess
import sys

if __name__ == "__main__":
    output=subprocess.check_output("./hello")
    if output == "Hello world!\n":
        sys.exit(0)
    else:
        print("FAILED!!")
        print output
        sys.exit(1)


ここまで準備できたら、次はhookを用意します。

".git/hooks/commit-msg"という名前で次のようなシェルスクリプトを作ります。

#!/bin/sh

#コミットメッセージが空でなければ
#ビルド&テストを実施
grep -v -e'^#' -e'^$' $1 >/dev/null
if [ $? -eq 0 ];then
  make && python test.py
  exit $?
fi


これでgit commitしてメッセージを書き終えると自動的にmakeとtest.pyが実行されます。
今の状態だと、hello は"hello world!"と出力するのに、テストでは"Hello world!"と出力することを期待されているのでテストに失敗し、コミットできないはずです。
ではさっそく試してみましょう。

> git add hello.c Makefile test.py
>  git commit -m'Initial commit'
cc    -c -o hello.o hello.c
cc  hello.o -o hello
FAILED!!
hello world!

>git log
fatal: bad default revision 'HEAD'

たしかに、コミットされてません!
hello.cを修正して、正しく"Hello world!"と出力するように変えると

 git commit -m'Initial commit'
cc    -c -o hello.o hello.c
cc  hello.o -o hello
[master (root-commit) c524d0b] Initial commit
 3 files changed, 42 insertions(+)
 create mode 100644 Makefile
 create mode 100644 hello.c
 create mode 100755 test.py

>git log
commit c524d0bd9c1ed94fa20b9eab29a222f6312237d3
Author: n_so5 <n_so5@localhost>
Date:   Fri Jan 29 14:10:47 2016 +0900

    Initial commit

無事にコミットされました!


あとは、必ずテストを書くという強い心があれば大丈夫・・・orz

cmderでIntel CompilerとVSを使う設定

数値計算というと、大学とかに置いてあるスパコンにログインして、Linuxコマンドラインで作業してるイメージが強いかもしれませんが、時々windows上でVisualStudioとIntelコンパイラで開発してますっていう人にも出会います。*1

となると、受託開発ではやっぱりwindowsでやってねというお話をいただくこともあるんですが、いかんせんVSの起動が遅すぎるので
viでコードを書いてコマンドラインからビルドするといういつものスタイルで作業したくなるわけです。
しかし、インテルコンパイラのインストール時にもろもろ設定してくれたコマンドプロンプトは、所詮windowsのデフォルトのコマンドプロンプト上で環境変数などを設定しただけのものなので、使い難いったらありゃしない。


前置きが長くなりましたが、cmderの設定をいじって、インテルコンパイラを使える状態のcmd.exeが起動するようにしようというのが今回の目的です。
ちなみに環境はIntel Parallel Studio 2016+Visual Studio 2015+windows7な環境ですので、インストール先などは適宜読み替えてください。


まずは既存の設定の確認から

スタートメニューから「すべてのプログラム」->「Intel Parallel Studio XE 2016」->「Compiler and Performance Libraries」-> 「Command Prompt with Intel Compiler 16.0」とたどって「Intel 64 Visual Studio 2015 environment」をクリックします。


f:id:n_so5:20151202104215p:plain


プロパティ画面が開いたらリンク先欄にある文字列をコピーしておいて、cmderを起動します。
cmderのsettings画面で、「Startup」-> 「Tasks」とたどって「+」ボタンを押し右下の欄にペーストします。
後は上の方にある欄に適当に名前を付ければ完了です。


f:id:n_so5:20151202111235p:plain


cmder上で[+]ボタンの横にある下向き三角をクリックすると、メニューがずらっと出てくるので
さきほど作ったtaskを選ぶと、こんな感じでiclにパスが通った状態でコマンドプロンプトが起動します。


f:id:n_so5:20151202111651p:plain


あとは、vi+ctagsがあれば快適なコーディングができます。
ま、自由にいじっていいならcmakeでビルドするようにして、バッチファイルでも置いとくんですが・・・

*1:以前の同僚はVSしか使ったことが無いとか言ってて入社してきた時に凄いカルチャーショックを受けました

pandas+matplotlibで3D棒グラフを作る

たとえば、こんな感じの表があったとするじゃないですか。

うし ぶた とり
肉屋 580 280 300
スーパー 420 260 320

これを、エクセルに入力して、挿入->3D-縦棒と選ぶと

f:id:n_so5:20151008183105p:plain

こんな感じのかっこいい(?)グラフが作れるわけですが、これをpandas+matplotlibでやってみようというお話です。

結論から先に書くと

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.font_manager import FontProperties

df=pd.DataFrame({u"うし":[580, 420],
                 u"とり":[280, 260],
                 u"ぶた":[300, 320]},
               index=(u"肉屋", u"スーパー"))

ax=plt.figure().add_subplot(111, projection='3d')
fp=FontProperties(fname=r'C:\WINDOWS\Fonts\msgothic.ttc', size=10)

xpos,ypos=np.meshgrid(np.arange(len(df.index)), np.arange(len(df.columns)))
xpos=xpos.flatten()
ypos=ypos.flatten()
zpos=np.zeros(len(xpos))
dx=np.full(len(xpos), 0.05)
dy=np.full(len(ypos), 0.1)
dz=df.as_matrix().flatten()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz)

ax.set_xlabel(u"お店", fontproperties=fp)
ax.set_ylabel(u"種類", fontproperties=fp)
ax.set_zlabel(u"金額", fontproperties=fp)
plt.xticks(np.arange(len(df.index)),   df.index, fontproperties=fp)
plt.yticks(np.arange(len(df.columns)), df.columns, fontproperties=fp)

plt.axis([-0.5, len(df.index)-0.5, -0.5, len(df.columns)-0.5])

plt.savefig("hoge.png")

みたいなコードになります。


公式ページのexampleを見ると、
mplot3d example code: bars3d_demo.py — Matplotlib 1.4.3 documentation
ってのがありますが、こっちは普通の棒グラフを奥行方向に重ねて並べるもののようで、今回作ろうと思っていたのとはちょっと違います。

一見関係無さそうな名前ですが、
mplot3d example code: hist3d_demo.py — Matplotlib 1.4.3 documentation
のところで使っている、bar3d()が今回のグラフに必要な関数でした。
ところがこの関数、APIドキュメントがこんな調子でまったく意味不明です。

bar3d(x, y, z, dx, dy, dz, color=u'b', zsort=u'average', *args, **kwargs)

Generate a 3D bar, or multiple bars.

When generating multiple bars, x, y, z have to be arrays. dx, dy, dz can be arrays or scalars.

color can be:

A single color value, to color all bars the same color.
An array of colors of length N bars, to color each bar independently.
An array of colors of length 6, to color the faces of the bars similarly.
An array of colors of length 6 * N bars, to color each face independently.

When coloring the faces of the boxes specifically, this is the order of the coloring:

-Z (bottom of box)
+Z (top of box)
-Y
+Y
-X
+X

Keyword arguments are passed onto Poly3DCollection()

http://matplotlib.org/mpl_toolkits/mplot3d/api.html#mpl_toolkits.mplot3d.axes3d.Axes3D.bar3d

x, y, z have to be arraysとか言われても、何の値入れりゃえんじゃーと悩んでましたが、どうやら

  • 各配列は全て同じ長さの1次元配列にする
  • i番目の棒の左下隅の頂点座標をx, y, zのi番目の要素で指定
  • i番目の棒の各軸方向の幅をdx, dy, dzのi番目の要素で指定

ということのようです。

ちなみに、この例ではx、yともに項目名なのであまり違和感は無いかもしれませんが、元々私がやってた時は2次元でパラメータを振った時の実験結果をプロットしようとしていたので、x, y, zに値を入れてからdx, dy, dzって何を入れるんだろうかと、かなりドツボにはまってました。*1

あとのところは、コードを見れば分かると思いますので、解説は省きますが

set_?label
ラベルの設定
{x,y}ticks
x/y座標の値の指定
axis
座標軸の長さ指定
savefig
グラフを画像ファイルとして保存

です。


matplotlibの全般的な話は
matplotlib入門 - りんごがでている
に助けられました。ここ読まなかったら未だドキュメントの海で溺れてたと思いますorz

あと、フォント関連の設定については
Python - matplotlibで日本語 - Qiita
を参考にさせていただきました。



そういや、pandasろくに使って無いな・・・

*1:素直にwire frameでやってればそんなにはまらなかった気がしないでもない

windowsでのpython3のセットアップ

相変わらず仕事でpythonが絡むと「python2向けで」とか、下手すると「2.6で動作すること」とか言われますが、そろそろ自作のソフトくらいはpython3へ移行しようと思い立って、まずは環境を用意することにしました。

まずは、chocolateyからpython2/3をまとめてインストールします。

>choco install python python2 -y Chocolatey v0.9.9.7
Installing the following packages:
python;python2
By installing you accept licenses for the packages.

python v3.4.3.20150501
 Get-BinRoot is going to be deprecated by v1. Many packages no longer require it since the folders no longer have versions on them.
 Downloading python 32 bit
   from 'https://www.python.org/ftp/python/3.4.3/python-3.4.3.msi'
 Installing python...
 python has been installed.
 The install of python was successful.

python2 v2.7.10
 Get-BinRoot is going to be deprecated by v1. Many packages no longer require it since the folders no longer have versions on them.
 Warning: Old installation path “C:\Python27” detected.
 This package will continue to install python2 there unless you uninstall
 python2 from there and remove the “C:\Python27” folder. If you decide
 to do that, reinstall this package with the -force parameter and it will
 install to the Chocolatey bin root.
 Installing python2...
 python2 has been installed.
 The install of python2 was successful.

Chocolatey installed 2/2 package(s). 0 package(s) failed.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

途中で別のwindowが開いたりしますが、インストール完了後に一旦コマンドプロンプトを開き直すと

> python --version
Python 3.4.3
> C:\Python27\python.exe --version
Python 2.7.10

といった形でpython2と3が無事に動くようになりました。

続いてvirtualenvのインストール

>C:\tools\python3\Scripts\pip install virtualenv
You are using pip version 6.0.8, however version 7.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting virtualenv
  Downloading virtualenv-13.1.2-py2.py3-none-any.whl (1.7MB)
    100% |################################| 1.7MB 63kB/s
Installing collected packages: virtualenv

Successfully installed virtualenv-13.1.2

では、さっそくvirtual envを使って、python2.7用の環境を作ってみましょう。

>python -m virtualenv --python=C:\Python27\python.exe Py27
Running virtualenv with interpreter C:\Python27\python.exe
New python executable in Py27\Scripts\python.exe
Installing setuptools, pip, wheel...done.

Py27フォルダに移動して、activateすると

>cd Py27
>Scripts\activate
>python --version
Python 2.7.10

となって、無事にpython2.7の環境ができました。
この状態からdeactivateすると素の環境に戻ります。

>deactivate
>python --version
Python 3.4.3


とりあえず、2.7と3.4用の開発環境を一式作っておこう。

chefをやめてchocolateyへ

単にパッケージをインストールするだけのこんな感じのレシピをいくつか書いた後でふと気づきました。

if platform_family?('windows')
    windows_package node['hoge']['display_name'] do
      source         node['hoge']['url']
      installer_type :custom
      action         :install
      options        "/quiet"
    end
end

わざわざchefを使うまでの話でもないな・・・



というわけで、単純なインストール作業はchocolateyに
お任せすることにしました。

そうすると、今までchefでやってた作業で残るものは

  1. C:\WORKの作成
  2. 環境変数HOMEの設定
  3. gitで管理しているドットファイルの取得
  4. ssh鍵の作成
  5. フォントのインストール
  6. 環境変数PATHの設定(viとかのインストール先を追加したい)
  7. 自動起動の設定(主にautohotkey)

といったところです。

このうち、1, 2, 3, 6, 7についてはpowershellスクリプトに移行しました。
4,5は大した手間でもないので、手作業でやってます。*1



私が考えていたchefの利点というのは以下の3つでした。

  • 冪等性
  • platform independent
  • DSL

ところが、1のケースで考えると、そもそも既存のディレクトリが存在したら、ディレクトリは生成できるわけがないので、どんな手段を使うにしても冪等性を考える必要はないわけです。*2
同じように、3のケースであればgitコマンド自体が冪等性を保証してくれますし、ソフトのインストールについてもインストール済みであればwindowsインストーラが大抵は勝手に判定してくれます。

環境変数の設定はbashのexportでもsetxコマンドでも考慮してくれないので、PATHに同じディレクトリが複数回設定されるような状況が容易に起こるわけですが、この程度のことのためにchefを導入するのは、役不足でしょう。


platform依存性という観点では、そもそも設定している内容がwindows環境だから設定しないといけないという性質のものばかりなので、実際のところ、これまでの運用ではあまり活かせてませんでした。
vagrantvirtualboxみたいな、どんなOSでも入れたいソフトもあるので、こういったもののインストールはお任せしたいところなんですが、現状のchefではaptやyumdmgwindowsのような、各プラットフォームに対応するためのcookbookも準備する必要があって、少々煩わしいです。*3
あと、pythonとかnode.jsのような、重要なソフトのコミュニティcookbookがwindowsに対応していなくて、結局自分でwindows専用のcookbookを
書く羽目になるのも悲しいところです。


最後のDSLというのは、スクリプトで書き直していると重要性を痛感できるんですが、これまた環境変数の件と同じく、これだけのためにchefを導入するもんでもないなぁと感じてます。


というわけで、ほぼすべての自作cookbookは闇に葬られて、いくつかのpowershellスクリプトに生まれ変わりました。

*1:そもそも4は今までもパスフレーズの入力の時に操作する必要があったので完全に自動化できてたわけじゃないし

*2:ファイルシステムが担保していると考えれば良いのかな?

*3:Berkshelfなどで管理は自動化できるとはいえ、本来要らないものを入れられるのにはちょっと抵抗があります。