設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.47.1 → 2.50.1 無更改
-
2.47.0
2024-10-06
- 2.44.1 → 2.46.4 無更改
-
2.44.0
2024-02-23
- 2.39.1 → 2.43.7 無更改
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 無更改
-
2.38.0
2022-10-02
- 2.37.1 → 2.37.7 無更改
-
2.37.0
2022-06-27
- 2.34.1 → 2.36.6 無更改
-
2.34.0
2021-11-15
- 2.33.1 → 2.33.8 無更改
-
2.33.0
2021-08-16
- 2.32.1 → 2.32.7 無變更
-
2.32.0
2021-06-06
- 2.30.1 → 2.31.8 無更改
-
2.30.0
2020-12-27
- 2.27.1 → 2.29.3 無更改
-
2.27.0
2020-06-01
- 2.25.1 → 2.26.3 無更改
- 2.25.0 無更改
- 2.24.1 → 2.24.4 無更改
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 無更改
-
2.23.0
2019-08-16
- 2.22.2 → 2.22.5 無更改
-
2.22.1
2019-08-11
-
2.22.0
2019-06-07
Trace2 API可用於將除錯、效能和遙測資訊列印到標準錯誤或檔案。除非透過啟用一個或多個Trace2目標明確啟用Trace2功能,否則該功能處於非活動狀態。
Trace2 API旨在取代現有(Trace1)由GIT_TRACE
和GIT_TRACE_PERFORMANCE
設施提供的printf
()式追蹤。在初始實現期間,Trace2和Trace1可以並行執行。
Trace2 API定義了一組帶有已知欄位的高階訊息,例如(start
: argv
)和(exit
: {exit-code
, elapsed-time
})。
Git程式碼庫中的Trace2檢測將Trace2訊息傳送到已啟用的Trace2目標。目標將這些訊息內容轉換為特定用途的格式,並將事件寫入其資料流。透過這種方式,Trace2 API可以驅動多種不同型別的分析。
目標是使用VTable定義的,允許未來輕鬆擴充套件到其他格式。例如,這可以用於定義二進位制格式。
Trace2透過系統和全域性配置檔案中的trace2.*
配置值以及GIT_TRACE2*
環境變數進行控制。Trace2不讀取倉庫本地或工作區配置檔案,也不遵守-c
命令列配置設定。
Trace2 目標
Trace2定義了以下Trace2目標集。格式詳情將在後續章節中給出。
普通格式目標
普通格式目標是傳統的printf
()格式,類似於GIT_TRACE
格式。此格式透過GIT_TRACE2
環境變數或trace2.normalTarget
系統或全域性配置設定啟用。
例如
$ export GIT_TRACE2=~/log.normal $ git version git version 2.20.1.155.g426c96fcdb
或
$ git config --global trace2.normalTarget ~/log.normal $ git version git version 2.20.1.155.g426c96fcdb
產生
$ cat ~/log.normal 12:28:42.620009 common-main.c:38 version 2.20.1.155.g426c96fcdb 12:28:42.620989 common-main.c:39 start git version 12:28:42.621101 git.c:432 cmd_name version (version) 12:28:42.621215 git.c:662 exit elapsed:0.001227 code:0 12:28:42.621250 trace2/tr2_tgt_normal.c:124 atexit elapsed:0.001265 code:0
效能格式目標
效能格式目標(PERF)是一種基於列的格式,用於取代GIT_TRACE_PERFORMANCE
,適用於開發和測試,可能作為gprof
等工具的補充。此格式透過GIT_TRACE2_PERF
環境變數或trace2.perfTarget
系統或全域性配置設定啟用。
例如
$ export GIT_TRACE2_PERF=~/log.perf $ git version git version 2.20.1.155.g426c96fcdb
或
$ git config --global trace2.perfTarget ~/log.perf $ git version git version 2.20.1.155.g426c96fcdb
產生
$ cat ~/log.perf 12:28:42.620675 common-main.c:38 | d0 | main | version | | | | | 2.20.1.155.g426c96fcdb 12:28:42.621001 common-main.c:39 | d0 | main | start | | 0.001173 | | | git version 12:28:42.621111 git.c:432 | d0 | main | cmd_name | | | | | version (version) 12:28:42.621225 git.c:662 | d0 | main | exit | | 0.001227 | | | code:0 12:28:42.621259 trace2/tr2_tgt_perf.c:211 | d0 | main | atexit | | 0.001265 | | | code:0
事件格式目標
事件格式目標是一種基於JSON的事件資料格式,適用於遙測分析。此格式透過GIT_TRACE2_EVENT
環境變數或trace2.eventTarget
系統或全域性配置設定啟用。
例如
$ export GIT_TRACE2_EVENT=~/log.event $ git version git version 2.20.1.155.g426c96fcdb
或
$ git config --global trace2.eventTarget ~/log.event $ git version git version 2.20.1.155.g426c96fcdb
產生
$ cat ~/log.event {"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"4","exe":"2.20.1.155.g426c96fcdb"} {"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]} {"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"} {"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0} {"event":"atexit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621268Z","file":"trace2/tr2_tgt_event.c","line":163,"t_abs":0.001265,"code":0}
Trace2 API
Trace2公共API在trace2.h
中定義並記錄;有關更多資訊,請參閱該檔案。所有公共函式和宏都以trace2_
為字首,並在trace2.c
中實現。
沒有公共的Trace2資料結構。
Trace2程式碼還在trace2/
目錄中定義了一組私有函式和資料型別。這些符號以tr2_
為字首,並且只能由trace2.c
中的函式(或trace2/
中的其他私有原始檔)使用。
Trace2 目標格式
NORMAL 格式
事件以以下形式的行寫入:
[<time> SP <filename>:<line> SP+] <event-name> [[SP] <event-message>] LF
如果GIT_TRACE2_BRIEF
或trace2.normalBrief
為真,則time
、filename
和line
欄位將被省略。
此目標旨在提供更多摘要(如GIT_TRACE),並且比其他目標細節更少。例如,它忽略執行緒、區域和資料訊息。
PERF 格式
事件以以下形式的行寫入:
[<time> SP <filename>:<line> SP+ BAR SP] d<depth> SP BAR SP <thread-name> SP+ BAR SP <event-name> SP+ BAR SP [r<repo-id>] SP+ BAR SP [<t_abs>] SP+ BAR SP [<t_rel>] SP+ BAR SP [<category>] SP+ BAR SP DOTS* <perf-event-message> LF
- <深度>
-
是git程序的深度。這是父git程序的數量。頂層git命令的深度值為“d0”。其子程序的深度值為“d1”。二級子程序的深度值為“d2”,依此類推。
- <執行緒名>
-
是執行緒的唯一名稱。主執行緒稱為“main”。其他執行緒名稱的形式為“th%d:%s”,包括一個唯一的數字和執行緒過程的名稱。
- <事件名>
-
是事件名。
- <倉庫ID>
-
如果存在,是一個表示正在使用的倉庫的數字。當開啟倉庫時,會發出
def_repo
事件。這定義了倉庫ID和關聯的工作區。隨後的倉庫特定事件將引用此倉庫ID。目前,主倉庫始終是“r1”。此欄位是為未來程序內子模組預期的。
- <絕對時間>
-
如果存在,是程式啟動以來的絕對時間(秒)。
- <相對時間>
-
如果存在,是相對於當前區域開始的時間(秒)。對於執行緒退出事件,它是執行緒的已用時間。
- <類別>
-
存在於區域和資料事件上,用於指示一個廣泛的類別,例如“index”或“status”。
- <效能事件訊息>
-
是自由形式的
printf
()訊息,旨在供人類閱讀。
15:33:33.532712 wt-status.c:2310 | d0 | main | region_enter | r1 | 0.126064 | | status | label:print 15:33:33.532712 wt-status.c:2331 | d0 | main | region_leave | r1 | 0.127568 | 0.001504 | status | label:print
如果GIT_TRACE2_PERF_BRIEF
或trace2.perfBrief
為真,則time
、file
和line
欄位將被省略。
d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload
PERF目標用於開發期間的互動式效能分析,並且相當“嘈雜”。
EVENT 格式
每個事件都是一個JSON物件,包含多個鍵/值對,以單行寫入,後跟一個換行符(LF)。
'{' <key> ':' <value> [',' <key> ':' <value>]* '}' LF
一些鍵/值對是所有事件通用的,有些是事件特定的。
通用鍵/值對
以下鍵/值對是所有事件通用的
{ "event":"version", "sid":"20190408T191827.272759Z-H9b68c35f-P00003510", "thread":"main", "time":"2019-04-08T19:18:27.282761Z", "file":"common-main.c", "line":42, ... }
如果GIT_TRACE2_EVENT_BRIEF
或trace2.eventBrief
為真,則所有事件中都省略file
和line
欄位,並且time
欄位僅存在於“start”和“atexit”事件上。
事件特定鍵/值對
"version"
-
此事件提供可執行檔案的版本和EVENT格式。它應該始終是追蹤會話中的第一個事件。如果添加了新的事件型別,移除了現有欄位,或現有事件或欄位的解釋發生重大變化,則EVENT格式版本將增加。較小的更改,例如向現有事件新增新欄位,不需要增加EVENT格式版本。
{ "event":"version", ... "evt":"4", # EVENT format version "exe":"2.20.1.155.g426c96fcdb" # git version }
"too_many_files"
-
如果目標追蹤目錄中的檔案過多(請參閱trace2.maxFiles配置選項),此事件將寫入到git-trace2-discard哨兵檔案。
{ "event":"too_many_files", ... }
"start"
-
此事件包含main()接收到的完整argv。
{ "event":"start", ... "t_abs":0.001227, # elapsed time in seconds "argv":["git","version"] }
"exit"
-
當git呼叫
exit
()時,會發出此事件。{ "event":"exit", ... "t_abs":0.001227, # elapsed time in seconds "code":0 # exit code }
"atexit"
-
此事件由Trace2的
atexit
例程在最終關閉期間發出。它應該是程序發出的最後一個事件。(此處報告的已用時間比“exit”事件中報告的時間要長,因為它在所有其他atexit任務完成後執行。)
{ "event":"atexit", ... "t_abs":0.001227, # elapsed time in seconds "code":0 # exit code }
"signal"
-
當程式被使用者訊號終止時,會發出此事件。根據平臺的不同,訊號事件可能會阻止“atexit”事件的生成。
{ "event":"signal", ... "t_abs":0.001227, # elapsed time in seconds "signo":13 # SIGTERM, SIGINT, etc. }
"error"
-
當呼叫
BUG
()、bug
()、error
()、die
()、warning
()或usage
()函式時,會發出此事件。{ "event":"error", ... "msg":"invalid option: --cahced", # formatted error message "fmt":"invalid option: %s" # error format string }
錯誤事件可能會多次發出。格式字串允許後處理器根據型別對錯誤進行分組,而無需擔心特定的錯誤引數。
"cmd_path"
-
此事件包含已發現的git可執行檔案的完整路徑(在配置為解析此路徑的平臺上)。
{ "event":"cmd_path", ... "path":"C:/work/gfw/git.exe" }
"cmd_ancestry"
-
此事件包含當前程序的父級(以及更早世代的父級)的文字命令名稱,以陣列形式按從最近的父級到最遠的曾祖父的順序排列。它可能未在所有平臺上實現。
{ "event":"cmd_ancestry", ... "ancestry":["bash","tmux: server","systemd"] }
"cmd_name"
-
此事件包含此git程序的命令名稱以及來自父git程序的命令層次結構。
{ "event":"cmd_name", ... "name":"pack-objects", "hierarchy":"push/pack-objects" }
通常,“name”欄位包含命令的規範名稱。當規範名稱不可用時,使用以下特殊值之一:
"_query_" # "git --html-path" "_run_dashed_" # when "git foo" tries to run "git-foo" "_run_shell_alias_" # alias expansion to a shell command "_run_git_alias_" # alias expansion to a git command "_usage_" # usage error
"cmd_mode"
-
此事件(如果存在)描述命令變體。此事件可能會多次發出。
{ "event":"cmd_mode", ... "name":"branch" }
“name”欄位是一個任意字串,用於描述命令模式。例如,checkout可以檢出一個分支或一個單獨的檔案。這些變體通常具有不同的效能特徵,不可比較。
"alias"
-
當別名被展開時,此事件會存在。
{ "event":"alias", ... "alias":"l", # registered alias "argv":["log","--graph"] # alias expansion }
"child_start"
-
此事件描述即將派生的子程序。
{ "event":"child_start", ... "child_id":2, "child_class":"?", "use_shell":false, "argv":["git","rev-list","--objects","--stdin","--not","--all","--quiet"] "hook_name":"<hook_name>" # present when child_class is "hook" "cd":"<path>" # present when cd is required }
“child_id”欄位可用於將此child_start與相應的child_exit事件匹配。
“child_class”欄位是一個粗略的分類,例如“editor”、“pager”、“transport/*”和“hook”。未分類的子級歸類為“?”。
"child_exit"
-
此事件在當前程序從
waitpid
()返回並收集到子程序的退出資訊後生成。{ "event":"child_exit", ... "child_id":2, "pid":14708, # child PID "code":0, # child exit-code "t_rel":0.110605 # observed run-time of child process }
請注意,子程序的會話ID對於當前/生成程序不可用,因此此處報告子程序的PID作為後處理的提示。(但這只是一個提示,因為子程序可能是沒有會話ID的shell指令碼。)
請注意,
t_rel
欄位包含子程序觀察到的執行時間(秒)(從fork/exec/spawn之前開始,在waitpid
()之後停止,幷包括作業系統程序建立開銷)。因此,此時間將略大於子程序本身報告的atexit時間。 "child_ready"
-
此事件在當前程序啟動後臺程序並釋放其所有控制代碼後生成。
{ "event":"child_ready", ... "child_id":2, "pid":14708, # child PID "ready":"ready", # child ready state "t_rel":0.110605 # observed run-time of child process }
請注意,子程序的會話ID對於當前/生成程序不可用,因此此處報告子程序的PID作為後處理的提示。(但這只是一個提示,因為子程序可能是沒有會話ID的shell指令碼。)
此事件在子程序在後臺啟動並獲得少量時間啟動和開始工作後生成。如果子程序正常啟動而父程序仍在等待,“ready”欄位將具有值“ready”。如果子程序啟動太慢且父程序超時,該欄位將具有值“timeout”。如果子程序啟動但父程序無法探測它,該欄位將具有值“error”。
在父程序發出此事件後,它將釋放其所有對子程序的控制代碼,並將子程序視為後臺守護程序。因此,即使子程序最終完成啟動,父程序也不會發出更新的事件。
請注意,
t_rel
欄位包含父程序將子程序釋放到後臺時的觀察到的執行時間(秒)。子程序被假定為長時間執行的守護程序,並且可能比父程序存活更長時間。因此,父程序的子事件時間不應與子程序的atexit時間進行比較。 "exec"
-
此事件在git嘗試
exec
()另一個命令而不是啟動子程序之前生成。{ "event":"exec", ... "exec_id":0, "exe":"git", "argv":["foo", "bar"] }
“exec_id”欄位是命令唯一的ID,僅在
exec
()失敗並生成相應的exec_result事件時有用。 "exec_result"
-
如果
exec
()失敗且控制返回到當前git命令,則會生成此事件。{ "event":"exec_result", ... "exec_id":0, "code":1 # error code (errno) from exec() }
"thread_start"
-
此事件線上程啟動時生成。它從新執行緒的執行緒過程中內部生成(因為它需要訪問執行緒的執行緒本地儲存中的資料)。
{ "event":"thread_start", ... "thread":"th02:preload_thread" # thread name }
"thread_exit"
-
此事件線上程退出時生成。它從執行緒的執行緒過程中內部生成。
{ "event":"thread_exit", ... "thread":"th02:preload_thread", # thread name "t_rel":0.007328 # thread elapsed time }
"def_param"
-
生成此事件以記錄全域性引數,例如配置設定、命令列標誌或環境變數。
{ "event":"def_param", ... "scope":"global", "param":"core.abbrev", "value":"7" }
"def_repo"
-
此事件定義了一個倉庫ID並將其與工作樹的根目錄關聯。
{ "event":"def_repo", ... "repo":1, "worktree":"/Users/jeffhost/work/gfw" }
如前所述,倉庫ID目前始終為1,因此只會有一個def_repo事件。之後,如果支援程序內子模組,則每個訪問的子模組都應發出一個def_repo事件。
"region_enter"
-
此事件在進入區域時生成。
{ "event":"region_enter", ... "repo":1, # optional "nesting":1, # current region stack depth "category":"index", # optional "label":"do_read_index", # optional "msg":".git/index" # optional }
category
欄位可在未來增強中用於基於類別的過濾。GIT_TRACE2_EVENT_NESTING
或trace2.eventNesting
可用於過濾深度巢狀的區域和資料事件。它預設為“2”。 "region_leave"
-
此事件在離開區域時生成。
{ "event":"region_leave", ... "repo":1, # optional "t_rel":0.002876, # time spent in region in seconds "nesting":1, # region stack depth "category":"index", # optional "label":"do_read_index", # optional "msg":".git/index" # optional }
"data"
-
此事件用於記錄執行緒和區域本地的鍵/值對。
{ "event":"data", ... "repo":1, # optional "t_abs":0.024107, # absolute elapsed time "t_rel":0.001031, # elapsed time in region/thread "nesting":2, # region stack depth "category":"index", "key":"read/cache_nr", "value":"3552" }
“value”欄位可以是整數或字串。
"data-json"
-
此事件用於記錄包含結構化資料的預格式化JSON字串。
{ "event":"data_json", ... "repo":1, # optional "t_abs":0.015905, "t_rel":0.015905, "nesting":1, "category":"process", "key":"windows/ancestry", "value":["bash.exe","bash.exe"] }
"th_timer"
-
此事件記錄秒錶計時器線上程中執行的時間量。當執行緒退出時,會為請求每執行緒事件的計時器生成此事件。
{ "event":"th_timer", ... "category":"my_category", "name":"my_timer", "intervals":5, # number of time it was started/stopped "t_total":0.052741, # total time in seconds it was running "t_min":0.010061, # shortest interval "t_max":0.011648 # longest interval }
"timer"
-
此事件記錄秒錶計時器在所有執行緒中聚合執行的時間量。此事件在程序退出時生成。
{ "event":"timer", ... "category":"my_category", "name":"my_timer", "intervals":5, # number of time it was started/stopped "t_total":0.052741, # total time in seconds it was running "t_min":0.010061, # shortest interval "t_max":0.011648 # longest interval }
"th_counter"
-
此事件記錄執行緒中計數器變數的值。當執行緒退出時,會為請求每執行緒事件的計數器生成此事件。
{ "event":"th_counter", ... "category":"my_category", "name":"my_counter", "count":23 }
"counter"
-
此事件記錄所有執行緒中計數器變數的值。此事件在程序退出時生成。此處報告的總值是所有執行緒的總和。
{ "event":"counter", ... "category":"my_category", "name":"my_counter", "count":23 }
"printf"
-
此事件記錄人類可讀的訊息,沒有特定的格式指南。
{ "event":"printf", ... "t_abs":0.015905, # elapsed time in seconds "msg":"Hello world" # optional }
Trace2 API 使用示例
以下是一個假想的Trace2 API使用示例,展示了預期的用法(不涉及實際的Git細節)。
- 初始化
-
初始化發生在
main
()中。在幕後,會註冊一個atexit
和signal
處理程式。int main(int argc, const char **argv) { int exit_code; trace2_initialize(); trace2_cmd_start(argv); exit_code = cmd_main(argc, argv); trace2_cmd_exit(exit_code); return exit_code; }
- 命令詳情
-
在基本資訊建立後,可以將被發現的額外命令資訊傳送到Trace2。
int cmd_checkout(int argc, const char **argv) { trace2_cmd_name("checkout"); trace2_cmd_mode("branch"); trace2_def_repo(the_repository); // emit "def_param" messages for "interesting" config settings. trace2_cmd_list_config(); if (do_something()) trace2_cmd_error("Path '%s': cannot do something", path); return 0; }
- 子程序
-
包裝生成子程序的程式碼。
void run_child(...) { int child_exit_code; struct child_process cmd = CHILD_PROCESS_INIT; ... cmd.trace2_child_class = "editor"; trace2_child_start(&cmd); child_exit_code = spawn_child_and_wait_for_it(); trace2_child_exit(&cmd, child_exit_code); }
例如,以下fetch命令生成了ssh、index-pack、rev-list和gc。此示例還顯示fetch花費了5.199秒,其中4.932秒在ssh中。
$ export GIT_TRACE2_BRIEF=1 $ export GIT_TRACE2=~/log.normal $ git fetch origin ...
$ cat ~/log.normal version 2.20.1.vfs.1.1.47.g534dbe1ad1 start git fetch origin worktree /Users/jeffhost/work/gfw cmd_name fetch (fetch) child_start[0] ssh git@github.com ... child_start[1] git index-pack ... ... (Trace2 events from child processes omitted) child_exit[1] pid:14707 code:0 elapsed:0.076353 child_exit[0] pid:14706 code:0 elapsed:4.931869 child_start[2] git rev-list ... ... (Trace2 events from child process omitted) child_exit[2] pid:14708 code:0 elapsed:0.110605 child_start[3] git gc --auto ... (Trace2 events from child process omitted) child_exit[3] pid:14709 code:0 elapsed:0.006240 exit elapsed:5.198503 code:0 atexit elapsed:5.198541 code:0
當一個git程序是另一個git程序的(直接或間接)子程序時,它會繼承Trace2上下文資訊。這允許子程序列印命令層次結構。此示例顯示gc是fetch的子程序[3]。當gc程序將其名稱報告為“gc”時,它還會將層次結構報告為“fetch/gc”。(在此示例中,為了清晰起見,子程序的trace2訊息已縮排。)
$ export GIT_TRACE2_BRIEF=1 $ export GIT_TRACE2=~/log.normal $ git fetch origin ...
$ cat ~/log.normal version 2.20.1.160.g5676107ecd.dirty start git fetch official worktree /Users/jeffhost/work/gfw cmd_name fetch (fetch) ... child_start[3] git gc --auto version 2.20.1.160.g5676107ecd.dirty start /Users/jeffhost/work/gfw/git gc --auto worktree /Users/jeffhost/work/gfw cmd_name gc (fetch/gc) exit elapsed:0.001959 code:0 atexit elapsed:0.001997 code:0 child_exit[3] pid:20303 code:0 elapsed:0.007564 exit elapsed:3.868938 code:0 atexit elapsed:3.868970 code:0
- 區域
-
區域可用於計時程式碼的有趣部分。
void wt_status_collect(struct wt_status *s) { trace2_region_enter("status", "worktrees", s->repo); wt_status_collect_changes_worktree(s); trace2_region_leave("status", "worktrees", s->repo); trace2_region_enter("status", "index", s->repo); wt_status_collect_changes_index(s); trace2_region_leave("status", "index", s->repo); trace2_region_enter("status", "untracked", s->repo); wt_status_collect_untracked(s); trace2_region_leave("status", "untracked", s->repo); } void wt_status_print(struct wt_status *s) { trace2_region_enter("status", "print", s->repo); switch (s->status_format) { ... } trace2_region_leave("status", "print", s->repo); }
在此示例中,掃描未跟蹤檔案從+0.012568執行到+0.027149(自程序啟動以來),耗時0.014581秒。
$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ git status ... $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.160.g5676107ecd.dirty d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) ... d0 | main | region_enter | r1 | 0.010988 | | status | label:worktrees d0 | main | region_leave | r1 | 0.011236 | 0.000248 | status | label:worktrees d0 | main | region_enter | r1 | 0.011260 | | status | label:index d0 | main | region_leave | r1 | 0.012542 | 0.001282 | status | label:index d0 | main | region_enter | r1 | 0.012568 | | status | label:untracked d0 | main | region_leave | r1 | 0.027149 | 0.014581 | status | label:untracked d0 | main | region_enter | r1 | 0.027411 | | status | label:print d0 | main | region_leave | r1 | 0.028741 | 0.001330 | status | label:print d0 | main | exit | | 0.028778 | | | code:0 d0 | main | atexit | | 0.028809 | | | code:0
區域可以巢狀。這會導致訊息在PERF目標中縮排,例如。已用時間相對於相應巢狀級別的開始時間,正如預期。例如,如果我們向以下內容新增區域訊息:
static enum path_treatment read_directory_recursive(struct dir_struct *dir, struct index_state *istate, const char *base, int baselen, struct untracked_cache_dir *untracked, int check_only, int stop_at_first_file, const struct pathspec *pathspec) { enum path_treatment state, subdir_state, dir_state = path_none; trace2_region_enter_printf("dir", "read_recursive", NULL, "%.*s", baselen, base); ... trace2_region_leave_printf("dir", "read_recursive", NULL, "%.*s", baselen, base); return dir_state; }
我們可以進一步調查掃描未跟蹤檔案所花費的時間。
$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ git status ... $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.162.gb4ccea44db.dirty d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) ... d0 | main | region_enter | r1 | 0.015047 | | status | label:untracked d0 | main | region_enter | | 0.015132 | | dir | ..label:read_recursive d0 | main | region_enter | | 0.016341 | | dir | ....label:read_recursive vcs-svn/ d0 | main | region_leave | | 0.016422 | 0.000081 | dir | ....label:read_recursive vcs-svn/ d0 | main | region_enter | | 0.016446 | | dir | ....label:read_recursive xdiff/ d0 | main | region_leave | | 0.016522 | 0.000076 | dir | ....label:read_recursive xdiff/ d0 | main | region_enter | | 0.016612 | | dir | ....label:read_recursive git-gui/ d0 | main | region_enter | | 0.016698 | | dir | ......label:read_recursive git-gui/po/ d0 | main | region_enter | | 0.016810 | | dir | ........label:read_recursive git-gui/po/glossary/ d0 | main | region_leave | | 0.016863 | 0.000053 | dir | ........label:read_recursive git-gui/po/glossary/ ... d0 | main | region_enter | | 0.031876 | | dir | ....label:read_recursive builtin/ d0 | main | region_leave | | 0.032270 | 0.000394 | dir | ....label:read_recursive builtin/ d0 | main | region_leave | | 0.032414 | 0.017282 | dir | ..label:read_recursive d0 | main | region_leave | r1 | 0.032454 | 0.017407 | status | label:untracked ... d0 | main | exit | | 0.034279 | | | code:0 d0 | main | atexit | | 0.034322 | | | code:0
Trace2區域類似於現有的trace_performance_enter()和trace_performance_leave()例程,但它們是執行緒安全的並維護每執行緒的計時器堆疊。
- 資料訊息
-
新增到區域的資料訊息。
int read_index_from(struct index_state *istate, const char *path, const char *gitdir) { trace2_region_enter_printf("index", "do_read_index", the_repository, "%s", path); ... trace2_data_intmax("index", the_repository, "read/version", istate->version); trace2_data_intmax("index", the_repository, "read/cache_nr", istate->cache_nr); trace2_region_leave_printf("index", "do_read_index", the_repository, "%s", path); }
此示例顯示索引包含3552個條目。
$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ git status ... $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.156.gf9916ae094.dirty d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) d0 | main | region_enter | r1 | 0.001791 | | index | label:do_read_index .git/index d0 | main | data | r1 | 0.002494 | 0.000703 | index | ..read/version:2 d0 | main | data | r1 | 0.002520 | 0.000729 | index | ..read/cache_nr:3552 d0 | main | region_leave | r1 | 0.002539 | 0.000748 | index | label:do_read_index .git/index ...
- 執行緒事件
-
新增到執行緒過程的執行緒訊息。
例如,多執行緒的preload-index程式碼可以透過圍繞執行緒池的區域進行檢測,然後線上程過程中進行每執行緒的啟動和退出事件。
static void *preload_thread(void *_data) { // start the per-thread clock and emit a message. trace2_thread_start("preload_thread"); // report which chunk of the array this thread was assigned. trace2_data_intmax("index", the_repository, "offset", p->offset); trace2_data_intmax("index", the_repository, "count", nr); do { ... } while (--nr > 0); ... // report elapsed time taken by this thread. trace2_thread_exit(); return NULL; } void preload_index(struct index_state *index, const struct pathspec *pathspec, unsigned int refresh_flags) { trace2_region_enter("index", "preload", the_repository); for (i = 0; i < threads; i++) { ... /* create thread */ } for (i = 0; i < threads; i++) { ... /* join thread */ } trace2_region_leave("index", "preload", the_repository); }
在此示例中,
main
執行緒執行了preload_index()並啟動了preload
區域。啟動了七個執行緒,命名為th01:preload_thread
到th07:preload_thread
。來自每個執行緒的事件在發生時會自動追加到共享目標流中,因此它們可能以隨機順序與其他執行緒一起出現。最後,主執行緒等待執行緒完成並離開區域。資料事件使用活動執行緒名稱進行標記。它們用於報告每執行緒引數。
$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ git status ... $ cat ~/log.perf ... d0 | main | region_enter | r1 | 0.002595 | | index | label:preload d0 | th01:preload_thread | thread_start | | 0.002699 | | | d0 | th02:preload_thread | thread_start | | 0.002721 | | | d0 | th01:preload_thread | data | r1 | 0.002736 | 0.000037 | index | offset:0 d0 | th02:preload_thread | data | r1 | 0.002751 | 0.000030 | index | offset:2032 d0 | th03:preload_thread | thread_start | | 0.002711 | | | d0 | th06:preload_thread | thread_start | | 0.002739 | | | d0 | th01:preload_thread | data | r1 | 0.002766 | 0.000067 | index | count:508 d0 | th06:preload_thread | data | r1 | 0.002856 | 0.000117 | index | offset:2540 d0 | th03:preload_thread | data | r1 | 0.002824 | 0.000113 | index | offset:1016 d0 | th04:preload_thread | thread_start | | 0.002710 | | | d0 | th02:preload_thread | data | r1 | 0.002779 | 0.000058 | index | count:508 d0 | th06:preload_thread | data | r1 | 0.002966 | 0.000227 | index | count:508 d0 | th07:preload_thread | thread_start | | 0.002741 | | | d0 | th07:preload_thread | data | r1 | 0.003017 | 0.000276 | index | offset:3048 d0 | th05:preload_thread | thread_start | | 0.002712 | | | d0 | th05:preload_thread | data | r1 | 0.003067 | 0.000355 | index | offset:1524 d0 | th05:preload_thread | data | r1 | 0.003090 | 0.000378 | index | count:508 d0 | th07:preload_thread | data | r1 | 0.003037 | 0.000296 | index | count:504 d0 | th03:preload_thread | data | r1 | 0.002971 | 0.000260 | index | count:508 d0 | th04:preload_thread | data | r1 | 0.002983 | 0.000273 | index | offset:508 d0 | th04:preload_thread | data | r1 | 0.007311 | 0.004601 | index | count:508 d0 | th05:preload_thread | thread_exit | | 0.008781 | 0.006069 | | d0 | th01:preload_thread | thread_exit | | 0.009561 | 0.006862 | | d0 | th03:preload_thread | thread_exit | | 0.009742 | 0.007031 | | d0 | th06:preload_thread | thread_exit | | 0.009820 | 0.007081 | | d0 | th02:preload_thread | thread_exit | | 0.010274 | 0.007553 | | d0 | th07:preload_thread | thread_exit | | 0.010477 | 0.007736 | | d0 | th04:preload_thread | thread_exit | | 0.011657 | 0.008947 | | d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload ... d0 | main | exit | | 0.029996 | | | code:0 d0 | main | atexit | | 0.030027 | | | code:0
在此示例中,預載入區域耗時0.009122秒。這7個執行緒在索引的各自部分上花費了0.006069到0.008947秒。執行緒“th01”處理了從偏移量0開始的508個專案。執行緒“th02”處理了從偏移量2032開始的508個專案。執行緒“th04”處理了從偏移量508開始的508個專案。
此示例還顯示,執行緒名稱在每個執行緒啟動時以競爭方式分配。
- 配置(def param)事件
-
將“有趣的”配置值轉儲到trace2日誌中。
我們可以選擇性地發出配置事件,請參閱git-config[1]中的
trace2.configparams
瞭解如何啟用它。$ git config --system color.ui never $ git config --global color.ui always $ git config --local color.ui auto $ git config --list --show-scope | grep 'color.ui' system color.ui=never global color.ui=always local color.ui=auto
然後,使用
GIT_TRACE2_CONFIG_PARAMS
將配置color.ui
標記為“有趣的”配置$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ export GIT_TRACE2_CONFIG_PARAMS=color.ui $ git version ... $ cat ~/log.perf d0 | main | version | | | | | ... d0 | main | start | | 0.001642 | | | /usr/local/bin/git version d0 | main | cmd_name | | | | | version (version) d0 | main | def_param | | | | scope:system | color.ui:never d0 | main | def_param | | | | scope:global | color.ui:always d0 | main | def_param | | | | scope:local | color.ui:auto d0 | main | data | r0 | 0.002100 | 0.002100 | fsync | fsync/writeout-only:0 d0 | main | data | r0 | 0.002126 | 0.002126 | fsync | fsync/hardware-flush:0 d0 | main | exit | | 0.000470 | | | code:0 d0 | main | atexit | | 0.000477 | | | code:0
- 秒錶計時器事件
-
測量函式呼叫或程式碼段中花費的時間量,這些程式碼段可能在程序的整個生命週期中從程式碼中的許多地方呼叫。
static void expensive_function(void) { trace2_timer_start(TRACE2_TIMER_ID_TEST1); ... sleep_millisec(1000); // Do something expensive ... trace2_timer_stop(TRACE2_TIMER_ID_TEST1); } static int ut_100timer(int argc, const char **argv) { ... expensive_function(); // Do something else 1... expensive_function(); // Do something else 2... expensive_function(); return 0; }
在此示例中,我們測量了
expensive_function
()中花費的總時間,無論它在程式整體流程中的何時被呼叫。$ export GIT_TRACE2_PERF_BRIEF=1 $ export GIT_TRACE2_PERF=~/log.perf $ t/helper/test-tool trace2 100timer 3 1000 ... $ cat ~/log.perf d0 | main | version | | | | | ... d0 | main | start | | 0.001453 | | | t/helper/test-tool trace2 100timer 3 1000 d0 | main | cmd_name | | | | | trace2 (trace2) d0 | main | exit | | 3.003667 | | | code:0 d0 | main | timer | | | | test | name:test1 intervals:3 total:3.001686 min:1.000254 max:1.000929 d0 | main | atexit | | 3.003796 | | | code:0