• Like
Pythonista も ls を読むべきか?
Upcoming SlideShare
Loading in...5
×

Pythonista も ls を読むべきか?

  • 3,689 views
Uploaded on

Python Developers Festa 2013.11 での発表資料です。 …

Python Developers Festa 2013.11 での発表資料です。
https://github.com/pyspa/pyfes/blob/develop/201311.rst
性能計測結果は Solaris 系の OpenIndiana 151a 上で実施したものですので、他の OS の場合は異なる傾向となる可能性もあります。

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,689
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
18
Comments
0
Likes
15

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Pythonista も ls を読むべきか? 藤原 克則 @flyingfoozy
  • 2. 自己紹介
  • 3. O 藤原 克則 (FUJIWARA Katsunori) O ホームページ http://www.lares.dti.ne.jp/~foozy/index.ja.html O ブログ http://d.hatena.ne.jp/flying-foozy/ O Twitter @flyingfoozy
  • 4. O 分散リポジトリ型履歴管理ツール Mercurial の翻訳コミッタ/コントリビュータ O Mercurial の hack に特化した なんちゃって Pythonista
  • 5. O Solaris 上で稼働させる HPC 向けファイルシステムの実装などを 仕事でやっていたことも O 「Tokyo OpenSolaris 勉強会」 で Solarisカーネルの実装に関する勉強とか http://www.opensolaris.gr.jp/study.html O 下位レイヤの話も好き
  • 6. 執筆過程で見つけた バグの修正パッチが ソースツリーに取り込まれた
  • 7. GNU coreutils の ls は ワシが育てた! (約1/4900)
  • 8. 本日のお題は….
  • 9. Pythonista も ls を読むべきか?
  • 10. Pythonista: 「os.listdir() を使うから 読まなくても良くねぇ?」
  • 11. 例えばこんな感じ? import os for e in os.listdir(path): fullpath = os.path.join(path, e) if os.path.isdir(fullpath): # ディレクトリに対する処理 elif os.path.isfile(fullpath): # ファイルに対する処理 .....
  • 12. そんな実装では スケールしない!!!
  • 13. システムコール 呼び出しコスト O os.path.isdir(), os.path.isfile() ... は 判定処理毎に lstat(2) 呼び出し O 呼び出し頻度は 「要素数 × 平均的な if 判定数」 O コンテキストスイッチを生じるので 通常の関数呼び出しよりも 圧倒的にコストが高い
  • 14. 多少コスト意識が ある場合は…. import os, stat for e in os.listdir(path): fullpath = os.path.join(path, e) st = os.lstat(fullpath) if stat.S_ISDIR(st.st_mode): # ディレクトリに対する処理 elif stat.S_ISREG(st.st_mode) # ファイルに対する処理 .....
  • 15. それでも残る 性能劣化要因
  • 16. 要因 (1) ~ os.lstat() 呼び出しコスト O os.listdir() は 内部的に readdir(3) を使用 O readdir(3) が返す struct dirent は 要素種別情報 d_type を保持 O 種別情報のみで事足りる場合 os.lstat() 呼び出し自体が不要な筈 (サイズや日時情報が必要ない場合等)
  • 17. 要因 (2) ~ ファイル名解決コスト O OS内部でのファイル名解決 (ファイル名⇒対象の管理情報)は パス要素毎の繰り返し処理で実現 O os.lstat() に指定されるファイル名にも 同様の解決コストが必要
  • 18. “foo/bar/baz/file” に対する OS内部でのファイル名解決例 1. 2. 3. 4. 5. “.” への “foo” の問い合わせ “./foo" 相当の管理情報の取得 “./foo” への “bar” の問い合わせ “./foo/bar” 相当の管理情報の取得 “./foo/bar” への .......
  • 19. ファイル名解決における 直接的なコスト O ディレクトリ階層の深さ ⇒ 繰り返しによるコストの高低 O 配下要素の多寡 ⇒ 要素有無の確認コストの高低 O OS/ファイルシステム毎に色々な性能改善策 (名前解決キャッシュ/木構造管理/ハッシュテー ブル) O 運用回避 e.g.ディレクトリ配下の要素数に上限を設ける (proxyサーバやブラウザのキャッシュ)
  • 20. ファイル名解決における 間接的なコスト O 階層/配下要素の増加による I/O 量の増加 O メモリアクセスと比べて、 圧倒的にコストが高い O I/O 対象の散在によるシークコストの増加 O 記録媒体が HDD であれば、 ミリ秒単位の I/O 待ち状態 O GHz クラスの CPU なら、 単純計算でも百万命令単位分の I/O 待ち
  • 21. 性能劣化の低減策
  • 22. 低減策 (1) ~ os.lstat() 呼び出しの低減 O readdir(3) が返す struct dirent には 各要素の種別情報を保持する d_type フィールドがある O 種別情報のみで事足りるなら lstat(2) 呼び出し自体が不要
  • 23. 低減策 (2) ~ ファイル名解決コストの低減 O fstatat(2) システムコールの利用 O SYNOPSYS int fstatat(int dfd, const char *path, struct stat *buf, int flag); O 起点ディレクトリ(dfd)からの相対的名前解決 O 直下の要素なら問い合わせは1階層限定 O I/O対象を局所化可能
  • 24. 低減策の効果計測
  • 25. 基本条件 O 1.8GHz 4 core Atom 環境 O I/O 要因での性能劣化を極力防止 O メモリファイルシステム上でテスト O 常に現ディレクトリからの相対アクセス O 必要なファイル/ディレクトリ要素のみ
  • 26. lstat(2) 実行のコスト O 実行条件 O 1000 要素を保持するディレクトリ O 1000 要素それぞれへの lstat(2) 実施 O 計測結果 O 1000 回繰り返しで 3 ~ 4 秒の違い O lstat(2) 実行コストは 1回あたり 3 usec ~ 4 usec
  • 27. ファイル名解決のコスト O 実行条件 O 現ディレクトリから 10 階層隔てる O 1000 要素を保持するディレクトリ O 1000 要素それぞれへの lstat(2) または fstatat(2) 実施 O 計測結果 O 1000 回繰り返し時に 6 ~ 7 秒の違い O lstat(2) と fstatat(2) のコスト差は 1階層あたり 0.6 usec ~ 0.7 usec
  • 28. 性能計測の評価 O 対象10,000超で体感的な差が出る可能性 O システムコールのコスト差だけでも 対象1,000,000なら数秒オーダーの差 O 実際の環境では、性能劣化要因が増える O ディレクトリ階層が複雑化した場合 ファイル名解決コストの増加 O HDD上のファイルシステムの場合 シーク発生による I/O待ちの増加
  • 29. 低減策の問題点
  • 30. 環境毎の仕様準拠 O dirent.d_type による種別情報の提供は POSIX 標準ではオプション扱い O GNU coreutils の ls でも 使用可能な環境では使用 O fstatat(2) の標準化は XPG7 (2013) から O XPG7 非準拠なら、サポートの必要無し (とは言うものの多くの環境で利用可能) O GNU coreutils の ls では未使用
  • 31. Python からの利用可能性 O Python の標準 API からは dirent.d_type も fstatat(2) も使えない
  • 32. Python から使えないなら そんな話するな!
  • 33. そんな時の為の C ライブラリ連携!
  • 34. Mercurial における listdir() の独自実装
  • 35. まーきゅりあるノ話ヲ シタイダケデハ ナイデスヨ?(棒)
  • 36. O ディレクトリ配下要素の 情報取得を行う機能 osutil.listdir() を MercurialではCライブラリとして独自実装 O システムコール実行コストを 環境に応じて極力低減 O DT_REG マクロ判定 (dirent.d_type 利用の可否) O AT_SYMLINK_NOFOLLOW マクロ判定 (fstatat(2) 利用の可否) O Cライブラリ連携を使用できない環境向けに pure Python 版 osutil もあるが 性能的には当然Cライブラリ実装よりも遅い
  • 37. 結論
  • 38. ls.c は読まなくても…. O mercurial/osutil.c の listdir() 実装は 読んでおいた方が良いかもね! O ディレクトリ要素や要素毎情報の取得で 使用している API を把握しよう O API 使い分けによる 性能への影響を理解しよう O POSIX環境向けと Windows環境向け実装が 同一ファイル中にあるので参照時は注意
  • 39. Pythonista も…. O 「lsを読まずにプログラマを名乗るな!」を 買ってね! O OS の内部処理とかファイルシステム周りの 話も盛り込んであるよ!
  • 40. 参考資料
  • 41. Mercurial O プロジェクトページ http://mercurial.selenic.com/ O mercurial/osutil.c http://selenic.com/repo/hg/file/stable/mercurial/osutil.c O mercurial/pure/osutil.py http://selenic.com/repo/hg/file/stable/mercurial/pure/osutil.py
  • 42. POSIX仕様 O XPG6: IEEE Std 1003.1, 2004 Edition http://pubs.opengroup.org/onlinepubs/9699919799/ O XPG7: IEEE Std 1003.1, 2013 Edition http://pubs.opengroup.org/onlinepubs/009695399/
  • 43. GNU coreutils O プロジェクトページ http://www.gnu.org/software/coreutils/ O src/ls.c http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c
  • 44. 「lsを読まずに プログラマを名乗るな!」 O 書籍情報 http://www.shuwasystem.co.jp/products/7980html/3943.html O サポートページ http://www.lares.dti.ne.jp/~foozy/fujiguruma/ls-src/index.html
  • 45. おしまい