Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
Pythonista も
ls を読むべきか?
藤原 克則 @flyingfoozy
自己紹介
O 藤原 克則

(FUJIWARA Katsunori)
O ホームページ
http://www.lares.dti.ne.jp/~foozy/index.ja.html

O ブログ
http://d.hatena.ne.jp/flying...
O 分散リポジトリ型履歴管理ツール

Mercurial の翻訳コミッタ/コントリビュータ
O Mercurial の hack に特化した
なんちゃって Pythonista
O Solaris 上で稼働させる

HPC 向けファイルシステムの実装などを
仕事でやっていたことも
O 「Tokyo OpenSolaris 勉強会」 で
Solarisカーネルの実装に関する勉強とか
http://www.opensola...
執筆過程で見つけた
バグの修正パッチが
ソースツリーに取り込まれた
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):
# ディレクトリに対する処理...
そんな実装では
スケールしない!!!
システムコール
呼び出しコスト
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 st...
それでも残る
性能劣化要因
要因 (1) ~
os.lstat() 呼び出しコスト
O os.listdir() は

内部的に readdir(3) を使用
O readdir(3) が返す struct dirent は
要素種別情報 d_type を保持
O 種別情...
要因 (2) ~
ファイル名解決コスト
O OS内部でのファイル名解決

(ファイル名⇒対象の管理情報)は
パス要素毎の繰り返し処理で実現
O os.lstat() に指定されるファイル名にも
同様の解決コストが必要
“foo/bar/baz/file” に対する
OS内部でのファイル名解決例
1.
2.
3.
4.
5.

“.” への “foo” の問い合わせ
“./foo" 相当の管理情報の取得
“./foo” への “bar” の問い合わせ
“./f...
ファイル名解決における
直接的なコスト
O ディレクトリ階層の深さ

⇒ 繰り返しによるコストの高低
O 配下要素の多寡
⇒ 要素有無の確認コストの高低
O OS/ファイルシステム毎に色々な性能改善策

(名前解決キャッシュ/木構造管理/ハッシ...
ファイル名解決における
間接的なコスト
O 階層/配下要素の増加による I/O 量の増加
O メモリアクセスと比べて、

圧倒的にコストが高い
O I/O 対象の散在によるシークコストの増加
O 記録媒体が HDD であれば、

ミリ秒単位の ...
性能劣化の低減策
低減策 (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 fl...
低減策の効果計測
基本条件
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) 実行コストは...
ファイル名解決のコスト
O 実行条件
O 現ディレクトリから 10 階層隔てる
O 1000 要素を保持するディレクトリ
O 1000 要素それぞれへの

lstat(2) または fstatat(2) 実施
O 計測結果
O 1000 回繰り...
性能計測の評価
O 対象10,000超で体感的な差が出る可能性
O システムコールのコスト差だけでも

対象1,000,000なら数秒オーダーの差
O 実際の環境では、性能劣化要因が増える
O ディレクトリ階層が複雑化した場合

ファイル名解決...
低減策の問題点
環境毎の仕様準拠
O dirent.d_type による種別情報の提供は

POSIX 標準ではオプション扱い
O GNU coreutils の ls でも

使用可能な環境では使用
O fstatat(2) の標準化は XPG7 (2013...
Python からの利用可能性
O Python の標準 API からは

dirent.d_type も fstatat(2) も使えない
Python から使えないなら
そんな話するな!
そんな時の為の
C ライブラリ連携!
Mercurial における
listdir() の独自実装
まーきゅりあるノ話ヲ
シタイダケデハ
ナイデスヨ?(棒)
O ディレクトリ配下要素の

情報取得を行う機能 osutil.listdir() を
MercurialではCライブラリとして独自実装
O システムコール実行コストを
環境に応じて極力低減
O DT_REG マクロ判定

(dirent.d_...
結論
ls.c は読まなくても….
O mercurial/osutil.c の listdir() 実装は

読んでおいた方が良いかもね!
O ディレクトリ要素や要素毎情報の取得で
使用している API を把握しよう
O API 使い分けによる
性...
Pythonista も….
O 「lsを読まずにプログラマを名乗るな!」を

買ってね!
O OS の内部処理とかファイルシステム周りの
話も盛り込んであるよ!
参考資料
Mercurial
O プロジェクトページ
http://mercurial.selenic.com/

O mercurial/osutil.c
http://selenic.com/repo/hg/file/stable/mercurial...
POSIX仕様
O XPG6: IEEE Std 1003.1, 2004 Edition
http://pubs.opengroup.org/onlinepubs/9699919799/

O XPG7: IEEE Std 1003.1, 2...
GNU coreutils
O プロジェクトページ
http://www.gnu.org/software/coreutils/

O src/ls.c
http://git.savannah.gnu.org/cgit/coreutils.gi...
「lsを読まずに
プログラマを名乗るな!」
O 書籍情報
http://www.shuwasystem.co.jp/products/7980html/3943.html

O サポートページ
http://www.lares.dti.ne.j...
おしまい
Pythonista も ls を読むべきか?
Pythonista も ls を読むべきか?
Nächste SlideShare
Wird geladen in …5
×

Pythonista も ls を読むべきか?

6.180 Aufrufe

Veröffentlicht am

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

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Pythonista も ls を読むべきか?

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

×