playground.tensorflow.orgの仕組み
WebUIで機械学習を学習できるplaygroundというツールが、公開されている。このツールを使ったチュートリアルも散見される。
ここでは、該当ソフトウェア構成を見てみた。ソースコードは、GitHub - tensorflow/playground: Play with neural networks!にある。
動作としては、以下の通りである。
- dist以下のディレクトリに、html/css/jsファイル等を配置する。
- npmにより起動されたhttpサーバが、dist以下のファイルを提供する。
- 提供されたhtml/css/js等のファイルは、ブラウザ側で動く。(サーバ側の負荷はなし)
なお、ニューラルネットワークの計算は、src/nn.tsで行っている。
その他の関連ファイル
- npm(Javascript用パッケージ管理ツール)
- package.json (npmの設定ファイル。依存ファイル名等記載)
- TypeScript(Microsoftが作ったJavascript用メタ言語)
- Documentation · TypeScript
- tsconfig.json (TypeScriptの設定ファイル)
- tslint.json (TypeScriptのチェックツール)
- typings.json (TypeScriptの型定義ツール)
PythonのGlobal Interpreter Lock (GIL) について
Python (CPython) では、インタープリターはひとつしかない。このため、複数のスレッドを走らせた場合、ある時点ではひとつのスレッドしか動かない。このためのスレッド同期機構を、Global Interpreter Lock (GIL) という。PythonでのGIL自体は、1992年の初期実装から変更が無い。しかし、Lockのスレッド間引渡し方法が、Python 3.2から変更されている。これにより、CPUインテンシブプロセスでの複数コアで複数スレッドを動かした場合の性能劣化を改善している。
ここでは、2.7と3.5を比較してどのように違うかを説明する。Python 2.7は、interpreter_lock (GIL) と _Py_Ticker (GIL監視間隔 大まかに命令数100が標準)からなる。なお、切り替え間隔は、sys.setcheckintervalで設定することが出来る。この方式では、スレッド間でロックを取り合って実行を継続する。別コアで動いているスレッド間の場合、ロックの開放情報をシグナルで別コアに送るのは時間がかかる。このため、CPUインテンシブプロセス間のコンテキストスイッチは、ほぼ永遠に発生しない。このため、全体として処理効率が落ちる。
Python 3.5は、gil_locked (GIL) 、gil_drop_request (GIL要求)および gil_interval (GIL監視間隔 5000マイクロ秒 (5ミリ秒) が標準) からなる。なお、切り替え間隔は、sys.setswitchintervalで設定することが出来る。この場合、gil_drop_requestをスレッド間のフラグとして用いる。待ちスレッドがフラグを設定して要求し、一定時間後実行スレッドが、フラグを確認しスレッドのロックを開放し、待ちスレッドに実行件を譲る。これにより、マルチコアでも、効率的にコンテキストスイッチを行うことが出来る。
とはいえ、Python3.2以降に簡単に切り替えられない(たとえば、Python 2.xベースであり、Python 3.xへ移行できない)という場合もありうる。この場合、Pythonプロセスの実行するコアを指定する等の対策が必要と考えられる。言うまでも無く、CPUインテンシブプロセスが6つあれば、6つのコアにそれぞれ指定する等が考えられる。
マニュアル
- 3.5
- gil_locked/gil_interval (microsec)/INTERVAL等、関数としてはtake_gil等
- PyInterpreterState/PyThreadState等
- PyEval_EvalFrameEx =>ループとして、切り替えて動く
- コンテキストスイッチ部分
- Py_Main
- 2.7
その他の参考資料
- 3.2でのGIL更新(マルチコアでの性能劣化の話が記載されている)
- 3.2前後での性能比較等
- 古いGILでのトラブル例
Pythonのバイトコードまで
PythonスクリプトからPythonのバイトコードまで、どうなっているかを追いかけてみた。
具体的には、Pythonスクリプトから、pycファイルが保存されるまでである。
コマンドラインやスクリプトで実行する場合は以下に相当する
# python -m compileall file.py
import py_compile
py_compile.compile("file.py")
Pythonのスクリプトは、パースされ、AST (抽象構文木) を生成し、CFG (制御フローグラフ) となり、バイトコードとして生成される。CFGから、バイトコードは、assemble()で生成する。
pycの書式は、以下からなっている。(_code_to_bytecode()関数にて)
- MAGIC_NUMBER
- mtime
- size
- code
ついでながら、codeは、marshall(シリアライズ)している。
- ソースコード
- コンパイルするためのスクリプト
- pycの書込み
- pycを実行するコード
- MAGIC_NUMBER
- pycへの書き込みデータ (_code_to_bytecode)
- バイトコードへのコンパイルから実行までの主なコード群
- cpython/ceval.c at 3.5 · python/cpython · GitHub(VM engine)
- cpython/ceval.h at 3.5 · python/cpython · GitHub
- cpython/compile.c at 3.5 · python/cpython · GitHub(Bytecode compiler)
- cpython/compile.h at 3.5 · python/cpython · GitHub
- cpython/frameobject.c at 3.5 · python/cpython · GitHub(execution frames)
- cpython/frameobject.h at 3.5 · python/cpython · GitHub
- cpython/opcode.h at 3.5 · python/cpython · GitHub(bytecodes)
- cpython/code.h at 3.5 · python/cpython · GitHub(PyCodeObject)
- cpython/pystate.c at 3.5 · python/cpython · GitHub(interpreter state)
- cpython/pystate.h at 3.5 · python/cpython · GitHub
- cpython/pythonrun.c at 3.5 · python/cpython · GitHub(entry point)
- cpython/pythonrun.h at 3.5 · python/cpython · GitHub
- ドキュメント
- DevGuide
- Library
- marshal — Internal Python object serialization — Python 3.7.3 documentation
- 29.12. inspect — Inspect live objects — Python 3.5.7 documentation
- importlib — The implementation of import — Python 3.7.3 documentation
- ast — Abstract Syntax Trees — Python 3.7.3 documentation
- py_compile — Compile Python source files — Python 3.7.3 documentation
- compileall — Byte-compile Python libraries — Python 3.7.3 documentation
- dis — Disassembler for Python bytecode — Python 3.7.3 documentation
- その他
- CPythonVmInternals - Python Wiki
- Pythonの内部構造の授業(10時間)
- Python VM (ceval.c) の動きを説明している。(PyFrameObjectの動き等々)
- 動的情報をどこにおいてあるかの説明(PyFrameObject => PyCodeObject)
- python2.7の場合
- https://www.usenix.org/legacy/event/woot08/tech/full_papers/portnoy/portnoy.pdf
- python2.5の場合
- 500 Lines or Less | A Python Interpreter Written in Python
Heat/Autoscaling
HeatのAutoScalingは、Ceilometer (Newtonからは、Aodh)のサーバ等の負荷の信号を用いて、スケールさせる。
フローとしては、以下の通り
- Heat EngineからCeilometerにシグナルを登録
- Ceilometerから、Heat_API_CFNに変更を通知
- Heat_API_CFNから、Heat Engineに変更を通知 (handle_signalが稼動する)
- Heat Engineは、スケールインもしくはアウトする (サーバの起動又は停止)
なお、スケールの変更可否は、Cooldownクラスで行う。
参考資料
- AutoScaleの分割
- AutoScaleのテンプレート
- spec
- 開発者用文書
- 解説例 (HEAT Engine/API_CFNとCeilometerの連携等)
コマンド
- deployment-create
- handle_signal
- heat.api.cfn.v1
- その他関連コード
- SIGNAL_TYPES
- Attributes (FnAttr)
- default_deployment_signal_transport
Python2*3(six)での違い(printの改行)
OpenStackでのoslo_service/eventlet/greenlet
OpenStackの各コンポでWSGI (Web Service Gateway Interface) をどう実現しているか?の観点で見ると、eventlet.wsgiを使っている場合が多い。
そして、eventlet.wsgiを効率的に動かすために、Greenletを使っている。なお、Greenletは、C言語拡張モジュールによるPython用のGreenThread実装である。このため、Pythonで実装したよりも、スレッド間切り替えが早い。
また、oslo_serviceを介してeventletを間接的に呼び出しているコンポもある。
2016年8月20日時点 (Newtonリリースの前) のコードでは、eventletのWSGIフレームワークの使用状況は以下の通りである。
コンポ名 | eventlet使用している? | oslo_serviceから使用している? |
---|---|---|
cinder | ○ | ○ |
glance | ○ | × |
heat | ○ | × |
ironic | ○ | ○ |
keystone | × | × |
neutron | ○ | ○ |
nova | ○ | × |
参考資料
- greenlet
- eventlet
- oslo_service
- eventletのwsgiをOpenStack用にラップしている。
OpenStackでのPythonコーディング規約チェック
OpenStackの場合hackingモジュールでPythonコード規約をチェックする。ただし、個別のコード規約は、モジュール毎のHACKING.rstに記載されている。そして、実際の個別チェックツールもhackingディレクトリにスクリプトがおかれている。出力されるエラーコードは、PEP8ベースのE/W系およびhackingベースのH系に分かれる。そのほかに、各コンポごとに設定されたエラーコードが出力される。ふと見るとNは、Nova/Neutronでコード番号がかぶっている。
- 参考資料
- 各コンポ
- N系 (Nova) のエラーの説明がある
- Heat系のエラーの説明がある
- N系およびC系 (Cinder) のエラーの説明がある(もともとNovaから分岐したためN系がある)
- G系 (Glance) のエラーの説明がある。
- keystone/HACKING.rst at master · openstack/keystone · GitHub
- N系 (Neutron) のエラーの説明がある。
- Swiftは、個別チェックHACKING.rstがない。
- E系および、W系のエラーの説明がある(PEP8)
- H系のエラー説明がある(Openstack hacking)
- 日本語での説明
- 各コンポ