地標是OCAML的簡單分析庫。它提供了原始圖,以劃定代碼的部分並在運行時測量儀器代碼的性能。可用的措施是通過匯總CPU週期(使用CPU的時間郵票計數器),應用時間(使用Sys.time
)和分配的字節(使用Gc.allocated_bytes
)來獲得的。代碼的儀器可以使用PPX擴展程序自動或半自動手工完成。
在執行程序期間,控制流的儀器代碼遍歷被記錄為帶有收集措施的“呼叫圖”。結果可以直接瀏覽在控制台上,也可以導出到JSON。
該工具旨在將其用作查找在程序中花費的時間(而不是基準的獨立代碼(例如core_bench))的方式,而提供的結果僅與OCAML代碼的儀器相對應(與工具相反)直接與二進制可執行文件(如gprof或perf)一起使用。
有關更多信息,您可以瀏覽API。
該庫分為兩個軟件包:運行時庫的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
庫及其PPX構建可執行test
。可選的--auto
標誌打開自動儀器(見下文)。
(executable
(name test)
(libraries landmarks)
(preprocess (pps landmarks-ppx --auto))
)
可以使用沙丘自動觸發項目的儀器。請查看Lexifi/Landmarks-Starter的基本示例,並查看《沙丘手冊》以獲取更多信息。
ocamlfind ocamlopt -c -package landmarks prog.ml
ocamlfind ocamlopt -o prog -package landmarks -linkpkg prog.cmx
您可以用“ Ocamlc”替換“ Ocamlopt”,以在字節碼中編譯程序。
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, - 自動”是可選的,並且可以打開自動儀器。
有三個主要原則:
val register : string -> landmark
val enter : landmark -> unit
val exit : landmark -> unit
register
功能聲明了新的地標,應在Toplevel上使用。 enter
和exit
功能用於界定附屬於地標的代碼部分。在分析結束時,我們檢索每個地標的總匯總時間信息,用於執行相應的代碼。在執行過程中,還記錄了每個訪問的地標的痕跡,以構建“呼叫圖”。
例如:
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
的ARITH n
時fun ... ->
和function ... ->
在body
中。請注意,將此註釋與LET-REC綁定一起使用時,僅記錄入口點調用。例如,在以下代碼中
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 )
與“偶數”相關的地標將精確地穿越一次(不是三遍!),而控制流將不會穿過與“奇數”相關的地標。
The structure annotations [@@@landmark "auto"]
and [@@@landmark "auto-off"]
activate or deactivate the automatic instrumentation of top-level functions in a module.在自動模式下,所有函數聲明都是隱式註釋的。如下所述,可以通過OCAML_LANDMARKS
中的OPAML_LANDMARKS中的Option auto
啟用/禁用所有文件的自動儀器。
環境變量OCAML_LANDMARKS
在兩個不同的階段讀取:執行PPX重寫器以及Landmarks模塊被儀器程序加載時。該變量被解析為表單option=argument
或option
的逗號分隔列表,其中option
是:
在PPX重寫階段(在編譯時):
auto
(無參數):默認情況下打開自動儀器(表現得好像每個模塊以註釋開頭[@@@landmark "auto"]
)。
threads
(無參數):告訴PPX擴展程序使用Landmark_threads
模塊而不是模塊Landmark
。
加載儀器程序(在運行時)時:
format
具有可能的參數: textual
(默認)或json
。它控制分析的輸出格式,該格式是控制台友好表示形式,也可以是callgraph的JSON編碼。
threshold
在0.0到100.0之間為參數(默認值:1.0)。如果閾值不為零,則文本輸出將在此閾值以下的呼叫圖中隱藏節點(以其父級的百分比為單位)。對於其他格式,此選項毫無意義。
output
可能參數: stderr
(默認), stdout
, temporary
, <file>
(其中<file>
是文件的路徑)。它講述了在哪裡輸出分析結果。使用temporary
它將將其打印在臨時文件中(該文件的名稱將在標準錯誤上打印)。您也可以使用temporary:<directory>
指定文件生成的目錄。
沒有爭論的debug
。激活詳細模式,每次調用地標原始圖。
沒有爭論的time
。還可以在分析過程中收集Sys.time
時間戳。
沒有off
。禁用分析。
on
爭論。啟用分析(默認;可能會省略)。
allocation
沒有參數。還收集Gc.allocated_byte
數據。
您可以在計算機上編譯網絡查看器,也可以在線瀏覽。您需要使用FilePicker加載JSON文件,然後單擊以瀏覽呼叫圖。
Landmark
模塊不是線程安全。如果您有多個線程,則必須確保最多有一個線程是執行儀器代碼。為此,您可以使用Landmark_threads
模塊(包含在Landmarks-threads.cm(x)A檔案中),該模塊可以防止在所有線程中執行的非線程安全函數,但開始進行分析。
對錶達的註釋可能會隨著多態性的速度(釋放結束註釋不是這種情況)。例如,以下代碼將無法編譯:
let test = ( fun x -> x)[ @ landmark " test " ]
in test " string " , test 1
此“地標”包由Lexifi根據MIT許可的條款許可。