ランドマークは、 OCAMLのシンプルなプロファイリングライブラリです。コードの一部を区切り、実行時に計装コードのパフォーマンスを測定するためのプリミティブを提供します。利用可能な測定値は、CPUサイクル(CPUのタイムスタンプカウンターを使用)、適用時間( Sys.time
を使用)、および割り当てられたバイト( Gc.allocated_bytes
を使用)を集約することによって得られます。コードの計装は、PPX拡張機能を使用して、自動的に、または半自動的に行われます。
プログラムの実行中、制御フローによる計装コードのトラバーサルは、収集された測定値を運ぶ「コールグラフ」として記録されます。結果は、コンソールで直接閲覧するか、JSONにエクスポートされる場合があります。
このツールは、プログラムの時間が費やされる場所を見つける方法として使用することを目的としています(Core_benchのようなコードの独立した部分ではなく)、OCAMLコードの計装部分のみに対応する結果を提供することを目的としています(OCAMLコードの計装部分のみに対応します( GPROFやPERFなどのバイナリ実行可能ファイルを直接動作します)。
詳細については、APIを閲覧できます。
ライブラリは2つのパッケージに分割されます。ランタイムライブラリ用のlandmarks
と、自動機器を実装するプレプロセッサ用landmarks-ppx
です。
opam install landmarks
または
opam install landmarks-ppx
ランタイムライブラリまたはランタイムライブラリとプリプロセッサの両方をインストールします。
git clone https://github.com/LexiFi/landmarks.git
cd landmarks
dune build @install
ライブラリlandmarks
とプリプロセッサlandmarks-ppx
使用して、実行可能ファイルやライブラリをベンチマークするだけです。たとえば、次のdune
ファイルは、 landmarks
LibraryとそのPPXを使用して実行可能なtest
を構築します。オプションの--auto
フラグは自動計装をオンにします(以下を参照)。
(executable
(name test)
(libraries landmarks)
(preprocess (pps landmarks-ppx --auto))
)
Duneを使用して、プロジェクトの計装を自動的にトリガーすることができます。基本的な例については、Lexifi/Landmarks-Starterをご覧ください。詳細については、Duneマニュアルをご覧ください。
ocamlfind ocamlopt -c -package landmarks prog.ml
ocamlfind ocamlopt -o prog -package landmarks -linkpkg prog.cmx
「ocamlopt」を「ocamlc」で置き換えて、bytecodeでプログラムをコンパイルできます。
ocamlfind ocamlopt -c -package landmarks -package landmarks-ppx -ppxopt landmarks-ppx,--auto prog.ml
ocamlfind ocamlopt -o prog -package landmarks -linkpkg prog.cmx
「-ppxopt landmarks-ppx、 - auto」はオプションであり、自動計装をオンにすることに注意してください。
3つの主なプリミティブがあります。
val register : string -> landmark
val enter : landmark -> unit
val exit : landmark -> unit
register
関数は新しいランドマークを宣言し、トップレベルで使用する必要があります。関数enter
とexit
ランドマークに添付されたコードの部分を区切るために使用されます。プロファイリングの終わりに、各ランドマークについて、対応するコードの実行に費やした集約時間情報を取得します。実行中、「callgraph」を構築するために、訪問した各ランドマークの痕跡も記録されます。
例えば:
open Landmark
let loop = register " loop "
let sleep = register " sleep "
let main = register " main "
let zzz () =
enter sleep;
Unix. sleep 1 ;
exit sleep
let () =
begin
start_profiling () ;
enter main;
enter loop;
for _ = 1 to 9 do
zzz ()
done ;
exit loop;
zzz () ;
exit main;
end
(このファイルはocamlfind ocamlc -o prog -package landmarks -package unix -linkpkg prog.ml
)
誘導されたコールグラフは次のとおりです。
- 100.00% : main
| - 90.00% : loop
| | - 100.00% : sleep
| - 10.00% : sleep
これは次のように言い換えることができます:
clock()
関数ライブラリは、X86 32および64ビットアーキテクチャの高性能サイクルカウンターへのバインディングを提供します( landmarks-noc.cm(x)a
独自の実装を提供するアーカイブを使用することができます)。計装コード内で費やされる時間を測定するために使用されます。
ボイラープレートコードの作成を避けるために、このパッケージで分散したPPX拡張機能を使用できます。これにより、プログラマーは注釈を使用して式を計装し、トップレベルの関数を自動的に機器にすることができます。
値expr [@landmark "name"]
が拡張されます
Landmark. enter __generated_landmark_1;
let r =
try expr with e -> Landmark. exit __generated_landmark_1; raise e
in
Landmark. exit __generated_landmark_1;
r
と宣言
let __generated_landmark_1 = Landmark. register " name "
トップレベルで追加されています。
この変換は、テール再帰的な呼び出しを維持しない(また、多型の一般化を防ぐ)ことを指摘する必要があります。これらlet rec ... in
問題を回避するには、他の提供された拡張機能を使用することをお勧めしますlet ... in
let [ @ landmark] f = body
拡張されています:
let __generated_landmark_2 = Landmark. register " f "
let f = body
let f x1 ... xn =
Landmark. enter __generated_landmark_2;
let r =
try f x1 ... xn with e -> Landmark. exit __generated_landmark_2; raise e
in
Landmark. exit __generated_landmark_2;
r
f
のアリティn
fun ... ->
およびfunction ... ->
body
。この注釈をLet-Rec-Bindingsで使用する場合、エントリポイント呼び出しのみが記録されることに注意してください。たとえば、次のコードで
let () =
let [ @ landmark] rec even n = (n = 0 ) || odd (n - 1 )
and [ @ landmark] odd n = (n = 1 ) || n > 0 && even (n - 1 )
in Printf. printf " 'six is even' is %b n " (even 6 )
「偶数」に関連付けられているランドマークは、3回ではなく(3回ではありません!)、「奇数」に関連付けられたランドマークを通過しません。
構造アノテーション[@@@landmark "auto"]
および[@@@landmark "auto-off"]
は、モジュール内のトップレベル関数の自動計装をアクティブ化または非アクティブ化します。自動モードでは、すべての関数宣言は暗黙的に注釈が付けられます。以下に詳述するように、オプションauto
のオプションOCAML_LANDMARKS
を介して、すべてのファイルに対して自動機器を有効/無効にできます。
環境変数OCAML_LANDMARKS
、ppx rewriterが実行されたとき、およびランドマークモジュールが機器のプログラムによってロードされたときの2つの異なる段階で読み取られます。この変数は、フォームoption=argument
またはoption
のアイテムのコンマ分離されたリストとして解析されます。 option
は次のとおりです。
PPXライター段階(コンピレーション時間)中:
auto
(引数なし):デフォルトで自動機器をオンにします(各モジュールがAnnotation [@@@landmark "auto"]
で始まるかのように動作します)。
threads
(引数なし):PPX拡張機能に、モジュールのLandmark
の代わりにLandmark_threads
モジュールを使用するように指示します。
計装プログラムをロードするとき(実行時に):
可能な引数を備えたformat
: textual
(デフォルト)またはjson
。コンソールフレンドリーな表現またはcallgraphのJSONエンコードであるプロファイリングの出力形式を制御します。
引数として0.0〜100.0の数があるthreshold
(デフォルト:1.0)。しきい値がゼロでない場合、テキスト出力はこのしきい値の下のコールグラフのノードを非表示にします(親の時間の割合で)。このオプションは、他の形式では無意味です。
可能な引数を伴うoutput
: stderr
(デフォルト)、 stdout
、 temporary
、 <file>
( <file>
はファイルのパスです)。プロファイリングの結果をどこに出力するかを示します。 temporary
には一時ファイルに印刷されます(このファイルの名前は標準エラーに印刷されます)。また、 temporary:<directory>
を使用して、ファイルが生成されるディレクトリを指定することもできます。
引数なしのdebug
。ランドマークのプリミティブが呼び出されるたびに、stderrにトレースを出力する冗長モードをアクティブにします。
議論のないtime
。また、プロファイリング中にSys.time
タイムスタンプを収集します。
議論なしでoff
。プロファイリングを無効にします。
議論なしon
。プロファイリングを有効にします(デフォルト;省略する場合があります)。
引数なしのallocation
。また、 Gc.allocated_byte
データを収集します。
コンピューターでWebビューアーをコンパイルするか、オンラインで閲覧することができます。 FilePickerを使用してJSONファイルをロードする必要があります。その後、クリックしてCallgraphを参照できます。
Landmark
モジュールはスレッドセーフではありません。複数のスレッドがある場合は、最大で1つのスレッドが機器コードを実行していることを確認する必要があります。そのためには、 Landmark_threads
モジュール(Landmarks-threads.cm(x)に含まれるアーカイブ)を使用して、プロファイリングを開始したスレッド以外のすべてのスレッドで実行されない機能を実行することを防ぎます。
表現への注釈は、多型で和らげられる可能性があります(これは、拘束された注釈の場合ではありません)。たとえば、次のコードのコンパイルに失敗します。
let test = ( fun x -> x)[ @ landmark " test " ]
in test " string " , test 1
この「ランドマーク」パッケージは、MITライセンスの条件に基づいてLexifiによってライセンスされています。