コンパイル済みプログラムを実行する

実行可能なプログラムを作るとき、GHCシステムはコードをコンパイルし、それを自明でないランタイムシステム(RTS)とリンクする。これは、記憶領域の管理、スレッドのスケジュール、プロファイルの取得などを行う。

RTSは、振る舞いを制御するための沢山のオプションを持っている。例えば、コンテキストスイッチの間隔やヒープのデフォルトの大きさを変えたり、ヒーププロファイルを有効にしたりである。こうしたオプションは色々な方法でランタイムシステムに渡すことができる。次の節(4.16.1. RTSオプションを設定する)ではこれらの方法を記述し、それ以降の節ではRTSオプション自体について記述する。

RTSオプションを設定する

RTSオプションを設定するのには四つの方法がある。

コマンド行でRTSオプションを設定する

リンク時に-rtsoptsフラグを適切に設定していたなら、プログラムを実行するときにRTSオプションをコマンド行で与えることができる。

Haskellプログラムの実行が開始されるとき、RTSはコマンド行引数から+RTS-RTSで囲まれた部分を自分用に抽出する。以下のような例を考える。

$ ghc prog.hs -rtsopts
[1 of 1] Compiling Main             ( prog.hs, prog.o )
Linking prog ...
$ ./prog -f +RTS -H32m -S -RTS -h foo bar
    

RTSは-H32m -Sを横取りし、プログラムがSystem.Environment.getArgsを読んだときには残りの引数である-f -h foo barが渡される。

次の例のように、ランタイムシステムへのオプションがコマンド行の最後まで続くときは、-RTSオプションは必要ない。

% hls -ltr /usr/etc +RTS -A5m
    

残りのオプションを問答無用で(RTSでなく)プログラムに渡したいなら、––RTSを使うことができる。

いつもと同様、sizeを取るRTSオプションについては、以下が適用される。sizeの最後の文字がKまたはkなら、数値は1000倍される。Mまたはmなら、1,000,000倍される。GまたはGなら、1,000,000,000倍される。(カウンタのオーバーフローはあなたの責任である)

+RTS -?オプションを与えれば、実際に利用可能なRTSオプションを表示することができる。(これはどのようにコンパイルされたかによって異なる)

注意: GHCはそれ自身GHCでコンパイルされているので、通常の+RTS ... -RTSの組み合わせを使ってRTSオプションを変更することができる。例えば、コンパイル時の最大ヒープサイズを128Mに増やすには、+RTS -M128m -RTSをコマンド行に加えれば良い。

コンパイル時にRTSオプションを設定する

-with-rtsoptsフラグ(4.11.6. リンクに影響するオプション)を使うことで、プログラムのRTSオプションをコンパイル時に設定することができる。例として、-H128m -K64mを設定するには、-with-rtsopts="-H128m -K64m"付きでリンクすればよい。

RTSOPTSでRTSオプションを設定する

リンク時に-rtsoptsフラグがnone以外に設定されているなら、RTSオプションは環境変数GHCRTSからも採られる。例えば、GHCでコンパイルされた全てのプログラムについて最大ヒープサイズを2Gにするなら、次のようにすれば良い。(sh系のシェルを使っていると仮定する)

     GHCRTS='-M2G'
     export GHCRTS
  

GHCRTS環境変数から採られたRTSオプションはコマンド行からオプションを与えることで上書きできる。

ヒント: あなたの環境にGHCRTS=-M2Gのようなものを設定しておくと、Haskellプログラムがあなたのマシンの実メモリを超えて成長することを簡単に防ぐことができる。誤ってこういうことをするのは良くあることであり、OSがそのプロセスを殺すことを決めるまでマシンがゆっくりと地を這うことになる。(そして、ちゃんと正しいのを殺してくれるといいね)

RTSの振る舞いを変更するためのフック

GHCでは、ランタイムシステムから呼ばれるフックをコンパイル時に含めることで、任意のプログラムのRTS設定をある程度制御することができる。RTSにはこれら全てのフックのスタブ定義が含まれているが、自分の版を書いてGHCのコマンド行からリンクすることで、デフォルトと異なるものを使える。

DLLリンクの気まぐれのせいで、これらのフックはWindowsでプログラムが動的リンクでビルドされるときには働かない。

ghc_rts_optsというフックを使うと、特定のプログラムのRTSオプションを恒久的に設定することができる。これは新しい-with-rtsoptsというリンカオプションと同じである。よくある使いかたは、プログラムのヒープやスタックをデフォルトより大きくすることである。例えば、-H128m -K1mを設定するには、まず以下の定義をCソースファイルに置く。

  char *ghc_rts_opts = "-H128m -K1m";
  

このCファイルをコンパイルし、できたオブジェクトファイルを、Haskellプログラムをリンクするときのコマンド行に加えれば良い。

これらのフラグは、GHCRTS環境変数やコマンド行のフラグよりも先に解釈される。

ランタイムシステムがどうしようもなくなったとき(例えばスタックオーバーフロー)に表示される文言を変更することもできる。このためのフックは以下である。

void OutOfHeapHook (unsigned long, unsigned long)

ヒープオーバーフローのメッセージ。

void StackOverflowHook (long int)

スタックオーバーフローのメッセージ。

void MallocFailHook (long int)

mallocが失敗したときに表示されるメッセージ。

これらのフックの使いかたの例としては、GHCソースツリーのghc/compiler/parser/hschooks.cにあるGHC自身のものを見よ。

いろいろなRTSオプション

-Vsecs

RTSの時計が進行する時間間隔を設定する。ランタイムは単一のタイマシグナルを使って時計を進行させる。コンテクストスイッチのタイマ(4.13. Concurrent Haskellを使う)およびヒーププロファイル時のタイマ(5.4.1. ヒーププロファイルのためのRTSオプション)を制御するのにはこれが使われる。また、時間プロファイルをとるときは、プロファイルの標本を記録するのにRTSのタイマシグナルを直接使うことになる。

通常、-Vオプションを直接指定する必要はない。-C-iオプションで短い間隔が指定されたときは、自動的にRTSタイマの分解能も調整されるからである。しかし、時間プロファイルの分解能を増したいときには、-Vを設定することが必要になる。

値0を使うと、RTSの時計は完全に無効にされ、それに依存したタイマも無効になる。コンテクストスイッチのタイマとプロファイルタイマである。それでもコンテクストスイッチは発生するが、決定論的に、かつ通常よりずっと高い頻度で発生するようになる。インターバルタイマを無効にすると、実行時の非決定性の源が一つ除かれるわけであり、デバッグに便利である。

--install-signal-handlers=yes|no

yes(デフォルト)なら、RTSはctrl-Cの類を捕捉するためのシグナルハンドラを設置する。このオプションは、HaskellコードをDLLとして使っていて、自分でシグナルハンドラを設定したいときに特に有用である。

--install-signal-handlers=noの場合でも、RTSの時間間隔タイマは変わらずに有効だということに注意。タイマシグナルはSIGVTALRMかSIGALRMで、RTSの設定とOSの能力によって異なる。このタイマシグナルを無効化するにはRTSオプション-V0を使う。(上記参照)

-xmaddress

警告: このオプションはメモリ確保の問題を回避するためだけのものである。GHCiが「failed to mmap() memory below 2Gb」のようなメッセージを表示して失敗するのでない限り、使ってはいけない。あなたの機械でGHCiを動かすのにこのオプションを使う必要があるなら、バグとして報告してほしい。

64ビットの機械では、RTSはアドレス空間の下方2Gbの中にメモリを確保する必要がある。種々のOSにおけるこれの対応は不完全であり、ときどき失敗する。このオプションは、アドレス空間の下方2Gbの中でどこのメモリを確保できるかについてRTSにヒントを与えるために存在する。例えば、+RTS -xm20000000 -RTSとすれば、RTSが0.5Gb markから確保を開始すべきというヒントになる。デフォルトは、可能なら下方2Gb中にメモリを確保するためのOS組み込みの手段(例えばLinuxならMAP_32BIT付きのmmap)を使い、それがなければ-xm40000000である。

ガベッジコレクタを制御するためのRTSオプション

ガベッジコレクタの挙動を精密に制御するために、いくつかのオプションが存在する。通常時には、これらはどれも使う必要がない(といいのだが)。それでも、最高の性能を得たいときのために、いくつかの箇所を調整することができるようになっている。

-A size

[デフォルト: 512k]ガベッジコレクタが使う確保領域の大きさを設定する。確保領域(実際には世代0・段階0)は固定されており、大きさが変わることはない。(-Hを使った場合はこの限りでない。下記参照)

確保領域の大きさを増すことは、性能の向上につながるかもしれないし、そうでないかもしれない。(より大きい確保領域を使うと、キャッシュの振舞は悪化するが、ガベッジコレクションの回数は減り、昇格(promotion)も少なくなる)

世代数が一しかないとき(-G1)は、-Aオプションは最小の確保領域を指定する。これは、実際の確保領域の大きさがヒープ中のデータの量によって変動するからである。(下記の-Fを見よ)

-c

もっとも古い世代を回収するときにコンパクト化アルゴリズムを使う。デフォルトでは最古世代はコピーアルゴリズムで回収されるが、このオプションが使われると、その場でコンパクト化されるようになる。コンパクト化アルゴリズムはコピーアルゴリズムより遅いが、相当量のメモリを節約できることがある。

ヒープの大きさ(これは-Hオプションで変えられる)が一定のとき、コンパクト化を使うことでかえってGCのコストが削減できるということがあり得る(GCの回数が減らせるかもしれないので)。ヒープの大きさに対する生存データの比が高いとき(>30%、例えば)には特にその傾向が強い。

注意: 現在、コンパクト化は、-G1で単一世代が指定されているときには動作しない。

-c n

[デフォルト: 30] 生存データがヒープの大きさの上限(-Mオプションを見よ)のn%を超えたときに自動的にコンパクト化を有効にする。デフォルトではヒープの大きさに上限はないので、-Msizeでヒープの大きさの上限が指定されない限り、このオプションには効果がない。

-F factor

[デフォルト: 2] このオプションは、古い世代のために予約されるメモリの量(two-space GCのときは確保領域の大きさ)を、生存データの量との比で指定する。例えば、最後に最も古い世代が回収されたときに生存データが2Mあったとすると、デフォルトでは、4Mにまでなるのを待ってから再び回収する。

これについてはデフォルトがうまく働いているようである。潤沢なメモリがあるなら、通常、-Ffactorを増やすよりも-Hsizeを使った方が良い。

-Fの値は、ヒープの最大の大きさ(-Msizeで設定する)に近づいたときには、ガベッジコレクタによって自動的に減らされる。

-G generations

[デフォルト: 2] ガベッジコレクタが使う世代の数を設定する。デフォルトの2は良い選択のようだが、ガベッジコレクタは任意の数の世代をサポートしている。プログラムが長い時間に渡って実行されるのでない限り、4程度より大きな値はおそらく良くない。最古の世代が一回も回収されないということになるからである。

+RTS -G1で一世代を指定すると、当然、単純な2-spaceコレクタになる。2-spaceコレクタでは、-Aオプション(上記参照)が指定するのは確保領域の最小の大きさである。これは、ヒープ中の生存データの量が増えるに従って確保領域も拡大されるからである。複数世代のコレクタでは確保領域の大きさは固定である。(-Hオプションを使う場合はこの限りでない。下を見よ)

-qg[gen]

[GHC 6.12.1から] [デフォルト: 0] 世代genとそれより上の世代において、並列GCを使う。genを省略すると、並列GCは完全に無効になり、逐次GCに戻る。

デフォルトの並列GC設定は、通常、並列プログラム(parやStrategyや複数のスレッドを使うもの)に適している。しかし、単一スレッドの逐次的なプログラムに関しても、並列GCを有効にする恩恵があることがある。特に、プログラムが大量のヒープデータを持ち、実行時間のかなりの部分をGCが占めるような場合である。逐次的なプログラムにおいて並列GCを使うには、適切な-Nオプションを使って並列ランタイムを有効にすればよい。加えて、-qg1を使って並列GCを古い世代のみに制限すると良いかもしれない。

-qb[gen]

[GHC 6.12.1から] [デフォルト: 1] 並列GCにおいて、世代genとそれより上の世代で負荷分散を使う。genを省略すると、負荷分散を完全に無効にする。

負荷分散とは、GCの作業を空いているコア間で分配することである。これは、ヒープが大きく、GCの作業を並列化する必要がある場合には良いことである。しかし、並列プログラムの若い世代における短い回収では、これは最悪である。なぜなら、データをCPUのキャッシュから動かすことで、局所性を損うからである。(訳注: 理解できないのでだれか助けて 原文は because it can harm locality by moving data from the cache of the CPU where is it being used to the cache of another CPU.)。実際、並列プログラムでは、-qbで負荷分散を完全に無効にした方が良いこともある。

-H size

[デフォルト: 0] このオプションはガベッジコレクタに「推奨されるヒープの大きさ」を提示する。プログラムのメモリ使用量が増加し、性能を保つためにヒープの大きさを増す必要が発生するまでは、ガベッジコレクタは指定された大きさの程度のメモリを使う。

デフォルトでは、ヒープは小さい状態から開始し、必要に応じて伸長・収縮する。これは性能に悪影響を及ぼすので、メモリが潤沢にあるなら、-Hsizeに大きな値を指定すると良い。GCの性能を向上させるには、通常、-Asizeよりも-Hsizeを使った方が良い。

-I seconds

(デフォルト: 0.3) スレッド化された、またはSMP版のRTS(-threadedを見よ。4.11.6. リンクに影響するオプション)においては、ランタイムが一定期間待機状態である(Haskellの計算が実行されていない)とき、自動的に大GCが実行される。GCが実行されるまでの時間を指定するのが-Isecondsオプションである。-I0を指定すると待機状態でのGCが無効になる。

対話的アプリケーションでは、待機時GCが多くの場合有効である。これは、Haskellの計算が起こっていない待機状態の間に、終了子を走らせたりデッドロックしたスレッドを感知したりできるからである。さらに、アプリケーションが忙しいときにGCが起こる可能性が減るので、反応性が向上するかもしれない。しかし、ヒープ中の生存データの割合があまりに高いと、待機時GCが重大な遅れを引き起こすことがある。また、時間間隔が短すぎると、対話的な反応性に悪影響を及ぼすことになるかもしれない。

これは実験的な機能である。問題が起きたり、改善案があるなら、知らせてほしい。

-k size

[デフォルト: 1k] スレッドの初期スタックサイズを設定する。スレッドのスタック(主スレッドのスタックも含めて)はヒープ上にとられ、必要に応じて成長する。デフォルト値はたくさんの小さなスレッドを使う並行アプリケーションに適している。あなたのプログラムがこれに沿わないなら、このオプションを増加させると性能が向上するかもしれない。

通常、主スレッドはやや大きめのヒープで開始される。これは、プログラムが開始するときに起こる不必要なスタックの伸長を低減するためである。

-K size

[デフォルト: 8M] 個々のスレッドの最大スタックサイズをsizeに設定する。このオプションは、プログラムが無限ループに陥ったときに利用可能なメモリを使い果たすことがないようするためだけに存在している。

-m n

ヒープのうち確保可能な(訳注: 未使用な)部分の最小%を指定する。デフォルトは3%である。

-M size

[デフォルト: 無制限] 最大ヒープサイズをsizeに設定する。ヒープは通常プログラムのメモリ要求に従って伸長したり収縮したりする。このオプションの唯一の存在理由は、ヒープが際限なく膨張してスワップ空間を使い果たす(結果として、少なくともプログラムが即座にOSに殺されることになる)のを防ぐことである。

ヒープの最大サイズは他のGCパラメタにも影響する。ヒープ中の生存データが最大ヒープサイズに対して一定の割合を越えると、最古の世代に対して自動的にコンパクト化回収が有効になり、最大ヒープサイズを越えることがないように-Fパラメタが減少せしめられる。

-t[file] , -s[file] , -S[file] , --machine-readable

これらのオプションはランタイムシステムの統計情報を生成する。プログラムを実行するのに使った時間、ガベッジコレクタで使った時間、確保されたメモリの量、ヒープの最大サイズ、といったものである。この三種類のオプションは、詳細さの度合いが異なる。-tは、GHCの-Rghc-timingオプションと同じ形式で一行だけの出力を生成する。-sはプログラムの最後にもっと詳細なまとめを生成し、-Sはさらにガベッジコレクション一回一回について情報を生成する。

出力内容はfileに置かれる。fileが省略された場合、出力はstderrに送られる。

-tフラグを使った場合、プログラムの終了時、次のようなものを見ることになるだろう。

<<ghc: 36169392 bytes, 69 GCs, 603392/1065272 avg/max bytes residency (2 samples), 3M in use, 0.00 INIT (0.00 elapsed), 0.02 MUT (0.02 elapsed), 0.07 GC (0.07 elapsed) :ghc>>

これは以下のことを伝えている。

  • この実行全体にわたってプログラムによって確保されたバイトの総量。

  • 実行されたガベッジコレクションの合計回数。

  • 「内容量(residency)」の平均値および最大値。内容量とは、生存しているデータの量をバイト単位で表したものである。ランタイムが生存データの量を決定できるのは大GCの間だけなので、標本の数が大GCの数に対応する(これは比較的小さい数になる)。プログラムのヒープの性質についてのよりよい描像を得るためには、-hTを使うこと(4.16.5. プロファイルに関するRTSオプション)。

  • RTSがOSから確保したメモリの最大値。

  • ランタイムシステムの初期化(INIT)、プログラム自体の実行(MUT, the mutator)、ガベッジコレクション(GC)それぞれのCPU時間と経過した実時間。

-t --machine-readableとすれば、よりfuture-proofな、機械可読の形式でこれを得ることができる。

 [("bytes allocated", "36169392")
 ,("num_GCs", "69")
 ,("average_bytes_used", "603392")
 ,("max_bytes_used", "1065272")
 ,("num_byte_usage_samples", "2")
 ,("peak_megabytes_allocated", "3")
 ,("init_cpu_seconds", "0.00")
 ,("init_wall_seconds", "0.00")
 ,("mutator_cpu_seconds", "0.02")
 ,("mutator_wall_seconds", "0.02")
 ,("GC_cpu_seconds", "0.07")
 ,("GC_wall_seconds", "0.07")
 ]

-sフラグを使った場合、プログラムの終了時に次のようなものを目にすることになるだろう。(細部が厳密にどうなるかは使っているRTSの種類によって異なる。例えば、プロファイルのデータを見られるのはRTSがプロファイル用にコンパイルされている場合だけである)

      36,169,392 bytes allocated in the heap
       4,057,632 bytes copied during GC
       1,065,272 bytes maximum residency (2 sample(s))
          54,312 bytes maximum slop
               3 MB total memory in use (0 MB lost due to fragmentation)

  Generation 0:    67 collections,     0 parallel,  0.04s,  0.03s elapsed
  Generation 1:     2 collections,     0 parallel,  0.03s,  0.04s elapsed

  SPARKS: 359207 (557 converted, 149591 pruned)

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time    0.01s  (  0.02s elapsed)
  GC    time    0.07s  (  0.07s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time    0.08s  (  0.09s elapsed)

  %GC time      89.5%  (75.3% elapsed)

  Alloc rate    4,520,608,923 bytes per MUT second

  Productivity  10.5% of total user, 9.1% of total elapsed
  • "bytes allocated in the heap"はこの実行全体にわたってプログラムによって確保されたバイトの総量である。

  • GHCはデフォルトではコピーGCを使っている。"bytes copied during GC"はガベッジコレクション中にコピーしなければならなかったバイト数を示す。

  • プログラムによって実際に使われた空間の最大値が"bytes maximum residency"の数値である。これは大GCのときにしか検査されないから、単なる近似値である。標本(sample)の数によって何回検査されたかが分かる。

  • "bytes maximum slop"は、GHCがメモリをブロック単位で確保することによって無駄になった空間の最大値である。 slopとはブロックの無駄になった後方部分である。これを制御する方法はない。どれだけのメモリがこうやって失われたか見たいだけである。

  • "total memory in use"はRTSがOSから確保したメモリの最大値である。

  • 次に、行われたガベッジコレクションについての情報がある。それぞれの世代について、ガベッジコレクションが何回行われたか、そのうち何回が並列に行われたか、その世代をGCするために使われたCPU時間の合計、その世代をGCするために経過した実時間の合計、が示されている。

  • 統計情報SPARKSは、プログラム中でのControl.Parallel.parやこれに関連した機能の利用に関係する。個々のスパーク(spark)はparの一回の呼び出しを表す。スパークが「変換される(converted)」とは、それが並列に実行されることである。スパークが「刈り取られる(pruned)」とは、それが既に評価済みであることが分かり、ガベッジコレクタによってプールから捨てられることである。実行が終わると残っているスパークはすべて捨てられるので、「変換された」ものと「刈り取られた」ものを足しても合計に見たないことがあり得る。

  • 次に、CPU時間と経過した実時間を、そのときランタイムシステムが何をしていたかによって項目分けしたものがある。INITはランタイムシステムの初期化である。MUTはmutator time、すなわち実際にあなたのコードを走らせるのに掛かった時間である。GCはガベッジコレクションを行うのに掛かった時間である。RPは維持原因プロファイルを行うのに掛かった時間である。PROFはその他のプロファイルを行うのに掛かった時間である。EXITはランタイムシステムの終了処理時間である。最後に、Totalは、もちろん、合計である。

    %GCは、GCが全体の何%を占めるかを表している。"Alloc rate"は"bytes allocated in the heap"をMUT CPU時間で割ったものである。"Productivity"はCPU時間および経過した実時間の合計の何%がmutator(MUT)で消費されたかである。

-Sフラグは、-sフラグと同じものを出力するのに加え、GCが発生するたびにそれについての情報を表示する。

    Alloc    Copied     Live    GC    GC     TOT     TOT  Page Flts
    bytes     bytes     bytes  user  elap    user    elap
   528496     47728    141512  0.01  0.02    0.02    0.02    0    0  (Gen:  1)
[...]
   524944    175944   1726384  0.00  0.00    0.08    0.11    0    0  (Gen:  0)

個々のガベッジコレクションについて、表示するのは以下のものである。

  • このGCで確保したバイト数。

  • このGCでコピーしたバイト数。

  • 現在生存しているバイト数。

  • このGCに掛かった時間(CPU時間および経過した実時間)。

  • これまでにプログラムが実行された時間(CPU時間および経過した実時間)。

  • このGCで起こったページフォールトの個数。

  • 直近のGCの終了以降に起こったページフォールトの個数。

  • GC対象の世代。

並行性と並列性に関するRTSオプション

並行実行に関わるRTSオプションは4.13. Concurrent Haskellを使うで、並列計算に関わる物は4.14.2. SMP並列性のためのRTSオプションで、それぞれ説明されている。

プロファイルに関するRTSオプション

プロファイルについてのランタイムオプションの大部分は、プログラムをプロファイル用にコンパイルした場合にのみ利用可能である。(5.2. プロファイルについてのコンパイルオプションを見よ、またランタイムオプションについては5.4.1. ヒーププロファイルのためのRTSオプションを見よ)。ただし、通常の非プロファイル版実行ファイルでも利用できるプロファイルオプションがただ一つ存在する。

-hT

基本的なヒーププロファイルを、prog.hpというファイルに生成する。ヒーププロファイルのグラフを作成するには、hp2ps(5.5. hp2ps––ヒーププロファイルをPostScriptへを見よ)を使えばよい。この基本的なヒーププロファイルは、データ構築子ごとに分類され、その他の種類のクロージャはFUNTHUNKといった広い範疇ごとにまとめられている。より詳細なプロファイルを得るには、完全なプロファイルサポート(第5章. プロファイルを取る)を使えばよい。

追跡情報を得る

プログラムが-eventlogオプション(4.11.6. リンクに影響するオプション)付きでリンクされている場合、実行時のイベントを二通りの方法で記録することができる。

  • バイナリ形式でファイルに記録し、後でいろいろなツールによって分析できるようにする。ThreadScopeはそのようなツールの一つであり、イベント記録を解釈して、プログラムの視覚的な並列実行プロファイルを作成する。

  • テキストとして標準出力に出力し、デバッグに供する。

-l[flags]

イベントをバイナリ形式でprogram.eventlogというファイルに記録する。ここで、flagsは、どの種類のイベントを記録するかを示す文字の零個以上の並びである。現在、対応している型はひとつだけである。すなわち、-lsでスケジューラのイベントを記録する。

記録ファイルの形式はGHCに付属するEventLogFormat.hに記述されており、Haskellではghc-eventsライブラリを使うことでパースできる。.eventlogファイルの内容をテキストとしてダンプするには、ghc-eventsパッケージに付属しているshow-ghc-eventsというツールが使える。

-v[flags]

イベントを、.eventlogファイルにではなく、テキストとして標準出力に記録する。flags-lの場合と同じであるが、追加のオプションtがあって、これは、表示される個々のイベントの前にタイムスタンプを表示することを示す。(バイナリの.eventlogファイルでは、全てのイベントは自動的にタイムスタンプと結び付けられる)

この追跡フレームワークで記録されるイベントを、デバッグオプション-Dxも生成する。デフォルトではこれらのイベントはテキストとして標準出力にダンプされる(-Dxによって-vが有効になる)が、-lを使うことでバイナリのイベント記録ファイルに保存することもできる。

ハックする者、デバッグする者、及び好奇心過剰な魂のためのRTSオプション

これらのRTSオプションは、(a) GHCのバグを回避するために、(b) 「何が実際に起きているか」を知るために、(c) なんとなくそうしたいから、という理由で使うことができる。素人にはおすすめできない。

-B

GC(大)が始まるたびにベルを鳴らす。

実に奇妙なことだが、実際にこのオプションを使う人々が存在する。ダラム(イギリス)にいる我々の仲間、ポール・キャラハンは次のように書いている。「ここには色んな目的のためにこれを使う人々がいる—これは本当だ—例えば、コード/機械が何かをしているということを確認したり、無限ループを発見したり、最近付け加えたコードのコストを量ったりだ。ある種の人々はビープのパターンからプログラムがどの段階にいるかを聞き分けることさえできる。しかし最も重要な使いかたは、同じオフィスにいる他の人を鬱陶しがらせることである…」

-D x

RTSのデバッグフラグ。RTSがDEBUGオプション付きでリンクされているときのみ使える。RTSのいろいろな部分について、デバッグ出力や追加の実行時の正気チェックを有効にするためのxの値が用意されている。例えば、+RTS -Ds -RTSとするとスケジューラのデバッグ出力が有効になる。どういうデバッグフラグがサポートされているかを知るには+RTS -?が使える。

-lオプションを追加すると、デバッグ出力が標準出力でなくバイナリのイベント記録ファイルに送られるようになる。デバッグ追跡にかかるオーバーヘッドを減らしたいときに便利かもしれない。

-r file

プログラムの実行終了時に「ticky-ticky」統計情報を生成する(プログラムが-debugオプション付きでリンクされている場合にのみ利用可能)。fileの扱いは上にある-SRTSオプションの場合と同じである。

ticky-tickyプロファイルについての更なる情報は、5.7. 「ticky-ticky」プロファイルを使うを見よ。

-xc

(プログラムがプロファイルを取れるようにコンパイルしてある場合のみ利用可能) プログラム中で例外が発生したとき、このオプションが指定されていると、現在のコスト集約点スタックがstderrに出力される。

これは特にデバッグ時に有用である。プログラムがhead []エラーを起こすが、コードのどの部分が原因か分からないとき、-prof -auto-allを付けてコンパイルし、+RTS -xc -RTSを付けて実行すれば、エラーが発生した地点の呼び出しスタックが正確に分かる。

発生した例外一つにつき一行が出力される。(プログラムは、実行を通して、例外を複数回発生させたり捕捉したりし得る)。各行は以下の形を取る。

< cc1, ..., ccn >

それぞれのcciはプログラム中のコスト集約点(5.1. コスト集約点とコスト集約点スタックを見よ)であり、この列は例外が発生した地点での「呼び出しスタック」を表している。最も右にあるのが最も外側の関数である。

-Z

GC時の「update-frame-squeezing」を無効にする。(There's no particularly good reason to turn it off, except to ensure the accuracy of certain data collected regarding thunk entry counts.(訳注: 訳せません。助けて))

RTSに関する情報を取得する

RTSに、自分自身の情報をいくらか表示させることが可能である。これをするには--infoフラグを使う。例えば次のように。

$ ./a.out +RTS --info
 [("GHC RTS", "YES")
 ,("GHC version", "6.7")
 ,("RTS way", "rts_p")
 ,("Host platform", "x86_64-unknown-linux")
 ,("Host architecture", "x86_64")
 ,("Host OS", "linux")
 ,("Host vendor", "unknown")
 ,("Build platform", "x86_64-unknown-linux")
 ,("Build architecture", "x86_64")
 ,("Build OS", "linux")
 ,("Build vendor", "unknown")
 ,("Target platform", "x86_64-unknown-linux")
 ,("Target architecture", "x86_64")
 ,("Target OS", "linux")
 ,("Target vendor", "unknown")
 ,("Word size", "64")
 ,("Compiler unregisterised", "NO")
 ,("Tables next to code", "YES")
 ]

この情報は、[(String, String)]型の値として読めるように整形されている。現在、以下のフィールドが存在する。

GHC RTS

このプログラムはGHC RTSにリンクされているか?(常に"YES")

GHC version

このプログラムをコンパイルするのに用いられたGHCのバージョン

RTS way

ランタイムの種類(「way」)。特によくある値は、rts(バニラ)、rts_thr(スレッド化されたランタイム、つまり-threadedオプション付きでリンクされたもの)、rts_p(プロファイル用ランタイム、つまり-profオプション付きでリンクされたもの)である。他の種類には、debug(-debugを使ってリンクされたもの)、dyn(RTSが動的にリンクされる、つまり実行ファイルに静的にリンクされているのでない共有ライブラリである)などがある。これらは組み合わせることができる。例えば、rts_thr_debug_pというものが可能である。

Target platform, Target architecture, Target OS, Target vendor

プログラムが走ることを意図されたプラットフォーム。

Build platform, Build architecture, Build OS, Build vendor

プログラムがビルドされたプラットフォーム。(つまり、GHC自身のターゲットプラットフォームである)。通常これはターゲットプラットフォームと同じである。(クロスコンパイルの際には異なることが考えられる)

Host platform, Host architecture Host OS Host vendor

GHC自身がコンパイルされたプラットフォーム。これも、通常はビルドおよびターゲットのプラットフォームと同じである。

Word size

ターゲットプラットフォームのワードの大きさに応じて、"32"または"64"

Compiler unregistered(訳注: unregisteredでなくunregisterisedが正しいものと思われる)

このプログラムは「非レジスタ化」版のGHC(すなわち、通常未対応のプラットフォームであるために、プラットフォーム固有の最適化なしでコンパイルされたGHC)によってコンパイルされたか?実験的なGHCのビルドを使っているのでない限り、この値は通常noである。

Tables next to code

info tableをコードに直接隣接させて配置するという最適化は有用であるが、全てのプラットフォームで対応されている訳ではない。このフィールドは、プログラムがこの最適化を使ってコンパイルされているかどうかを示すものである。(珍しいプラットフォームでなければ通常yesである)