HPCメモ

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

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などで管理は自動化できるとはいえ、本来要らないものを入れられるのにはちょっと抵抗があります。

windowsの"PROGRAMFILES"環境変数

32bit windowsでは、プログラムのインストール先はたいてい"C:Program Files"ですが、64bit windowsでは、64bitプログラムは"C:Program Files"に、32bitプログラムは"C:Program Files(x86)"に分けてインストールするのがお約束になっています。

この"Program Files"ディレクトリを参照する環境変数として%PROGRAMFILES%というのがあるんですが、この環境変数は呼び出し元プログラムが32bitか64bitかによって変わるようです。

C:\WORK>\Windows\SysWOW64\cmd.exe
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\WORK>echo %PROGRAMFILES%
C:\Program Files (x86)

C:\WORK>exit

C:\WORK>\Windows\System32\cmd.exe
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\WORK>echo %PROGRAMFILES%
C:\Program Files

一瞬逆に思えるけど、System32の下にあるのが64bit版で、SysWOW64の下にあるのが、32bit版のcmd.exeです。


インストーラ無しで配布されているプログラムをインストールする(chefの)recipeで、インストール先として

"#{ENV['PROGRAMFILES']}\\hoge"

みたいなのを指定してたら、git-bashから入れるとProgram Files(x86)に入るし、コマンドプロンプトから入れるとProgram Filesに入るし大混乱になりました・・・orz


一応、こんな感じで回避してますが、そもそもインストール先を選択する時に%PROGRAMFILES%を使うのは不適切だってことですね。

if kernel['machine'] =~ /x86_64/
     default['install_to']  = "#{ENV['PROGRAMW6432']}"
else
     default['install_to']  = "#{ENV['PROGRAMFILES']}"
end