• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Pythonista も ls を読むべきか?
 

Pythonista も ls を読むべきか?

on

  • 4,344 views

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

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

Statistics

Views

Total Views
4,344
Views on SlideShare
3,891
Embed Views
453

Actions

Likes
15
Downloads
18
Comments
0

5 Embeds 453

http://d.hatena.ne.jp 397
https://twitter.com 48
http://s.deeeki.com 4
http://news.google.com 3
http://akimacho.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Pythonista も ls を読むべきか? Pythonista も ls を読むべきか? Presentation Transcript

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