設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.47.1 → 2.52.0 無更改
-
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 可用於將除錯、效能和遙測資訊列印到 stderr 或檔案。Trace2 功能處於非活動狀態,除非透過啟用一個或多個 Trace2 目標來顯式啟用。
Trace2 API 旨在取代現有的(Trace1)printf() 風格的跟蹤,該跟蹤由現有的 GIT_TRACE 和 GIT_TRACE_PERFORMANCE 功能提供。在初始實現期間,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}
啟用目標
要啟用目標,請將相應的環境變數或系統/全域性配置值設定為以下之一:
-
0或false- 停用目標。 -
1或true- 寫入STDERR。 -
[
2-9] - 寫入已開啟的檔案描述符。 -
<absolute-pathname> - 以追加模式寫入檔案。如果目標已存在且為目錄,則跟蹤資訊將寫入給定目錄下的檔案(每個程序一個)。
-
af_unix:[<socket-type>:]<absolute-pathname> - 寫入 Unix 域套接字(在支援它們的平臺上)。套接字型別可以是stream或dgram;如果省略,Git 將嘗試兩者。
當跟蹤檔案寫入目標目錄時,它們將根據 SID 的最後一部分命名(可選後跟一個計數器以避免檔名衝突)。
Trace2 API
Trace2 公共 API 在 trace2.h 中定義和記錄;有關更多資訊,請參考它。所有公共函式和宏都以 trace2_ 作為字首,並在 trace2.c 中實現。
沒有公共 Trace2 資料結構。
Trace2 程式碼還在 trace2/ 目錄中定義了一組私有函式和資料型別。這些符號以 tr2_ 作為字首,應僅由 trace2.c(或 trace2/ 中的其他私有原始檔)中的函式使用。
Trace2 目標格式
普通格式
事件以以下形式的行寫入:
[<time> SP <filename>:<line> SP+] <event-name> [[SP] <event-message>] LF
如果 GIT_TRACE2_BRIEF 或 trace2.normalBrief 為 true,則會省略 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
- <depth>
-
是 git 程序深度。這是父 git 程序的數量。頂級 git 命令的深度值為“d0”。它的子程序深度值為“d1”。二級子程序深度值為“d2”依此類推。
- <thread-name>
-
是執行緒的唯一名稱。主執行緒稱為“main”。其他執行緒名稱的格式為“th%d:%s”,包括一個唯一的數字和執行緒程序的名稱。
- <event-name>
-
是事件名稱。
- <repo-id>
-
如果存在,是指示正在使用的儲存庫的數字。當儲存庫開啟時會發出
def_repo事件。這定義了 repo-id 和關聯的工作樹。後續的儲存庫特定事件將引用此 repo-id。目前,對於主儲存庫,這始終是“r1”。此欄位是為了將來支援程序內子模組而設的。
- <t_abs>
-
如果存在,表示程式啟動以來的絕對時間(以秒為單位)。
- <t_rel>
-
如果存在,表示相對於當前區域開始的時間(以秒為單位)。對於執行緒退出事件,它是執行緒的已用時間。
- <category>
-
存在於區域和資料事件上,用於指示一個廣泛的類別,例如“index”或“status”。
- <perf-event-message>
-
是一個供人類閱讀的自由格式
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 為 true,則會省略 time、file 和 line 欄位。
d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload
PERF 目標旨在用於開發過程中的互動式效能分析,並且會產生大量輸出。
事件格式
每個事件都是一個 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,
...
}
"event":<event>-
是事件名稱。
"sid":<sid>-
是會話 ID。這是一個唯一的字串,用於標識程序例項,以便可以識別程序發出的所有事件。使用會話 ID 而不是 PID,因為 PID 會被作業系統回收。對於子 git 程序,會話 ID 前面會加上父 git 程序的會話 ID,以便在後處理過程中識別父子關係。
"thread":<thread>-
是執行緒名稱。
"time":<time>-
是事件的 UTC 時間。
"file":<filename>-
是生成事件的原始檔。
"line":<line-number>-
是生成事件的整數源行號。
"repo":<repo-id>-
如果存在,是前面描述的整數 repo-id。
如果 GIT_TRACE2_EVENT_BRIEF 或 trace2.eventBrief 為 true,則從所有事件中省略 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 可以 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"-
當執行緒啟動時會生成此事件。它從新執行緒的執行緒程序(thread-proc)內部生成(因為它需要訪問該執行緒的執行緒區域性儲存中的資料)。
{ "event":"thread_start", ... "thread":"th02:preload_thread" # thread name } "thread_exit"-
當執行緒退出時會生成此事件。它從執行緒的執行緒程序(thread-proc)內部生成。
{ "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"-
此事件定義了一個 repo-id 並將其與工作樹的根關聯。
{ "event":"def_repo", ... "repo":1, "worktree":"/Users/jeffhost/work/gfw" }如前所述,repo-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 的 child[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); }在此示例中,preload_index() 由
main執行緒執行,並啟動了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
在此示例中,preload 區域花費了 0.009122 秒。7 個執行緒花費了 0.006069 到 0.008947 秒來處理它們在索引中的部分。執行緒“th01”處理了 508 個偏移量為 0 的項。執行緒“th02”處理了 508 個偏移量為 2032 的項。執行緒“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