パフォーマンスチューニングを行う際、改修前後で効果があらわれているか確認するのは重要です。Pythonにはデフォルトでパフォーマンス解析を行うモジュールが組み込まれているのですが、そのままではちょっと使いづらいく出力結果も見にくいです。そこで、簡易な記法で計測できる+結果の可視化を行うツールを作りました。
まず、実行結果(dump_stats
などで保存したファイル)を以下のようにグラフ・表で可視化できます。インストールするとpyfbi_viz
というコマンドが使えるので、それでファイルを保存したディレクトリを指定すればOKです。改修前の計測、改修後の計測2つのファイルをフォルダに入れておけば前後の可視化が可能です。
pyfbi_viz stat_dir=ファイルを保存したディレクトリ
-
pure
は内部で呼び出している関数の実行時間を加味しない、純粋な実行時間になります(tottime
)。total
は、呼び出している関数の実行時間も含めた実際の処理時間になります(cumtime
に相当)。/call
は呼び出し一回当たりの時間になります。
計測に際しては、以下のようにpyfbi.target
を設定したところだけ計測を行うことが可能です。with pyfbi.watch
で開始して抜けるまで観測が行われます。
import time
import pyfbi
@pyfbi.target
def func1():
time.sleep(1)
def func2():
time.sleep(2)
with pyfbi.watch():
[f() for f in (func1, func2)]
pyfbi.show() # func2は計測されない
pyfbi.dump("your_stat_file_path") # ファイルに保存
もちろん、特に指定せず全てを対象にすることも可能です。その場合は以下のようにglobal_watch=True
を設定します。
with pyfbi.watch(global_watch=True):
[f() for f in (func1, func2)]
pyfbi.show() # func2も計測される
定期的な実行を行うことも可能です(x秒ごとに観測してファイルを保存するなど)。
import pyfbi
(set target to your function)
stat_dir = os.path.join(os.path.dirname(__file__), "stats")
# You can use global_watch=True if you want to profile all functions.
with pyfbi.watch_periodic(seconds=5, stat_dir=stat_dir):
for f in [func1, func2, func2, func3, func1, func1]:
f()
作成した背景
画像中の関数を見てピンと来た方がいるかもしれませんが、これはISUCON7に向けて作成されたツールです。実地でも「計測する」「改修する」「改善を確認してMergeする」というプロセスを踏んで行くのに役立ちました(実際は画像のキャッシュに気付くという壁を超えることができずその改善効果が日の目を見ることはほぼなかったのだが・・・)。
ベンチの値は非常に変動が大きく、またある程度待ち時間もあるため改修結果を測るのに使うのは難しかったです。その意味でも、確かな計測値が手に入るのは良かったです。
予選通過はならずでしたが、せっかく作ったものなのでパフォーマンス改善の折にはぜひ使っていただければと思います。
icoxfog417/pyfbi
(Starを頂けると予選敗退の心が癒されます m(_ _)m)