檢視原始碼 fprof (工具 v4.1.1)
一個使用追蹤到檔案的時間剖析工具,以盡量減少執行時的效能影響。
此模組用於剖析程式以找出執行時間如何被使用。追蹤到檔案用於盡量減少執行時的效能退化。
fprof
模組使用追蹤來收集剖析資料,因此不需要對任何要剖析的模組進行特殊編譯。當它開始追蹤時,fprof
將會清除節點中所有先前的追蹤,並在剖析目標程序上設定必要的追蹤標誌,以及所有已載入模組和將要載入的所有模組中的本機呼叫追蹤。fprof
在停止追蹤時會停用節點中的所有追蹤。
fprof
會呈現 自有時間,也就是函數用於自身執行的時間,以及 累積時間,也就是包含呼叫函數的時間。所有呈現的時間都是使用追蹤時間戳記收集的。fprof
會嘗試收集 CPU 時間戳記,如果主機作業系統支援的話。因此,時間可以是實際時間,而作業系統排程將會以大致公平的方式隨機影響所有呼叫的函數。
但是,如果剖析時間很短,而且主機作業系統不支援高解析度的 CPU 時間測量,則一些作業系統排程可能會顯示函數在幾乎沒有做任何事情的情況下,執行時間卻異常地長。舉例來說,觀察到一個或多或少只是組成一個元組的函數,執行速度比正常情況慢 100 倍。當重複追蹤時,執行時間會恢復正常。
剖析基本上分為 3 個步驟
追蹤:到檔案。追蹤資料包含函數呼叫、返回函數、程序排程、其他程序相關事件(例如
spawn
)和垃圾收集的項目。所有追蹤項目都有時間戳記。剖析:讀取追蹤檔案,模擬執行呼叫堆疊,並從模擬的呼叫堆疊和追蹤時間戳記計算原始剖析資料。剖析資料儲存在
fprof
伺服器狀態中。在此步驟中,追蹤資料可能會以文字格式轉儲到檔案或主控台。分析:原始剖析資料會排序、篩選,並以文字格式轉儲到檔案或主控台。文字格式的目的是讓人類讀者可以閱讀,並且可以使用標準 Erlang 解析工具進行解析。
由於 fprof
將追蹤資料傳送到檔案,因此執行時的效能退化會降到最低,但仍然遠非可以忽略不計,尤其是對於本身大量使用檔案系統的程式。追蹤檔案放置的位置也很重要,例如,在 Unix 系統上,/tmp
通常是不錯的選擇,因為它本質上是個 RAM 磁碟,而任何網路掛載的磁碟都是個糟糕的選擇。
fprof
也可以跳過檔案步驟,並追蹤到執行時進行剖析的追蹤器程序。
分析格式
本節描述 analyse/1
函數的輸出格式。
此格式可使用標準 Erlang 解析工具 erl_scan
和 erl_parse
、file:consult/1
或 io:read/2
進行解析。此處不描述解析格式 — 感興趣的讀者應該很容易嘗試出來。請注意,analyse/1
的某些標誌會影響格式。
以下範例在 Solaris 8 上的 Erlang/OTP R8 上執行;此範例中的所有 OTP 內部結構都與版本相關。
舉例來說,我們將使用以下函數,它是從模組 file
中稍微修改過的基準測試函數
-module(foo).
-export([create_file_slow/2]).
create_file_slow(Name, N) when is_integer(N), N >= 0 ->
{ok, FD} =
file:open(Name, [raw, write, delayed_write, binary]),
if N > 256 ->
ok = file:write(FD,
lists:map(fun (X) -> <<X:32/unsigned>> end,
lists:seq(0, 255))),
ok = create_file_slow(FD, 256, N);
true ->
ok = create_file_slow(FD, 0, N)
end,
ok = file:close(FD).
create_file_slow(FD, M, M) ->
ok;
create_file_slow(FD, M, N) ->
ok = file:write(FD, <<M:32/unsigned>>),
create_file_slow(FD, M+1, N).
讓我們看看執行後的列印輸出
1> fprof:apply(foo, create_file_slow, [junk, 1024]).
2> fprof:profile().
3> fprof:analyse().
列印輸出以
%% Analysis results:
{ analysis_options,
[{callers, true},
{sort, acc},
{totals, false},
{details, true}]}.
% CNT ACC OWN
[{ totals, 9627, 1691.119, 1659.074}]. %%%
開頭。CNT
欄顯示在追蹤中找到的函數呼叫總數。ACC
欄是從第一個時間戳記到最後一個時間戳記的追蹤總時間。而 OWN
欄是追蹤中找到的函數執行時間總和,不包括呼叫的函數。在這種情況下,它非常接近 ACC
時間,因為模擬器除了執行我們的測試程式外幾乎沒有做任何事情。
列印輸出中的所有時間值都以毫秒為單位。
列印輸出繼續
% CNT ACC OWN
[{ "<0.28.0>", 9627,undefined, 1659.074}]. %%
這是單個程序的列印輸出標頭。列印輸出僅包含這個單個程序,因為我們呼叫了 fprof:apply/3
,它只追蹤目前的程序。因此,CNT
和 OWN
欄與上面的總數完全匹配。由於將程序中所有呼叫的 ACC
時間加總沒有意義 — 得到的會像是上面總數的 ACC
值乘以呼叫堆疊的平均深度,因此 ACC
欄是未定義的。
直到下一個程序標頭的所有段落都僅與此程序內的函數呼叫有關。
現在我們來看看一些更有趣的東西
{[{undefined, 0, 1691.076, 0.030}],
{ {fprof,apply_start_stop,4}, 0, 1691.076, 0.030}, %
[{{foo,create_file_slow,2}, 1, 1691.046, 0.103},
{suspend, 1, 0.000, 0.000}]}.
{[{{fprof,apply_start_stop,4}, 1, 1691.046, 0.103}],
{ {foo,create_file_slow,2}, 1, 1691.046, 0.103}, %
[{{file,close,1}, 1, 1398.873, 0.019},
{{foo,create_file_slow,3}, 1, 249.678, 0.029},
{{file,open,2}, 1, 20.778, 0.055},
{{lists,map,2}, 1, 16.590, 0.043},
{{lists,seq,2}, 1, 4.708, 0.017},
{{file,write,2}, 1, 0.316, 0.021}]}.
列印輸出由每個呼叫的函數一個段落組成。標記為 %
的函數是該段落所關注的函數 — foo:create_file_slow/2
。在標記函數上方的是 呼叫 函數 — 呼叫標記函數的函數,而在下方的是標記函數 呼叫 的函數。
段落預設按照標記函數的 ACC
欄的降序排序。一個段落內的呼叫清單和被呼叫清單也預設按照其 ACC
欄的降序排序。
各欄如下
CNT
- 函數被呼叫的次數ACC
- 在函數中花費的時間,包括呼叫的函數OWN
- 在函數中花費的時間,不包括呼叫的函數
呼叫 函數的列包含 標記 函數的統計資料,但限制為僅計算從 該列 函數呼叫到 標記 函數的情況。
標記 函數的列僅包含所有 呼叫 列的總和。
被呼叫 函數的列包含 該列 函數的統計資料,但限制為僅計算從 標記 函數呼叫到 該列 函數的情況。
因此,我們看到 foo:create_file_slow/2
用於自身執行的時間非常少。它將大部分時間花費在 file:close/1
中。寫入 3/4 檔案內容的函數 foo:create_file_slow/3
是第二大耗時者。
我們還看到,寫入 1/4 檔案內容的 file:write/2
呼叫本身花費的時間很少。花費時間的是建立資料(lists:seq/2
和 lists:map/2
)。
已呼叫 fprof:apply_start_stop/4
的函數 undefined
是一個未知函數,因為該呼叫未記錄在追蹤中。僅記錄到執行從 fprof:apply_start_stop/4
返回到呼叫堆疊中更高層的其他函數,或者程序從那裡結束。
讓我們繼續往下查看列印輸出,找到
{[{{foo,create_file_slow,2}, 1, 249.678, 0.029},
{{foo,create_file_slow,3}, 768, 0.000, 23.294}],
{ {foo,create_file_slow,3}, 769, 249.678, 23.323}, %
[{{file,write,2}, 768, 220.314, 14.539},
{suspend, 57, 6.041, 0.000},
{{foo,create_file_slow,3}, 768, 0.000, 23.294}]}.
如果您與程式碼進行比較,您也會看到 foo:create_file_slow/3
僅從 foo:create_file_slow/2
和自身呼叫,並且僅呼叫 file:write/2
,請注意呼叫 file:write/2
的次數。但在這裡我們看到 suspend
被呼叫了幾次。這是一個虛擬函數,表示程序在 foo:create_file_slow/3
中執行時被暫停,而且由於程式碼中沒有 receive
或 erlang:yield/0
,因此必須是 Erlang 排程暫停,或者追蹤檔案驅動程式補償大型檔案寫入作業(這些被視為排程退出,然後排程到同一程序)。
讓我們找到 suspend
條目
{[{{file,write,2}, 53, 6.281, 0.000},
{{foo,create_file_slow,3}, 57, 6.041, 0.000},
{{prim_file,drv_command,4}, 50, 4.582, 0.000},
{{prim_file,drv_get_response,1}, 34, 2.986, 0.000},
{{lists,map,2}, 10, 2.104, 0.000},
{{prim_file,write,2}, 17, 1.852, 0.000},
{{erlang,port_command,2}, 15, 1.713, 0.000},
{{prim_file,drv_command,2}, 22, 1.482, 0.000},
{{prim_file,translate_response,2}, 11, 1.441, 0.000},
{{prim_file,'-drv_command/2-fun-0-',1}, 15, 1.340, 0.000},
{{lists,seq,4}, 3, 0.880, 0.000},
{{foo,'-create_file_slow/2-fun-0-',1}, 5, 0.523, 0.000},
{{erlang,bump_reductions,1}, 4, 0.503, 0.000},
{{prim_file,open_int_setopts,3}, 1, 0.165, 0.000},
{{prim_file,i32,4}, 1, 0.109, 0.000},
{{fprof,apply_start_stop,4}, 1, 0.000, 0.000}],
{ suspend, 299, 32.002, 0.000}, %
[ ]}.
我們沒有發現特別長的暫停時間,因此似乎沒有函數在 receive 陳述式中等待。實際上,prim_file:drv_command/4
包含 receive 陳述式,但在這個測試程式中,當輸入 receive 陳述式時,訊息位於程序的接收緩衝區中。我們還看到,測試執行的總暫停時間很短。
suspend
虛擬函數的 OWN
時間為零。這是為了防止程序的總 OWN
時間包含暫停時間。暫停時間到底是 ACC
時間還是 OWN
時間更像是一個哲學問題。
現在我們來看另一個有趣的虛擬函數 garbage_collect
{[{{prim_file,drv_command,4}, 25, 0.873, 0.873},
{{prim_file,write,2}, 16, 0.692, 0.692},
{{lists,map,2}, 2, 0.195, 0.195}],
{ garbage_collect, 43, 1.760, 1.760}, %
[ ]}.
在這裡我們看到沒有函數特別突出,這是非常正常的。
garbage_collect
虛擬函數的 OWN
時間不像 suspend
一樣為零,而是等於 ACC
時間。
垃圾收集通常在程序暫停時發生,但 fprof
會假裝暫停的函數先被解除暫停,然後進行垃圾收集,來隱藏這個事實。否則,列印輸出會顯示 garbage_collect
是從 suspend
呼叫的,但不會顯示可能是哪個函數導致了垃圾收集。
現在讓我們回到測試程式碼
{[{{foo,create_file_slow,3}, 768, 220.314, 14.539},
{{foo,create_file_slow,2}, 1, 0.316, 0.021}],
{ {file,write,2}, 769, 220.630, 14.560}, %
[{{prim_file,write,2}, 769, 199.789, 22.573},
{suspend, 53, 6.281, 0.000}]}.
不出所料,我們看到 file:write/2
是從 foo:create_file_slow/3
和 foo:create_file_slow/2
呼叫的。在每種情況下的呼叫次數以及所用時間也證實了先前的結果。
我們看到 file:write/2
僅呼叫 prim_file:write/2
,但讓我們不要深入研究核心應用程式的內部結構。
如果我們仍然 要 深入研究,我們會發現呼叫連結的驅動程式,該驅動程式會執行對主機作業系統的檔案操作
{[{{prim_file,drv_command,4}, 772, 1458.356, 1456.643}],
{ {erlang,port_command,2}, 772, 1458.356, 1456.643}, %
[{suspend, 15, 1.713, 0.000}]}.
這是總執行時間的 86 %,而且正如我們之前看到的,關閉操作是絕對最大的貢獻者。我們在呼叫堆疊中稍微往上找到一個比較比例
{[{{prim_file,close,1}, 1, 1398.748, 0.024},
{{prim_file,write,2}, 769, 174.672, 12.810},
{{prim_file,open_int,4}, 1, 19.755, 0.017},
{{prim_file,open_int_setopts,3}, 1, 0.147, 0.016}],
{ {prim_file,drv_command,2}, 772, 1593.322, 12.867}, %
[{{prim_file,drv_command,4}, 772, 1578.973, 27.265},
{suspend, 22, 1.482, 0.000}]}.
連結驅動程式中的檔案操作時間分配為:開啟佔 1 %、寫入佔 11 %、關閉佔 87 %。所有資料可能都緩衝在作業系統中,直到關閉。
細心的讀者可能會注意到,即使很容易認為 prim_file:drv_command/2
只是一個傳遞函數,但上面各段落的 prim_file:drv_command/2
和 prim_file:drv_command/4
的 ACC 時間並不相等。
缺少的時間可以在 prim_file:drv_command/4
的段落中找到,其中明顯可見不僅呼叫了 prim_file:drv_command/2
,還呼叫了一個 fun
{[{{prim_file,drv_command,2}, 772, 1578.973, 27.265}],
{ {prim_file,drv_command,4}, 772, 1578.973, 27.265}, %
[{{erlang,port_command,2}, 772, 1458.356, 1456.643},
{{prim_file,'-drv_command/2-fun-0-',1}, 772, 87.897, 12.736},
{suspend, 50, 4.582, 0.000},
{garbage_collect, 25, 0.873, 0.873}]}.
而更多缺少的時間可以解釋為 prim_file:open_int/4
直接呼叫 prim_file:drv_command/2
以及透過 prim_file:open_int_setopts/3
呼叫 prim_file:drv_command/2
,這使得情況變得複雜。
{[{{prim_file,open,2}, 1, 20.309, 0.029},
{{prim_file,open_int,4}, 1, 0.000, 0.057}],
{ {prim_file,open_int,4}, 2, 20.309, 0.086}, %
[{{prim_file,drv_command,2}, 1, 19.755, 0.017},
{{prim_file,open_int_setopts,3}, 1, 0.360, 0.032},
{{prim_file,drv_open,2}, 1, 0.071, 0.030},
{{erlang,list_to_binary,1}, 1, 0.020, 0.020},
{{prim_file,i32,1}, 1, 0.017, 0.017},
{{prim_file,open_int,4}, 1, 0.000, 0.057}]}.
.
.
.
{[{{prim_file,open_int,4}, 1, 0.360, 0.032},
{{prim_file,open_int_setopts,3}, 1, 0.000, 0.016}],
{ {prim_file,open_int_setopts,3}, 2, 0.360, 0.048}, %
[{suspend, 1, 0.165, 0.000},
{{prim_file,drv_command,2}, 1, 0.147, 0.016},
{{prim_file,open_int_setopts,3}, 1, 0.000, 0.016}]}.
註解
實際監控執行時間本身就是一項 CPU 密集型活動。對於被分析程式碼所執行的每個函式呼叫,都會在追蹤檔案中寫入一則訊息。
由於 ACC
時間的定義很難明確,因此有時很難正確計算。當一個函式在呼叫堆疊中出現多個實例時,這種情況尤其會發生,例如,該函式可能透過其他函式,甚至非尾遞迴地呼叫自身。
為了產生合理的結果,fprof
嘗試對每個函式僅收取一次 ACC
時間。它會選擇呼叫堆疊中最高層(持續時間最長)的實例。
有時,一個函式可能會意外地浪費大量(約 10 毫秒或更多,取決於主機作業系統)的 OWN
(和 ACC
)時間,即使是幾乎什麼都不做的函式也是如此。問題可能是作業系統選擇暫時排程 Erlang 執行時系統的進程,如果作業系統不支援高解析度的 CPU 時間測量,fprof
將使用掛鐘時間進行計算,並且看起來好像函式正在隨機消耗虛擬機時間。
另請參閱
摘要
函式
等同於 analyse([])
。
分析 fprof
伺服器中的原始分析資料。
在呼叫給定的函式時,會先執行 trace([start, ...])
,然後執行 trace(stop)
。
等同於 profile([])
。
將追蹤資料編譯成由 fprof
伺服器保存的原始分析資料。
啟動 fprof
伺服器。
等同於 stop(normal)
。
停止 fprof
伺服器。
啟動或停止追蹤。
啟動或停止追蹤。
類型
-type analyse_option() :: append | callers | {callers, boolean()} | {cols, Cols :: non_neg_integer()} | dest | {dest, Dest :: pid() | (Destfile :: file:filename())} | details | {details, boolean()} | no_callers | no_details | {sort, SortSpec :: acc | own} | totals | {totals, boolean()}.
-type apply_option() :: continue | {procs, PidList :: [pid()]} | start | (TraceStartOption :: trace_option()).
-type profile_option() :: append | dump | {dump, pid() | (Dump :: (Dumpfile :: file:filename() | []))} | file | {file, Filename :: file:filename()} | start | stop.
函式
-spec analyse() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when ServerPid :: pid(), Reason :: term().
等同於 analyse([])
。
-spec analyse(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), ServerPid :: pid(), Reason :: term(); ({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), OptionValue :: term(), ServerPid :: pid(), Reason :: term(); (OptionList) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionList :: [Option], Option :: analyse_option(), ServerPid :: pid(), Reason :: term().
分析 fprof
伺服器中的原始分析資料。
如果 Arg
是原子,則此呼叫等同於 analyse([Arg])
。
如果 Arg
是元組 {Option, _}
,則此呼叫等同於 analyse([Option])
。
否則,Arg
必須是有效選項的列表。
如果在沒有原始分析資料的情況下呼叫,則會傳回 {error, no_profile}
。
Destfile
用於呼叫 file:open/2
。
選項描述
dest
|{dest, Dest}
- 指定分析的目的地。如果未指定此選項或為dest
,則目的地將為呼叫者的群組領導者,否則目的地Dest
是 I/O 裝置的pid/0
或檔案名稱。如果檔案名稱為[]
,則會改用"fprof.analysis"
。append
- 使分析附加到目的地檔案。此選項僅允許與{dest, Destfile}
選項一起使用。{cols, Cols}
- 指定分析文字中的欄數。如果未指定此選項,則欄數會設定為 80。callers
|{callers, true}
- 在分析中印出呼叫者和被呼叫資訊。這是預設值。{callers, false}
|no_callers
- 在分析中抑制列印呼叫者和被呼叫資訊。{sort, SortSpec}
- 指定是否應根據 ACC 欄(預設值)或 OWN 欄對分析進行排序。請參閱下方的分析格式。totals
|{totals, true}
- 在分析中包含一個包含所有呼叫(無論是哪個進程)的呼叫統計資訊的區段。{totals, false}
- 抑制分析中的總計區段,這是預設值。details
|{details, true}
- 在分析中列印每個進程的呼叫統計資訊。這是預設值。{details, false}
|no_details
- 抑制分析中每個進程的呼叫統計資訊。
-spec apply(Module, Function, Args) -> term() when Module :: module(), Function :: atom(), Args :: [term()]; (Func, Args, OptionList) -> term() when Func :: fun() | {Module :: module(), Function :: atom()}, Args :: [term()], OptionList :: [Option], Option :: apply_option().
在呼叫給定的函式時,會先執行 trace([start, ...])
,然後執行 trace(stop)
。
如果函式引數(Arg1
、Arg2
和 Arg3
)是 Module
(原子)、Function
(原子)和 Args
(列表),則會使用 erlang:apply(Module, Function, Args)
呼叫函式。
如果函式引數是 Func
(函式)、Args
(列表)和 OptionList
(選項列表),則會使用 erlang:apply(Func, Args)
呼叫函式。
會盡量保持追蹤資料的清晰,避免不必要的追蹤訊息;追蹤會從衍生進程啟動和停止,而 erlang:apply/2
會在目前進程中呼叫,並且只會被導向追蹤啟動進程的 receive
和 send
陳述式包圍。當不再需要追蹤啟動進程時,該進程會結束。
TraceStartOption
是 trace/1
允許的任何選項。選項 [start, {procs, [self() | PidList]} | OptList]
會傳遞給 trace/1
,其中 OptList
是移除 continue
、start
和 {procs, _}
選項的 OptionList
。
continue
選項會抑制對 trace(stop)
的呼叫,並讓呼叫者在適當的時間停止追蹤。
-spec apply(Module, Function, Args, OptionList) -> term() when Module :: module(), Function :: atom(), Args :: [term()], OptionList :: [Option], Option :: apply_option().
-spec profile() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when ServerPid :: pid(), Reason :: term().
等同於 profile([])
。
-spec profile(OptionName) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), Tracer :: pid(), ServerPid :: pid(), Reason :: term(); ({OptionName, OptionValue}) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), OptionValue :: term(), Tracer :: pid(), ServerPid :: pid(), Reason :: term(); (OptionList) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionList :: [Option], Option :: profile_option(), Tracer :: pid(), ServerPid :: pid(), Reason :: term().
將追蹤資料編譯成由 fprof
伺服器保存的原始分析資料。
如果 Arg
是原子,則此呼叫等同於 profile([Arg])
。
如果 Arg
是元組 {OptionName, OptionValue}
,則此呼叫等同於 profile([Arg])
。
否則,Arg
必須是選項的列表。
Dumpfile
用於呼叫 file:open/2
,而 Filename
用於呼叫 dbg:trace_port(file, Filename)
。
支援下列選項
file
|{file, Filename}
- 讀取檔案Filename
並建立原始分析資料,該資料會由fprof
伺服器儲存在 RAM 中。如果指定選項file
,或未指定這些選項,則會讀取檔案fprof.trace
。當整個追蹤資料讀取完成後,呼叫會傳回,如果成功則會傳回值ok
。此選項不允許與start
或stop
選項一起使用。dump
|{dump, Dump}
- 指定追蹤文字轉儲的目的地。如果未指定此選項,則不會產生轉儲;如果是dump
,則目的地將是呼叫者的群組領導者,否則目的地Dump
是 I/O 裝置的 pid 或檔案名稱。如果檔案名稱為[]
,則會改用"fprof.dump"
。此選項無法與stop
選項結合使用。append
- 使追蹤文字轉儲附加到目的地檔案。此選項僅允許與{dump, Dumpfile}
選項一起使用。start
- 啟動一個追蹤器進程,該進程會在執行階段分析追蹤資料。如果成功,則呼叫會立即傳回,傳回值為{ok, Tracer}
。此選項不允許與stop
、file
或{file, Filename}
選項一起使用。stop
- 停止在執行階段分析追蹤資料的追蹤器進程。如果成功,則傳回值將為值ok
。此選項無法與start
、file
或{file, Filename}
選項結合使用。
-spec start() -> {ok, Pid} | {error, {already_started, Pid}} when Pid :: pid().
啟動 fprof
伺服器。
請注意,由於伺服器會自動由任何需要它的函式啟動,因此很少需要直接呼叫此函式。
-spec stop() -> ok.
等同於 stop(normal)
。
-spec stop(Reason) -> ok when Reason :: term().
停止 fprof
伺服器。
提供的 Reason
會成為伺服器進程的結束原因。依預設,除了 kill
以外的任何 Reason
都會向伺服器發送請求,並等待伺服器清理、回覆和結束。如果 Reason
為 kill
,則會直接終止伺服器。
如果 fprof
伺服器未執行,則此函式會立即傳回。
注意
當
fprof
伺服器停止時,收集的原始分析資料將會遺失。
-spec trace(verbose) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when ServerPid :: pid(), Reason :: term(); (OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), ServerPid :: pid(), Reason :: term(); ({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), OptionValue :: term(), ServerPid :: pid(), Reason :: term(); (OptionList) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionList :: [Option], Option :: trace_option(), ServerPid :: pid(), Reason :: term().
啟動或停止追蹤。
如果 Arg
是原子 verbose
,則此呼叫等同於 trace([start, verbose])
。
如果 Arg
是原子,則此呼叫等同於 trace([Arg])
。
如果 Arg
是元組 {OptionName, OptionValue}
,則此呼叫等同於 trace([Arg])
。
否則,Arg
必須是 追蹤選項的列表。
PidSpec
和 Tracer
用於呼叫 erlang:trace(PidSpec, true, [{tracer, Tracer} | Flags])
,而 Filename
用於呼叫 dbg:trace_port(file, Filename)
。
選項描述
stop
- 停止正在執行的fprof
追蹤,並清除節點上的所有追蹤。必須指定選項stop
或start
其中一個,但不能同時指定兩者。start
- 清除節點上的所有追蹤,並開始新的fprof
追蹤。必須指定選項start
或stop
其中一個,但不能同時指定兩者。verbose
|{verbose, boolean()}
-verbose
或{verbose, true}
選項會加入一些fprof
不需要,但對一般除錯目的而言可能很有趣的追蹤旗標。這些選項僅允許與start
選項一起使用。cpu_time
|{cpu_time, boolean()}
-cpu_time
或{cpu_time, true}
選項會使追蹤中的時間戳記使用 CPU 時間,而不是預設的實際時間。這些選項僅允許與start
選項一起使用。注意
從
cpu_time
取得正確的值可能很困難。取得正確值的最佳方法是使用單一排程器執行,並將該排程器綁定到特定的 CPU。例如erl +S 1 +sbt db`
{procs, PidSpec}
|{procs, [PidSpec]}
- 指定應追蹤哪些進程。如果未指定此選項,則會追蹤呼叫進程。也會追蹤由被追蹤進程產生的所有進程。此選項僅允許與start
選項一起使用。file
|{file, Filename}
- 指定追蹤的檔案名稱。如果指定了選項file
,或未指定這些選項中的任何一個,則會使用檔案fprof.trace
。此選項僅允許與start
選項一起使用,但不能與{tracer, Tracer}
選項一起使用。{tracer, Tracer}
- 指定應執行追蹤至進程或埠,而不是追蹤至檔案。此選項僅允許與start
選項一起使用,但不能與{file, Filename}
選項一起使用。
-spec trace(start, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when Filename :: file:filename(), ServerPid :: pid(), Reason :: term(); (verbose, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when Filename :: file:filename(), ServerPid :: pid(), Reason :: term(); (OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason} when OptionName :: atom(), OptionValue :: term(), ServerPid :: pid(), Reason :: term().
啟動或停止追蹤。
如果 What
是原子 start
,則此呼叫等同於 trace([start, {file, Value}])
。
如果 What
是原子 verbose
,則此呼叫等同於 trace([start, verbose, {file, Value}])
。
如果 What
是一個元組 {OptionName, OptionValue}
,則此呼叫等同於 trace([What])
。