Mac関連ネタを凄い勢いで翻訳するスレ・4

このエントリーをはてなブックマークに追加
226名称未設定
Making An Operating System Faster
http://www.kernelthread.com/mac/apme/optimizations/

は?
227偽の神:04/06/10 01:48 ID:be/WZY8z
>>226
我ながら非常に怪しい訳なので注意
へぼの私には手に余る文書だったよorz


○ オペレーティングシステムを速くする
AppeがMacOS Xを速くするために行った10の方法

ハードウェアもソフトウェアも性能が時間とともに上がっていくが。ソフトウェアの性能上昇率は
ハードウェアに比べるとかなり低い。実際、多くの人は
「時間とともにのろくなっていくソフトウェアだらけだ」と思っているだろう。
そのうえ、OSのように複雑なソフトウェアのパフォーマンスを客観的に計るのは難しい。
OSが速い、遅いというのは各人の印象次第だからだ。

OSのアーキテクチャは、一般的なハードウェアよりはるかに寿命が長い。
ハードウェアがどんどん性能upするのと違い、OS研究者がより速いアルゴリズムをどんどん思いつくなんてことはない。
にもかかわらず、OSの開発に携わる人たち ---研究担当、設計担当、実装担当、そしてマーケット担当--- は
パフォーマンスを上昇させ続けるという困難な仕事を課せられている。
OS市場(市場といっても一人勝ち状態だが)において、これを実現させられる所は多くない。
厳しいOS市場で、OSベンダーは自社OSを改良しつづけねばならない。
228偽の神:04/06/10 01:50 ID:be/WZY8z
今のところ、世界を揺るがす革新的アルゴリズムが出てくるような気配はない。
じゃあどうすればOSを速くできるか?
解決策はいくつか考えられる:
・普遍的な最適化手法を学者よろしく探求するよりも、ひとつの(もしくは少数の)一般的な使用状況下で
システムを速く動作させる。
・小規模でありきたり、たいした技術でもなく実装はゴチャゴチャ、そんな手段はいくつも考えられる。
だがこういった改善は、ユーザーから見て目立つ部分のパフォーマンスを向上させられる。
・OSの基本処理単位の改善はパフォーマンスの改良につながる。
例えば、OSでよく使われるアルゴリズムを改善すると、それを使うプロセス、例えばシステム起動が改善されたりする。
・結局、ユーザーにとって目立つ部分が最も重要である。
「作業がより速く進むこと」 が 「パフォーマンスがいい」 とみなされる。
その作業に関わるコンポーネントやら実装やら設計やらを一から作り直さなくても速度を高めることは可能だ。
ユーザーがシステムをどう使うかは既に判っているので、動作がすばやくなったとユーザーに思わせるように
タスクの実行順を変更することができる。(実行順が不自然かつ不明瞭だとしても。)

MacOS X
AppleがMacOS Xのパフォーマンスを上げるために使った10の手法を見てみよう。
いくつかはシンプルな名案だ。開発者に取ってハイパフォーマンスなアプリを作るためのガイド
またはツールとなりえるものもある。これには特定の部分でパフォーマンスをひねり出す試みも含まれる。
以下、順不同で最適化の例を挙げる。
229偽の神:04/06/10 01:51 ID:be/WZY8z
1. BootCache
MacOS Xは起動時における起動ディスクの読み出しパターンをモニターし、
そのパターンをplaylist --キャッシュをまとめあげるために使われる-- に分類保存する。
こうしてできたBootCacheが起動ディスクの代わりに読み出し要求に応える。
また、キャッシュのヒット率を計ると同時に読み出しパターンをhistory listに保存する。
ヒット率が低すぎる場合はキャッシュが破棄される。
読み出しパターンは /var/db/BootCache.playlist に保存される。これがロードされると
キャッシュが有効になる。この一連の動作はユーザーからは見えないようになっている。
この機構は起動ボリュームのみをサポートし、128MB以上の物理メモリが動作条件になっている。
/System/Library/Extensions/BootCache.kext がBootCache機構を実装したカーネル機能拡張で、
kext内の Contents/Resources/BootCacheControl がユーザー用の実行バイナリで、playlistのロードなどを行う。

#BootCacheの効果はどのぐらいか?
以前、10.3.xのアップデートでBootCacheControlへの参照が壊れたことがあった。
BootCacheControlは(セーフブートでなければ) /etc/rc スクリプトで開始される。
/etc/rc スクリプトは BootCache.kext内のresourcesフォルダと/usr/sbin でBootCacheControlを探し、
前者(後者にはもともと存在しない)でそれを発見する。
しかし別のプログラム(loginwindow.app)は直接 /usr/sbin/BootCacheControl を探しエラーになるため
BootCacheが有効にならなかったのだ。
そこで /usr/sbin にBootCacheControlのシンボリックリンクを作ると起動が速くなった。
私のMacでは135秒→60秒に短縮された。
230偽の神:04/06/10 01:53 ID:be/WZY8z
2. カーネル機能拡張のキャッシュ
MacOS Xでは100近いカーネル機能拡張がロードされる。システムの Extensionsフォルダには
その倍近い数のカーネル機能拡張がある。システム起動毎にすべての機能拡張をスキャンして逐一ロードするのは
手間なので、MacOS Xは機能拡張とカーネル自身をキャッシュする。

各キャッシュの説明:
・カーネルキャッシュはカーネル本体と、リンクされたカーネル機能拡張、カーネル機能拡張の番号情報を含んでいる。
これは /System/Library/Caches/com.apple.kernelcaches に保存される。
キャッシュファイルは kernelcache.XXXXXXXX のような名前を持つ。この xxx は adler-32チェックサム
(gzipに使われているのと同じ)である。
・mkextキャッシュは複数のカーネル機能拡張とそれらの情報を含んでおり、起動を高速化させる。
BootXは最初にキャッシュされたデバイスドライバ一覧のロードを試みる。
(/usr/sbin/kextcache がキャッシュの生成、更新を行う)
もしmkextキャッシュが壊れている/見つからない場合、BootXは /System/Library/Extensions で
必要な機能拡張(機能拡張が内包する Info.plist にてOSBundleRequiredの記述があるもの)を探す。
mkextキャッシュは/System/Library/Extensions.mkextとして保存される。
/usr/sbin/mkextunpackを使えばmkextキャッシュの中身を展開できる。
・kextリポジトリキャッシュはすべての機能拡張とプラグインの情報を含んでいる。
/System/Library/Extensions.kextcacheとして保存される。これはgzip圧縮された巨大なXMLプロパティリストである
231偽の神:04/06/10 01:54 ID:be/WZY8z
3.ホットファイルクラスタリング
ホットファイルクラスタリング(HFC)はHFSボリューム上において、サイズが小さくかつ頻繁にアクセスされるファイルの
パフォーマンス向上を狙ったものだ。
この仕組みは起動ボリュームのみに適用される。
HFCは頻繁にアクセスされる「ホットな」ファイル(ジャーナリングファイルや、最適な位置に配置済みのファイルは除かれる)
を記録した集合配列であり、ボリュームの「ホットスペース」へ移動され断片化も解消される。
(ボリュームの先頭にあるメタデータ領域の終点から、ボリュームサイズの0.5%分がホットスペースとして使われる)
この集合配列のホットファイルは、DISABLED、IDLE、 BUSY、RECORDING、 EVALUATION、 EVICTION、ADOPTION
といったステージに分類される。
最大で5000項目、10MB以下のファイルが対象になる。
※メタデータ領域とは、HFS+がボリュームのメタデータ:アロケーションファイル(ビットマップ)、
エクステントオーバーフローファイル、ジャーナルファイル、カタログファイル、クォータファイル、
そしてホットファイルを格納する領域である。
10.3ではメタデータ領域がボリュームの先頭付近、ボリュームヘッダの直後に配置される。

#HFCは、ジャーナリングを有効にした10GB以上のボリュームでのみ有効になる。

どのファイルがホットファイルになっているかは人によって異なるだろう。
もしC言語のプログラミングを数日ぶっ通しでやったなら、多くのCヘッダがホットファイルになるだろう。
hfsdebug を使えばHFCの動作を追跡できる。
232偽の神:04/06/10 01:55 ID:be/WZY8z
4.Working Set Detection
Machカーネルは物理メモリを仮想メモリのキャッシュとして使用する。ページフォールト
(訳者註:必要なページが物理メモリにないというエラー。ページとは仮想メモリでの退避/読み戻し単位で、1ページは4KB)
が生じてページが物理メモリに読み戻されると、代わりとして現在物理メモリ内にあるページのうち
ディスクに退避させるものを選ばなければならない。
アプリケーションがすぐに必要とするページは引き続き物理メモリに保持した方が良い。

アプリケーションがいつどのページを要求するか事前にわかるような夢のOSはもちろん存在しない。
が、理想に近いものを実現するアルゴリズムはいくつかあり、ひとつはプロセスの局所性を利用するものだ。
局所性の原理とは、「あるプロセスはページ全体のうち、あまり変化しない特定のページを頻繁に読み出す」というものだ。
これらのページはWorking Setと呼ばれる。
研究によると、このWorking Setがメモリ内にまとまってかつ順序よく配置されていないと満足なパフォーマンスが得られない
(もちろん、ページフォールトは抑えなければならない)。

MacOS XのカーネルにはWorking Setを探し出し保守するためのサブシステム(これをTask Working Set、TWSと呼ぼう)
が組み込まれている。このサブシステムはカーネルの仮想メモリ機構に統合されている。
TWSは各タスクのページフォールト状況をプロファイルとして記録する。
このプロファイルはユーザー毎に作られ、/var/vm/app_profile/ に保存される。
プロファイルは物理メモリに優先的に保持すべきページを決めるのに使われる。
233偽の神:04/06/10 01:56 ID:be/WZY8z
他にもこんな利点がある:
・(すぐ必要になると予想される)複数のページ読み戻しを一度に行える。
・過去にTWSが探し出しディスクに保存したWorking Setを、現在のWorking Set作成の参考にできる。
・ページフォールト記録が示すディスク上のページはまず移動されていない(後述するが、HFS+上のファイルはあまり断片化しない)。
だからWorking Setをディスクからすばやく探し出せる。

#プロファイルは2つのページキャッシュとして/var/vm/app_profile/に保存される:
#U_names と #U_date (#UはユーザIDの16進法表記)。
#U_names ファイルは、プロファイル要素を保持する構造体を含んだシンプルなデータベースファイルである。
234偽の神:04/06/10 01:58 ID:be/WZY8z
5. オンザフライデフラグ
HFS+でファイルが開かれた時、以下のチェックが入る:
・ファイルサイズが20MB以下
・ファイル状態がBUSYになっていない
・ファイルが読み出し専用でない
・ファイルが8個以上のエクステントを持っている
(訳者註:エクステントとはファイルの断片のこと。つまりファイルが8個以上に断片化している時)
・システム起動/復帰から3分が経過
以上の条件をすべて満たしていると、その場でファイルの断片化が解消される。

ファイルの再配置(訳者註:SpeedDiskのようにファイルを種類別にかためて再配置すること?)は、
HFS+におけるエクステントベースのファイル書き込み処理、また非同期な書き込み処理によって自然に促進される。
より詳しい説明はFragmentation In HFS Plus Volumesにて。
(訳者註:HFS+ではディスクに書き込むべきファイルを一旦メモリに保持し、一定時間毎に一気にディスクに書き込む。
ファイル書き込み命令の数に比べて実際の書き込み動作が少ない、関連性のファイルが短時間で頻繁に書き込まれるのは
よくあること、といった点からこのような結論になっている?)
235偽の神:04/06/10 01:59 ID:be/WZY8z
6.プレバインディング
Mach-Oアプリケーション起動時のランタイムリンクを短縮して起動を高速化するための仕組み。

ダイナミックリンカは、アプリケーション起動時に"アプリケーションの未定義シンボル"と
"ダイナミックライブラリのシンボル"との対応付けを行う。
これはアドレス空間を確保したり、定義済みシンボルのアドレスを参照したりといった動作の内のひとつだ。
もしダイナミックライブラリがプレバインディング有効でコンパイルされていると、アドレス範囲があらかじめ定義される。
ダイナミックリンカはライブラリのシンボルを参照するのに定義済みのアドレスを使えるようになる。
この動作では、アドレスがだぶった時に特定ライブラリのアドレス指定を優先させることはできない。
Appleは「reserved(予約済み)」や「preferred(優先)」といったアドレス範囲を自身のソフトウェア用に確保しており、
サードパーティのライブラリがプレバインディングをサポートするためのアドレス範囲を別途指定している。
(訳者の怪しい註:未定義シンボル = アドレスが判らないAPI。定義済みシンボル = アドレスが判っているAPI。
ダイナミックライブラリのシンボル = ダイナミックライブラリがサポートするAPI。
ダイナミックリンカ = ダイナミックライブラリのAPIとアプリが定義しているシンボル(API)とを結びつける。
アプリが定義しているAPIを呼び出し可能にするべく、ダイナミックリンカがダイナミックライブラリのAPIを探して
アドレス空間にロードし、そのアドレスをアプリに伝える。アドレスが判ればそのAPIは定義済みとなる。)
236偽の神:04/06/10 01:59 ID:be/WZY8z
update_prebinding は、新しいファイルがシステムに追加されたときにプレバインディング情報を更新する。
たった1個ファイルを変更してもかなりの時間がかかる。なぜならその新ファイルに対応付けされる
すべてのライブラリや実行バイナリを見つけなければならないからだ。
(パッケージ情報はこれを助けるのに使われ、その依存情報を基にビルドするとより最適化が進む)
そしてredo_prebindingはファイルを適切にプレバインドする。

#システムのアップデートやソフトのインストール時に行われる最適化処理の正体は、このプレバインディングである。

usr/bin/otool を使えば、ライブラリがプレバインドされているかどうかが判る。
237偽の神:04/06/10 02:00 ID:be/WZY8z
7.開発支援
MacOS Xは「コード記述→コンパイル→デバッグ→コード記述...」の開発サイクルをすばやくするための工夫が盛り込まれている。
10.3に盛り込まれたその工夫を見てみよう。
・プリコンパイルされたヘッダ:Xcodeはプリコンパイルヘッダをサポートしている。
プレフィックスヘッダをプリコンパイルするのに使われる。
・分散ビルド:Xcodeは分散ビルドをサポートしており、ネットワーク接続された複数のマシンを使ってビルドできる。
・ゼロリンク:開発中に役に立つビルド方法。
アプリケーション起動時に初めてオブジェクトファイルがリンクされる方式にすることで、コンパイル時のリンク行程をパスし
ビルド時間を短縮する。
「修正して続ける」を使うと、デバッガ実行中にコード変更→再ビルド→デバッガ再開がその場で行える。
238偽の神:04/06/10 02:00 ID:be/WZY8z
8.より速いアプリケーションを作るための支援ツール
Appleはさまざまなパフォーマンス測定/デバッグツールを提供している。
MacOS Xに組み込まれているものもあるし、Developer Toolsをインストールすれば多くのツールを使うことができる。
Appleは自社の開発者やサードパーティがパフォーマンスガイドラインに沿ったコードを書くよう強く促している。

最初に言った通り、目に見えてわかるパフォーマンスというのは非常に重要だ。
例えば、メニューバーを表示してユーザーの入力に応答するまでの時間はできるだけ短くするのが望ましい。
こういう初期化処理を短縮するには、メインの初期化を後回しにしたりイベント順序を変えたりする工夫が必要になる。

MacOS X Tools
gpro、lsof、nm、top、vm_statといったGNU/Unixツールが組み込み済みで、さらに以下のようなツールもある:
・fs_usageは、ファイルシステム関連のシステムコールとページフォールトを抽出し表示する。
・heap は、プロセスのヒープ領域のうち確保されているメモリ領域を表示する。
・ktrace/kdump はカーネルプロセスを追跡できる。
・leaks は参照されていないのに確保されつづけているメモリ領域を探し出す。
・malloc_history はプロセスのメモリ確保履歴を表示する。
・otool はオブジェクトファイルの特定の部分を表示する。
・pagestuff はMach-Oバイナリの特定のページ情報を表示する
・sample は一定時間毎のプロセスの動作を追跡する。
・sc_usage はシステムコールを抽出し表示する。
・vmmap はプロセスが確保している仮想メモリのリージョンを表示する。
239偽の神:04/06/10 02:01 ID:be/WZY8z
パフォーマンス測定ツール
・MallocDebug は確保されたメモリを追跡し解析する。
・ObjectAlloc はObjective-Cやコアサービスのメモリ確保と解放を追跡する。
・OpenGL Profiler はOpneGLアプリケーションの各種情報を抽出する。
・PEFViewer はPEFバイナリの内容を見る。
(訳者註:PEFバイナリとはCarbon(CFM)やClassicバイナリのこと)
・QuartzDebug はアプリケーションの画面描画の様子をフラッシュ表示する。
・Sampler は前述SamplerのGUI版。
・Spin Control はレインボーカーソルが出現したときのアプリケーションの状態を調べる。
・Thread Viewer は各スレッドの活動状況を表示する。

CHUD Tools
CHUD Tools は以下のツールで構成されている:
・BigTop はtopやvm_statなどを統計表示する。
・CacheBasher はCPUのキャッシュパフォーマンスを測定する。
・MONster はハードウェアレベルのパフォーマンスデータを表示する。
・PMC Index はPerformance Monitoring Counterイベントを探し出す。
・Reggie SE はCPUやPCIバスのレジスタを表示/変更できる。
・Saturn はアプリケーションのCPUファンクションコールの統計を取る。
・Shark はシステム全体を監視して特定プログラムの動作統計を取る。
プログラムがどの処理で時間を食っているか知ることができる。
・Skidmarks GT はCPUのベンチマークを取る。(整数演算、浮動小数点演算、ベクトル演算)
・SpindownHD は各ディスクのスリープ/アクティブ状況を表示する。
・acid はamberが生成した追跡記録を解析する。(TT6Eフォーマットのみ)
・amber はプロセスの全スレッドを追跡し、発行された命令とデータアクセスを記録する。
・simg4 G4の動作サイクルシミュレータ 。
・simg5 G5の動作サイクルシミュレータ 。
240偽の神:04/06/10 02:01 ID:be/WZY8z
9.HFS+のジャーナリング
モダンなファイルシステムではジャーナリングは珍しいものではなく、HFS+のジャーナリング化はむしろ遅い方だ。
Appleは既存のHFS+にジャーナリングを追加し、10.3ではじめてジャーナリングがデフォルトで開始されるようになった。
ジャーナリング機構はファイルのメタデータとボリューム構造の変化を記録するが、データそのものは記録しない。
ジャーナリングの本来の目的は、ボリュームが正しくマウントされないときなどに
より速く確実にファイルシステムを修正することだが、メタデータアクセスのパフォーマンスは上がると思われる。


10.インスタントオン
Macはいわゆるハイバネーション(冬眠状態)にならない。
スリープしたときに必要なデバイス(特に物理メモリ)は作動したままになる。
バッテリ駆動しているときはその分駆動時間が縮む。
結果、Macは一瞬でスリープから復帰できる。
241偽の神:04/06/10 02:02 ID:be/WZY8z
最後に
MacOS Xを例に取って、OS屋が使う(特にエンドユーザーにとっての)パフォーマンス向上テクニックを紹介した。
このような最適化の積み重ねは普遍的な最適化よりも有効だと思われる。
目標は「目に見えるパフォーマンスの向上」だ。
こういう改善により、エンドユーザーはより速く作業が進むようになったと感じるのだ。


#もちろん、このような最適化はMacOS Xに限った話ではない。MicrosoftもWindowsで似たような最適化を行っている。
特にBootCacheやHFC、Working SetについてはWindowsでも同等のテクニックが使われている。