1= Trace2 API 2 3The Trace2 API can be used to print debug, performance, and telemetry 4information to stderr or a file. The Trace2 feature is inactive unless 5explicitly enabled by enabling one or more Trace2 Targets. 6 7The Trace2 API is intended to replace the existing (Trace1) 8printf-style tracing provided by the existing `GIT_TRACE` and 9`GIT_TRACE_PERFORMANCE` facilities. During initial implementation, 10Trace2 and Trace1 may operate in parallel. 11 12The Trace2 API defines a set of high-level messages with known fields, 13such as (`start`: `argv`) and (`exit`: {`exit-code`, `elapsed-time`}). 14 15Trace2 instrumentation throughout the Git code base sends Trace2 16messages to the enabled Trace2 Targets. Targets transform these 17messages content into purpose-specific formats and write events to 18their data streams. In this manner, the Trace2 API can drive 19many different types of analysis. 20 21Targets are defined using a VTable allowing easy extension to other 22formats in the future. This might be used to define a binary format, 23for example. 24 25Trace2 is controlled using `trace2.*` config values in the system and 26global config files and `GIT_TR2*` environment variables. Trace2 does 27not read from repo local or worktree config files or respect `-c` 28command line config settings. 29 30== Trace2 Targets 31 32Trace2 defines the following set of Trace2 Targets. 33Format details are given in a later section. 34 35=== The Normal Format Target 36 37The normal format target is a tradition printf format and similar 38to GIT_TRACE format. This format is enabled with the `GIT_TR` 39environment variable or the `trace2.normalTarget` system or global 40config setting. 41 42For example 43 44------------ 45$ export GIT_TR2=~/log.normal 46$ git version 47git version 2.20.1.155.g426c96fcdb 48------------ 49 50or 51 52------------ 53$ git config --global trace2.normalTarget ~/log.normal 54$ git version 55git version 2.20.1.155.g426c96fcdb 56------------ 57 58yields 59 60------------ 61$ cat ~/log.normal 6212:28:42.620009 common-main.c:38 version 2.20.1.155.g426c96fcdb 6312:28:42.620989 common-main.c:39 start git version 6412:28:42.621101 git.c:432 cmd_name version (version) 6512:28:42.621215 git.c:662 exit elapsed:0.001227 code:0 6612:28:42.621250 trace2/tr2_tgt_normal.c:124 atexit elapsed:0.001265 code:0 67------------ 68 69=== The Performance Format Target 70 71The performance format target (PERF) is a column-based format to 72replace GIT_TRACE_PERFORMANCE and is suitable for development and 73testing, possibly to complement tools like gprof. This format is 74enabled with the `GIT_TR2_PERF` environment variable or the 75`trace2.perfTarget` system or global config setting. 76 77For example 78 79------------ 80$ export GIT_TR2_PERF=~/log.perf 81$ git version 82git version 2.20.1.155.g426c96fcdb 83------------ 84 85or 86 87------------ 88$ git config --global trace2.perfTarget ~/log.perf 89$ git version 90git version 2.20.1.155.g426c96fcdb 91------------ 92 93yields 94 95------------ 96$ cat ~/log.perf 9712:28:42.620675 common-main.c:38 | d0 | main | version | | | | | 2.20.1.155.g426c96fcdb 9812:28:42.621001 common-main.c:39 | d0 | main | start | | 0.001173 | | | git version 9912:28:42.621111 git.c:432 | d0 | main | cmd_name | | | | | version (version) 10012:28:42.621225 git.c:662 | d0 | main | exit | | 0.001227 | | | code:0 10112:28:42.621259 trace2/tr2_tgt_perf.c:211 | d0 | main | atexit | | 0.001265 | | | code:0 102------------ 103 104=== The Event Format Target 105 106The event format target is a JSON-based format of event data suitable 107for telemetry analysis. This format is enabled with the `GIT_TR2_EVENT` 108environment variable or the `trace2.eventTarget` system or global config 109setting. 110 111For example 112 113------------ 114$ export GIT_TR2_EVENT=~/log.event 115$ git version 116git version 2.20.1.155.g426c96fcdb 117------------ 118 119or 120 121------------ 122$ git config --global trace2.eventTarget ~/log.event 123$ git version 124git version 2.20.1.155.g426c96fcdb 125------------ 126 127yields 128 129------------ 130$ cat ~/log.event 131{"event":"version","sid":"sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"1","exe":"2.20.1.155.g426c96fcdb"} 132{"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"]} 133{"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"} 134{"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} 135{"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} 136------------ 137 138=== Enabling a Target 139 140To enable a target, set the corresponding environment variable or 141system or global config value to one of the following: 142 143include::../trace2-target-values.txt[] 144 145== Trace2 API 146 147All public Trace2 functions and macros are defined in `trace2.h` and 148`trace2.c`. All public symbols are prefixed with `trace2_`. 149 150There are no public Trace2 data structures. 151 152The Trace2 code also defines a set of private functions and data types 153in the `trace2/` directory. These symbols are prefixed with `tr2_` 154and should only be used by functions in `trace2.c`. 155 156== Conventions for Public Functions and Macros 157 158The functions defined by the Trace2 API are declared and documented 159in `trace2.h`. It defines the API functions and wrapper macros for 160Trace2. 161 162Some functions have a `_fl()` suffix to indicate that they take `file` 163and `line-number` arguments. 164 165Some functions have a `_va_fl()` suffix to indicate that they also 166take a `va_list` argument. 167 168Some functions have a `_printf_fl()` suffix to indicate that they also 169take a varargs argument. 170 171There are CPP wrapper macros and ifdefs to hide most of these details. 172See `trace2.h` for more details. The following discussion will only 173describe the simplified forms. 174 175== Public API 176 177All Trace2 API functions send a messsage to all of the active 178Trace2 Targets. This section describes the set of available 179messages. 180 181It helps to divide these functions into groups for discussion 182purposes. 183 184=== Basic Command Messages 185 186These are concerned with the lifetime of the overall git process. 187 188`void trace2_initialize_clock()`:: 189 190 Initialize the Trace2 start clock and nothing else. This should 191 be called at the very top of main() to capture the process start 192 time and reduce startup order dependencies. 193 194`void trace2_initialize()`:: 195 196 Determines if any Trace2 Targets should be enabled and 197 initializes the Trace2 facility. This includes setting up the 198 Trace2 thread local storage (TLS). 199+ 200This function emits a "version" message containing the version of git 201and the Trace2 protocol. 202+ 203This function should be called from `main()` as early as possible in 204the life of the process after essential process initialization. 205 206`int trace2_is_enabled()`:: 207 208 Returns 1 if Trace2 is enabled (at least one target is 209 active). 210 211`void trace2_cmd_start(int argc, const char **argv)`:: 212 213 Emits a "start" message containing the process command line 214 arguments. 215 216`int trace2_cmd_exit(int exit_code)`:: 217 218 Emits an "exit" message containing the process exit-code and 219 elapsed time. 220+ 221Returns the exit-code. 222 223`void trace2_cmd_error(const char *fmt, va_list ap)`:: 224 225 Emits an "error" message containing a formatted error message. 226 227`void trace2_cmd_path(const char *pathname)`:: 228 229 Emits a "cmd_path" message with the full pathname of the 230 current process. 231 232=== Command Detail Messages 233 234These are concerned with describing the specific Git command 235after the command line, config, and environment are inspected. 236 237`void trace2_cmd_name(const char *name)`:: 238 239 Emits a "cmd_name" message with the canonical name of the 240 command, for example "status" or "checkout". 241 242`void trace2_cmd_mode(const char *mode)`:: 243 244 Emits a "cmd_mode" message with a qualifier name to further 245 describe the current git command. 246+ 247This message is intended to be used with git commands having multiple 248major modes. For example, a "checkout" command can checkout a new 249branch or it can checkout a single file, so the checkout code could 250emit a cmd_mode message of "branch" or "file". 251 252`void trace2_cmd_alias(const char *alias, const char **argv_expansion)`:: 253 254 Emits an "alias" message containing the alias used and the 255 argument expansion. 256 257`void trace2_def_param(const char *parameter, const char *value)`:: 258 259 Emits a "def_param" message containing a key/value pair. 260+ 261This message is intended to report some global aspect of the current 262command, such as a configuration setting or command line switch that 263significantly affects program performance or behavior, such as 264`core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`. 265 266`void trace2_cmd_list_config()`:: 267 268 Emits a "def_param" messages for "important" configuration 269 settings. 270+ 271The environment variable `GIT_TR2_CONFIG_PARAMS` or the `trace2.configParams` 272config value can be set to a 273list of patterns of important configuration settings, for example: 274`core.*,remote.*.url`. This function will iterate over all config 275settings and emit a "def_param" message for each match. 276 277`void trace2_cmd_set_config(const char *key, const char *value)`:: 278 279 Emits a "def_param" message for a new or updated key/value 280 pair IF `key` is considered important. 281+ 282This is used to hook into `git_config_set()` and catch any 283configuration changes and update a value previously reported by 284`trace2_cmd_list_config()`. 285 286`void trace2_def_repo(struct repository *repo)`:: 287 288 Registers a repository with the Trace2 layer. Assigns a 289 unique "repo-id" to `repo->trace2_repo_id`. 290+ 291Emits a "worktree" messages containing the repo-id and the worktree 292pathname. 293+ 294Region and data messages (described later) may refer to this repo-id. 295+ 296The main/top-level repository will have repo-id value 1 (aka "r1"). 297+ 298The repo-id field is in anticipation of future in-proc submodule 299repositories. 300 301=== Child Process Messages 302 303These are concerned with the various spawned child processes, 304including shell scripts, git commands, editors, pagers, and hooks. 305 306`void trace2_child_start(struct child_process *cmd)`:: 307 308 Emits a "child_start" message containing the "child-id", 309 "child-argv", and "child-classification". 310+ 311Before calling this, set `cmd->trace2_child_class` to a name 312describing the type of child process, for example "editor". 313+ 314This function assigns a unique "child-id" to `cmd->trace2_child_id`. 315This field is used later during the "child_exit" message to associate 316it with the "child_start" message. 317+ 318This function should be called before spawning the child process. 319 320`void trace2_child_exit(struct child_proess *cmd, int child_exit_code)`:: 321 322 Emits a "child_exit" message containing the "child-id", 323 the child's elapsed time and exit-code. 324+ 325The reported elapsed time includes the process creation overhead and 326time spend waiting for it to exit, so it may be slightly longer than 327the time reported by the child itself. 328+ 329This function should be called after reaping the child process. 330 331`int trace2_exec(const char *exe, const char **argv)`:: 332 333 Emits a "exec" message containing the "exec-id" and the 334 argv of the new process. 335+ 336This function should be called before calling one of the `exec()` 337variants, such as `execvp()`. 338+ 339This function returns a unique "exec-id". This value is used later 340if the exec() fails and a "exec-result" message is necessary. 341 342`void trace2_exec_result(int exec_id, int error_code)`:: 343 344 Emits a "exec_result" message containing the "exec-id" 345 and the error code. 346+ 347On Unix-based systems, `exec()` does not return if successful. 348This message is used to indicate that the `exec()` failed and 349that the current program is continuing. 350 351=== Git Thread Messages 352 353These messages are concerned with Git thread usage. 354 355`void trace2_thread_start(const char *thread_name)`:: 356 357 Emits a "thread_start" message. 358+ 359The `thread_name` field should be a descriptive name, such as the 360unique name of the thread-proc. A unique "thread-id" will be added 361to the name to uniquely identify thread instances. 362+ 363Region and data messages (described later) may refer to this thread 364name. 365+ 366This function must be called by the thread-proc of the new thread 367(so that TLS data is properly initialized) and not by the caller 368of `pthread_create()`. 369 370`void trace2_thread_exit()`:: 371 372 Emits a "thread_exit" message containing the thread name 373 and the thread elapsed time. 374+ 375This function must be called by the thread-proc before it returns 376(so that the coorect TLS data is used and cleaned up. It should 377not be called by the caller of `pthread_join()`. 378 379=== Region and Data Messages 380 381These are concerned with recording performance data 382over regions or spans of code. 383 384`void trace2_region_enter(const char *category, const char *label, const struct repository *repo)`:: 385 386`void trace2_region_enter_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`:: 387 388`void trace2_region_enter_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`:: 389 390 Emits a thread-relative "region_enter" message with optional 391 printf string. 392+ 393This function pushes a new region nesting stack level on the current 394thread and starts a clock for the new stack frame. 395+ 396The `category` field is an arbitrary category name used to classify 397regions by feature area, such as "status" or "index". At this time 398it is only just printed along with the rest of the message. It may 399be used in the future to filter messages. 400+ 401The `label` field is an arbitrary label used to describe the activity 402being started, such as "read_recursive" or "do_read_index". 403+ 404The `repo` field, if set, will be used to get the "repo-id", so that 405recursive oerations can be attributed to the correct repository. 406 407`void trace2_region_leave(const char *category, const char *label, const struct repository *repo)`:: 408 409`void trace2_region_leave_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`:: 410 411`void trace2_region_leave_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`:: 412 413 Emits a thread-relative "region_leave" message with optional 414 printf string. 415+ 416This function pops the region nesting stack on the current thread 417and reports the elapsed time of the stack frame. 418+ 419The `category`, `label`, and `repo` fields are the same as above. 420The `category` and `label` do not need to match the correpsonding 421"region_enter" message, but it makes the data stream easier to 422understand. 423 424`void trace2_data_string(const char *category, const struct repository *repo, const char *key, const char * value)`:: 425 426`void trace2_data_intmax(const char *category, const struct repository *repo, const char *key, intmax value)`:: 427 428`void trace2_data_json(const char *category, const struct repository *repo, const char *key, const struct json_writer *jw)`:: 429 430 Emits a region- and thread-relative "data" or "data_json" message. 431+ 432This is a key/value pair message containing information about the 433current thread, region stack, and repository. This could be used 434to print the number of files in a directory during a multi-threaded 435recursive tree walk. 436 437`void trace2_printf(const char *fmt, ...)`:: 438 439`void trace2_printf_va(const char *fmt, va_list ap)`:: 440 441 Emits a region- and thread-relative "printf" message. 442 443== Trace2 Target Formats 444 445=== NORMAL Format 446 447Events are written as lines of the form: 448 449------------ 450[<time> SP <filename>:<line> SP+] <event-name> [[SP] <event-message>] LF 451------------ 452 453`<event-name>`:: 454 455 is the event name. 456 457`<event-message>`:: 458 is a free-form printf message intended for human consumption. 459+ 460Note that this may contain embedded LF or CRLF characters that are 461not escaped, so the event may spill across multiple lines. 462 463If `GIT_TR2_BRIEF` or `trace2.normalBrief` is true, the `time`, `filename`, 464and `line` fields are omitted. 465 466This target is intended to be more of a summary (like GIT_TRACE) and 467less detailed than the other targets. It ignores thread, region, and 468data messages, for example. 469 470=== PERF Format 471 472Events are written as lines of the form: 473 474------------ 475[<time> SP <filename>:<line> SP+ 476 BAR SP] d<depth> SP 477 BAR SP <thread-name> SP+ 478 BAR SP <event-name> SP+ 479 BAR SP [r<repo-id>] SP+ 480 BAR SP [<t_abs>] SP+ 481 BAR SP [<t_rel>] SP+ 482 BAR SP [<category>] SP+ 483 BAR SP DOTS* <perf-event-message> 484 LF 485------------ 486 487`<depth>`:: 488 is the git process depth. This is the number of parent 489 git processes. A top-level git command has depth value "d0". 490 A child of it has depth value "d1". A second level child 491 has depth value "d2" and so on. 492 493`<thread-name>`:: 494 is a unique name for the thread. The primary thread 495 is called "main". Other thread names are of the form "th%d:%s" 496 and include a unique number and the name of the thread-proc. 497 498`<event-name>`:: 499 is the event name. 500 501`<repo-id>`:: 502 when present, is a number indicating the repository 503 in use. A `def_repo` event is emitted when a repository is 504 opened. This defines the repo-id and associated worktree. 505 Subsequent repo-specific events will reference this repo-id. 506+ 507Currently, this is always "r1" for the main repository. 508This field is in anticipation of in-proc submodules in the future. 509 510`<t_abs>`:: 511 when present, is the absolute time in seconds since the 512 program started. 513 514`<t_rel>`:: 515 when present, is time in seconds relative to the start of 516 the current region. For a thread-exit event, it is the elapsed 517 time of the thread. 518 519`<category>`:: 520 is present on region and data events and is used to 521 indicate a broad category, such as "index" or "status". 522 523`<perf-event-message>`:: 524 is a free-form printf message intended for human consumption. 525 526------------ 52715:33:33.532712 wt-status.c:2310 | d0 | main | region_enter | r1 | 0.126064 | | status | label:print 52815:33:33.532712 wt-status.c:2331 | d0 | main | region_leave | r1 | 0.127568 | 0.001504 | status | label:print 529------------ 530 531If `GIT_TR2_PERF_BRIEF` or `trace2.perfBrief` is true, the `time`, `file`, 532and `line` fields are omitted. 533 534------------ 535d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload 536------------ 537 538The PERF target is intended for interactive performance analysis 539during development and is quite noisy. 540 541=== EVENT Format 542 543Each event is a JSON-object containing multiple key/value pairs 544written as a single line and followed by a LF. 545 546------------ 547'{' <key> ':' <value> [',' <key> ':' <value>]* '}' LF 548------------ 549 550Some key/value pairs are common to all events and some are 551event-specific. 552 553==== Common Key/Value Pairs 554 555The following key/value pairs are common to all events: 556 557------------ 558{ 559 "event":"version", 560 "sid":"20190408T191827.272759Z-H9b68c35f-P00003510", 561 "thread":"main", 562 "time":"2019-04-08T19:18:27.282761Z", 563 "file":"common-main.c", 564 "line":42, 565 ... 566} 567------------ 568 569`"event":<event>`:: 570 is the event name. 571 572`"sid":<sid>`:: 573 is the session-id. This is a unique string to identify the 574 process instance to allow all events emitted by a process to 575 be identified. A session-id is used instead of a PID because 576 PIDs are recycled by the OS. For child git processes, the 577 session-id is prepended with the session-id of the parent git 578 process to allow parent-child relationships to be identified 579 during post-processing. 580 581`"thread":<thread>`:: 582 is the thread name. 583 584`"time":<time>`:: 585 is the UTC time of the event. 586 587`"file":<filename>`:: 588 is source file generating the event. 589 590`"line":<line-number>`:: 591 is the integer source line number generating the event. 592 593`"repo":<repo-id>`:: 594 when present, is the integer repo-id as described previously. 595 596If `GIT_TR2_EVENT_BRIEF` or `trace2.eventBrief` is true, the `file` 597and `line` fields are omitted from all events and the `time` field is 598only present on the "start" and "atexit" events. 599 600==== Event-Specific Key/Value Pairs 601 602`"version"`:: 603 This event gives the version of the executable and the EVENT format. 604+ 605------------ 606{ 607 "event":"version", 608 ... 609 "evt":"1", # EVENT format version 610 "exe":"2.20.1.155.g426c96fcdb" # git version 611} 612------------ 613 614`"start"`:: 615 This event contains the complete argv received by main(). 616+ 617------------ 618{ 619 "event":"start", 620 ... 621 "t_abs":0.001227, # elapsed time in seconds 622 "argv":["git","version"] 623} 624------------ 625 626`"exit"`:: 627 This event is emitted when git calls `exit()`. 628+ 629------------ 630{ 631 "event":"exit", 632 ... 633 "t_abs":0.001227, # elapsed time in seconds 634 "code":0 # exit code 635} 636------------ 637 638`"atexit"`:: 639 This event is emitted by the Trace2 `atexit` routine during 640 final shutdown. It should be the last event emitted by the 641 process. 642+ 643(The elapsed time reported here is greater than the time reported in 644the "exit" event because it runs after all other atexit tasks have 645completed.) 646+ 647------------ 648{ 649 "event":"atexit", 650 ... 651 "t_abs":0.001227, # elapsed time in seconds 652 "code":0 # exit code 653} 654------------ 655 656`"signal"`:: 657 This event is emitted when the program is terminated by a user 658 signal. Depending on the platform, the signal event may 659 prevent the "atexit" event from being generated. 660+ 661------------ 662{ 663 "event":"signal", 664 ... 665 "t_abs":0.001227, # elapsed time in seconds 666 "signal":13 # SIGTERM, SIGINT, etc. 667} 668------------ 669 670`"error"`:: 671 This event is emitted when one of the `error()`, `die()`, 672 or `usage()` functions are called. 673+ 674------------ 675{ 676 "event":"error", 677 ... 678 "msg":"invalid option: --cahced", # formatted error message 679 "fmt":"invalid option: %s" # error format string 680} 681------------ 682+ 683The error event may be emitted more than once. The format string 684allows post-processors to group errors by type without worrying 685about specific error arguments. 686 687`"cmd_path"`:: 688 This event contains the discovered full path of the git 689 executable (on platforms that are configured to resolve it). 690+ 691------------ 692{ 693 "event":"cmd_path", 694 ... 695 "path":"C:/work/gfw/git.exe" 696} 697------------ 698 699`"cmd_name"`:: 700 This event contains the command name for this git process 701 and the hierarchy of commands from parent git processes. 702+ 703------------ 704{ 705 "event":"cmd_name", 706 ... 707 "name":"pack-objects", 708 "hierarchy":"push/pack-objects" 709} 710------------ 711+ 712Normally, the "name" field contains the canonical name of the 713command. When a canonical name is not available, one of 714these special values are used: 715+ 716------------ 717"_query_" # "git --html-path" 718"_run_dashed_" # when "git foo" tries to run "git-foo" 719"_run_shell_alias_" # alias expansion to a shell command 720"_run_git_alias_" # alias expansion to a git command 721"_usage_" # usage error 722------------ 723 724`"cmd_mode"`:: 725 This event, when present, describes the command variant This 726 event may be emitted more than once. 727+ 728------------ 729{ 730 "event":"cmd_mode", 731 ... 732 "name":"branch" 733} 734------------ 735+ 736The "name" field is an arbitrary string to describe the command mode. 737For example, checkout can checkout a branch or an individual file. 738And these variations typically have different performance 739characteristics that are not comparable. 740 741`"alias"`:: 742 This event is present when an alias is expanded. 743+ 744------------ 745{ 746 "event":"alias", 747 ... 748 "alias":"l", # registered alias 749 "argv":["log","--graph"] # alias expansion 750} 751------------ 752 753`"child_start"`:: 754 This event describes a child process that is about to be 755 spawned. 756+ 757------------ 758{ 759 "event":"child_start", 760 ... 761 "child_id":2, 762 "child_class":"?", 763 "use_shell":false, 764 "argv":["git","rev-list","--objects","--stdin","--not","--all","--quiet"] 765 766 "hook_name":"<hook_name>" # present when child_class is "hook" 767 "cd":"<path>" # present when cd is required 768} 769------------ 770+ 771The "child_id" field can be used to match this child_start with the 772corresponding child_exit event. 773+ 774The "child_class" field is a rough classification, such as "editor", 775"pager", "transport/*", and "hook". Unclassified children are classified 776with "?". 777 778`"child_exit"`:: 779 This event is generated after the current process has returned 780 from the waitpid() and collected the exit information from the 781 child. 782+ 783------------ 784{ 785 "event":"child_exit", 786 ... 787 "child_id":2, 788 "pid":14708, # child PID 789 "code":0, # child exit-code 790 "t_rel":0.110605 # observed run-time of child process 791} 792------------ 793+ 794Note that the session-id of the child process is not available to 795the current/spawning process, so the child's PID is reported here as 796a hint for post-processing. (But it is only a hint because the child 797proces may be a shell script which doesn't have a session-id.) 798+ 799Note that the `t_rel` field contains the observed run time in seconds 800for the child process (starting before the fork/exec/spawn and 801stopping after the waitpid() and includes OS process creation overhead). 802So this time will be slightly larger than the atexit time reported by 803the child process itself. 804 805`"exec"`:: 806 This event is generated before git attempts to `exec()` 807 another command rather than starting a child process. 808+ 809------------ 810{ 811 "event":"exec", 812 ... 813 "exec_id":0, 814 "exe":"git", 815 "argv":["foo", "bar"] 816} 817------------ 818+ 819The "exec_id" field is a command-unique id and is only useful if the 820`exec()` fails and a corresponding exec_result event is generated. 821 822`"exec_result"`:: 823 This event is generated if the `exec()` fails and control 824 returns to the current git command. 825+ 826------------ 827{ 828 "event":"exec_result", 829 ... 830 "exec_id":0, 831 "code":1 # error code (errno) from exec() 832} 833------------ 834 835`"thread_start"`:: 836 This event is generated when a thread is started. It is 837 generated from *within* the new thread's thread-proc (for TLS 838 reasons). 839+ 840------------ 841{ 842 "event":"thread_start", 843 ... 844 "thread":"th02:preload_thread" # thread name 845} 846------------ 847 848`"thread_exit"`:: 849 This event is generated when a thread exits. It is generated 850 from *within* the thread's thread-proc (for TLS reasons). 851+ 852------------ 853{ 854 "event":"thread_exit", 855 ... 856 "thread":"th02:preload_thread", # thread name 857 "t_rel":0.007328 # thread elapsed time 858} 859------------ 860 861`"def_param"`:: 862 This event is generated to log a global parameter. 863+ 864------------ 865{ 866 "event":"def_param", 867 ... 868 "param":"core.abbrev", 869 "value":"7" 870} 871------------ 872 873`"def_repo"`:: 874 This event defines a repo-id and associates it with the root 875 of the worktree. 876+ 877------------ 878{ 879 "event":"def_repo", 880 ... 881 "repo":1, 882 "worktree":"/Users/jeffhost/work/gfw" 883} 884------------ 885+ 886As stated earlier, the repo-id is currently always 1, so there will 887only be one def_repo event. Later, if in-proc submodules are 888supported, a def_repo event should be emitted for each submodule 889visited. 890 891`"region_enter"`:: 892 This event is generated when entering a region. 893+ 894------------ 895{ 896 "event":"region_enter", 897 ... 898 "repo":1, # optional 899 "nesting":1, # current region stack depth 900 "category":"index", # optional 901 "label":"do_read_index", # optional 902 "msg":".git/index" # optional 903} 904------------ 905+ 906The `category` field may be used in a future enhancement to 907do category-based filtering. 908+ 909`GIT_TR2_EVENT_NESTING` or `trace2.eventNesting` can be used to 910filter deeply nested regions and data events. It defaults to "2". 911 912`"region_leave"`:: 913 This event is generated when leaving a region. 914+ 915------------ 916{ 917 "event":"region_leave", 918 ... 919 "repo":1, # optional 920 "t_rel":0.002876, # time spent in region in seconds 921 "nesting":1, # region stack depth 922 "category":"index", # optional 923 "label":"do_read_index", # optional 924 "msg":".git/index" # optional 925} 926------------ 927 928`"data"`:: 929 This event is generated to log a thread- and region-local 930 key/value pair. 931+ 932------------ 933{ 934 "event":"data", 935 ... 936 "repo":1, # optional 937 "t_abs":0.024107, # absolute elapsed time 938 "t_rel":0.001031, # elapsed time in region/thread 939 "nesting":2, # region stack depth 940 "category":"index", 941 "key":"read/cache_nr", 942 "value":"3552" 943} 944------------ 945+ 946The "value" field may be an integer or a string. 947 948`"data-json"`:: 949 This event is generated to log a pre-formatted JSON string 950 containing structured data. 951+ 952------------ 953{ 954 "event":"data_json", 955 ... 956 "repo":1, # optional 957 "t_abs":0.015905, 958 "t_rel":0.015905, 959 "nesting":1, 960 "category":"process", 961 "key":"windows/ancestry", 962 "value":["bash.exe","bash.exe"] 963} 964------------ 965 966== Example Trace2 API Usage 967 968Here is a hypothetical usage of the Trace2 API showing the intended 969usage (without worrying about the actual Git details). 970 971Initialization:: 972 973 Initialization happens in `main()`. Behind the scenes, an 974 `atexit` and `signal` handler are registered. 975+ 976---------------- 977int main(int argc, const char **argv) 978{ 979 int exit_code; 980 981 trace2_initialize(); 982 trace2_cmd_start(argv); 983 984 exit_code = cmd_main(argc, argv); 985 986 trace2_cmd_exit(exit_code); 987 988 return exit_code; 989} 990---------------- 991 992Command Details:: 993 994 After the basics are established, additional command 995 information can be sent to Trace2 as it is discovered. 996+ 997---------------- 998int cmd_checkout(int argc, const char **argv) 999{1000 trace2_cmd_name("checkout");1001 trace2_cmd_mode("branch");1002 trace2_def_repo(the_repository);10031004 // emit "def_param" messages for "interesting" config settings.1005 trace2_cmd_list_config();10061007 if (do_something())1008 trace2_cmd_error("Path '%s': cannot do something", path);10091010 return 0;1011}1012----------------10131014Child Processes::10151016 Wrap code spawning child processes.1017+1018----------------1019void run_child(...)1020{1021 int child_exit_code;1022 struct child_process cmd = CHILD_PROCESS_INIT;1023 ...1024 cmd.trace2_child_class = "editor";10251026 trace2_child_start(&cmd);1027 child_exit_code = spawn_child_and_wait_for_it();1028 trace2_child_exit(&cmd, child_exit_code);1029}1030----------------1031+1032For example, the following fetch command spawned ssh, index-pack,1033rev-list, and gc. This example also shows that fetch took10345.199 seconds and of that 4.932 was in ssh.1035+1036----------------1037$ export GIT_TR2_BRIEF=11038$ export GIT_TR2=~/log.normal1039$ git fetch origin1040...1041----------------1042+1043----------------1044$ cat ~/log.normal1045version 2.20.1.vfs.1.1.47.g534dbe1ad11046start git fetch origin1047worktree /Users/jeffhost/work/gfw1048cmd_name fetch (fetch)1049child_start[0] ssh git@github.com ...1050child_start[1] git index-pack ...1051... (Trace2 events from child processes omitted)1052child_exit[1] pid:14707 code:0 elapsed:0.0763531053child_exit[0] pid:14706 code:0 elapsed:4.9318691054child_start[2] git rev-list ...1055... (Trace2 events from child process omitted)1056child_exit[2] pid:14708 code:0 elapsed:0.1106051057child_start[3] git gc --auto1058... (Trace2 events from child process omitted)1059child_exit[3] pid:14709 code:0 elapsed:0.0062401060exit elapsed:5.198503 code:01061atexit elapsed:5.198541 code:01062----------------1063+1064When a git process is a (direct or indirect) child of another1065git process, it inherits Trace2 context information. This1066allows the child to print the command hierarchy. This example1067shows gc as child[3] of fetch. When the gc process reports1068its name as "gc", it also reports the hierarchy as "fetch/gc".1069(In this example, trace2 messages from the child process is1070indented for clarity.)1071+1072----------------1073$ export GIT_TR2_BRIEF=11074$ export GIT_TR2=~/log.normal1075$ git fetch origin1076...1077----------------1078+1079----------------1080$ cat ~/log.normal1081version 2.20.1.160.g5676107ecd.dirty1082start git fetch official1083worktree /Users/jeffhost/work/gfw1084cmd_name fetch (fetch)1085...1086child_start[3] git gc --auto1087 version 2.20.1.160.g5676107ecd.dirty1088 start /Users/jeffhost/work/gfw/git gc --auto1089 worktree /Users/jeffhost/work/gfw1090 cmd_name gc (fetch/gc)1091 exit elapsed:0.001959 code:01092 atexit elapsed:0.001997 code:01093child_exit[3] pid:20303 code:0 elapsed:0.0075641094exit elapsed:3.868938 code:01095atexit elapsed:3.868970 code:01096----------------10971098Regions::10991100 Regions can be use to time an interesting section of code.1101+1102----------------1103void wt_status_collect(struct wt_status *s)1104{1105 trace2_region_enter("status", "worktrees", s->repo);1106 wt_status_collect_changes_worktree(s);1107 trace2_region_leave("status", "worktrees", s->repo);11081109 trace2_region_enter("status", "index", s->repo);1110 wt_status_collect_changes_index(s);1111 trace2_region_leave("status", "index", s->repo);11121113 trace2_region_enter("status", "untracked", s->repo);1114 wt_status_collect_untracked(s);1115 trace2_region_leave("status", "untracked", s->repo);1116}11171118void wt_status_print(struct wt_status *s)1119{1120 trace2_region_enter("status", "print", s->repo);1121 switch (s->status_format) {1122 ...1123 }1124 trace2_region_leave("status", "print", s->repo);1125}1126----------------1127+1128In this example, scanning for untracked files ran from +0.012568 to1129+0.027149 (since the process started) and took 0.014581 seconds.1130+1131----------------1132$ export GIT_TR2_PERF_BRIEF=11133$ export GIT_TR2_PERF=~/log.perf1134$ git status1135...11361137$ cat ~/log.perf1138d0 | main | version | | | | | 2.20.1.160.g5676107ecd.dirty1139d0 | main | start | | 0.001173 | | | git status1140d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw1141d0 | main | cmd_name | | | | | status (status)1142...1143d0 | main | region_enter | r1 | 0.010988 | | status | label:worktrees1144d0 | main | region_leave | r1 | 0.011236 | 0.000248 | status | label:worktrees1145d0 | main | region_enter | r1 | 0.011260 | | status | label:index1146d0 | main | region_leave | r1 | 0.012542 | 0.001282 | status | label:index1147d0 | main | region_enter | r1 | 0.012568 | | status | label:untracked1148d0 | main | region_leave | r1 | 0.027149 | 0.014581 | status | label:untracked1149d0 | main | region_enter | r1 | 0.027411 | | status | label:print1150d0 | main | region_leave | r1 | 0.028741 | 0.001330 | status | label:print1151d0 | main | exit | | 0.028778 | | | code:01152d0 | main | atexit | | 0.028809 | | | code:01153----------------1154+1155Regions may be nested. This causes messages to be indented in the1156PERF target, for example.1157Elapsed times are relative to the start of the correpsonding nesting1158level as expected. For example, if we add region message to:1159+1160----------------1161static enum path_treatment read_directory_recursive(struct dir_struct *dir,1162 struct index_state *istate, const char *base, int baselen,1163 struct untracked_cache_dir *untracked, int check_only,1164 int stop_at_first_file, const struct pathspec *pathspec)1165{1166 enum path_treatment state, subdir_state, dir_state = path_none;11671168 trace2_region_enter_printf("dir", "read_recursive", NULL, "%.*s", baselen, base);1169 ...1170 trace2_region_leave_printf("dir", "read_recursive", NULL, "%.*s", baselen, base);1171 return dir_state;1172}1173----------------1174+1175We can further investigate the time spent scanning for untracked files.1176+1177----------------1178$ export GIT_TR2_PERF_BRIEF=11179$ export GIT_TR2_PERF=~/log.perf1180$ git status1181...1182$ cat ~/log.perf1183d0 | main | version | | | | | 2.20.1.162.gb4ccea44db.dirty1184d0 | main | start | | 0.001173 | | | git status1185d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw1186d0 | main | cmd_name | | | | | status (status)1187...1188d0 | main | region_enter | r1 | 0.015047 | | status | label:untracked1189d0 | main | region_enter | | 0.015132 | | dir | ..label:read_recursive1190d0 | main | region_enter | | 0.016341 | | dir | ....label:read_recursive vcs-svn/1191d0 | main | region_leave | | 0.016422 | 0.000081 | dir | ....label:read_recursive vcs-svn/1192d0 | main | region_enter | | 0.016446 | | dir | ....label:read_recursive xdiff/1193d0 | main | region_leave | | 0.016522 | 0.000076 | dir | ....label:read_recursive xdiff/1194d0 | main | region_enter | | 0.016612 | | dir | ....label:read_recursive git-gui/1195d0 | main | region_enter | | 0.016698 | | dir | ......label:read_recursive git-gui/po/1196d0 | main | region_enter | | 0.016810 | | dir | ........label:read_recursive git-gui/po/glossary/1197d0 | main | region_leave | | 0.016863 | 0.000053 | dir | ........label:read_recursive git-gui/po/glossary/1198...1199d0 | main | region_enter | | 0.031876 | | dir | ....label:read_recursive builtin/1200d0 | main | region_leave | | 0.032270 | 0.000394 | dir | ....label:read_recursive builtin/1201d0 | main | region_leave | | 0.032414 | 0.017282 | dir | ..label:read_recursive1202d0 | main | region_leave | r1 | 0.032454 | 0.017407 | status | label:untracked1203...1204d0 | main | exit | | 0.034279 | | | code:01205d0 | main | atexit | | 0.034322 | | | code:01206----------------1207+1208Trace2 regions are similar to the existing trace_performance_enter()1209and trace_performance_leave() routines, but are thread safe and1210maintain per-thread stacks of timers.12111212Data Messages::12131214 Data messages added to a region.1215+1216----------------1217int read_index_from(struct index_state *istate, const char *path,1218 const char *gitdir)1219{1220 trace2_region_enter_printf("index", "do_read_index", the_repository, "%s", path);12211222 ...12231224 trace2_data_intmax("index", the_repository, "read/version", istate->version);1225 trace2_data_intmax("index", the_repository, "read/cache_nr", istate->cache_nr);12261227 trace2_region_leave_printf("index", "do_read_index", the_repository, "%s", path);1228}1229----------------1230+1231This example shows that the index contained 3552 entries.1232+1233----------------1234$ export GIT_TR2_PERF_BRIEF=11235$ export GIT_TR2_PERF=~/log.perf1236$ git status1237...1238$ cat ~/log.perf1239d0 | main | version | | | | | 2.20.1.156.gf9916ae094.dirty1240d0 | main | start | | 0.001173 | | | git status1241d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw1242d0 | main | cmd_name | | | | | status (status)1243d0 | main | region_enter | r1 | 0.001791 | | index | label:do_read_index .git/index1244d0 | main | data | r1 | 0.002494 | 0.000703 | index | ..read/version:21245d0 | main | data | r1 | 0.002520 | 0.000729 | index | ..read/cache_nr:35521246d0 | main | region_leave | r1 | 0.002539 | 0.000748 | index | label:do_read_index .git/index1247...1248----------------12491250Thread Events::12511252 Thread messages added to a thread-proc.1253+1254For example, the multithreaded preload-index code can be1255instrumented with a region around the thread pool and then1256per-thread start and exit events within the threadproc.1257+1258----------------1259static void *preload_thread(void *_data)1260{1261 // start the per-thread clock and emit a message.1262 trace2_thread_start("preload_thread");12631264 // report which chunk of the array this thread was assigned.1265 trace2_data_intmax("index", the_repository, "offset", p->offset);1266 trace2_data_intmax("index", the_repository, "count", nr);12671268 do {1269 ...1270 } while (--nr > 0);1271 ...12721273 // report elapsed time taken by this thread.1274 trace2_thread_exit();1275 return NULL;1276}12771278void preload_index(struct index_state *index,1279 const struct pathspec *pathspec,1280 unsigned int refresh_flags)1281{1282 trace2_region_enter("index", "preload", the_repository);12831284 for (i = 0; i < threads; i++) {1285 ... /* create thread */1286 }12871288 for (i = 0; i < threads; i++) {1289 ... /* join thread */1290 }12911292 trace2_region_leave("index", "preload", the_repository);1293}1294----------------1295+1296In this example preload_index() was executed by the `main` thread1297and started the `preload` region. Seven threads, named1298`th01:preload_thread` through `th07:preload_thread`, were started.1299Events from each thread are atomically appended to the shared target1300stream as they occur so they may appear in random order with respect1301other threads. Finally, the main thread waits for the threads to1302finish and leaves the region.1303+1304Data events are tagged with the active thread name. They are used1305to report the per-thread parameters.1306+1307----------------1308$ export GIT_TR2_PERF_BRIEF=11309$ export GIT_TR2_PERF=~/log.perf1310$ git status1311...1312$ cat ~/log.perf1313...1314d0 | main | region_enter | r1 | 0.002595 | | index | label:preload1315d0 | th01:preload_thread | thread_start | | 0.002699 | | |1316d0 | th02:preload_thread | thread_start | | 0.002721 | | |1317d0 | th01:preload_thread | data | r1 | 0.002736 | 0.000037 | index | offset:01318d0 | th02:preload_thread | data | r1 | 0.002751 | 0.000030 | index | offset:20321319d0 | th03:preload_thread | thread_start | | 0.002711 | | |1320d0 | th06:preload_thread | thread_start | | 0.002739 | | |1321d0 | th01:preload_thread | data | r1 | 0.002766 | 0.000067 | index | count:5081322d0 | th06:preload_thread | data | r1 | 0.002856 | 0.000117 | index | offset:25401323d0 | th03:preload_thread | data | r1 | 0.002824 | 0.000113 | index | offset:10161324d0 | th04:preload_thread | thread_start | | 0.002710 | | |1325d0 | th02:preload_thread | data | r1 | 0.002779 | 0.000058 | index | count:5081326d0 | th06:preload_thread | data | r1 | 0.002966 | 0.000227 | index | count:5081327d0 | th07:preload_thread | thread_start | | 0.002741 | | |1328d0 | th07:preload_thread | data | r1 | 0.003017 | 0.000276 | index | offset:30481329d0 | th05:preload_thread | thread_start | | 0.002712 | | |1330d0 | th05:preload_thread | data | r1 | 0.003067 | 0.000355 | index | offset:15241331d0 | th05:preload_thread | data | r1 | 0.003090 | 0.000378 | index | count:5081332d0 | th07:preload_thread | data | r1 | 0.003037 | 0.000296 | index | count:5041333d0 | th03:preload_thread | data | r1 | 0.002971 | 0.000260 | index | count:5081334d0 | th04:preload_thread | data | r1 | 0.002983 | 0.000273 | index | offset:5081335d0 | th04:preload_thread | data | r1 | 0.007311 | 0.004601 | index | count:5081336d0 | th05:preload_thread | thread_exit | | 0.008781 | 0.006069 | |1337d0 | th01:preload_thread | thread_exit | | 0.009561 | 0.006862 | |1338d0 | th03:preload_thread | thread_exit | | 0.009742 | 0.007031 | |1339d0 | th06:preload_thread | thread_exit | | 0.009820 | 0.007081 | |1340d0 | th02:preload_thread | thread_exit | | 0.010274 | 0.007553 | |1341d0 | th07:preload_thread | thread_exit | | 0.010477 | 0.007736 | |1342d0 | th04:preload_thread | thread_exit | | 0.011657 | 0.008947 | |1343d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload1344...1345d0 | main | exit | | 0.029996 | | | code:01346d0 | main | atexit | | 0.030027 | | | code:01347----------------1348+1349In this example, the preload region took 0.009122 seconds. The 7 threads1350took between 0.006069 and 0.008947 seconds to work on their portion of1351the index. Thread "th01" worked on 508 items at offset 0. Thread "th02"1352worked on 508 items at offset 2032. Thread "th04" worked on 508 itemts1353at offset 508.1354+1355This example also shows that thread names are assigned in a racy manner1356as each thread starts and allocates TLS storage.13571358== Future Work13591360=== Relationship to the Existing Trace Api (api-trace.txt)13611362There are a few issues to resolve before we can completely1363switch to Trace2.13641365* Updating existing tests that assume GIT_TRACE format messages.13661367* How to best handle custom GIT_TRACE_<key> messages?13681369** The GIT_TRACE_<key> mechanism allows each <key> to write to a1370different file (in addition to just stderr).13711372** Do we want to maintain that ability or simply write to the existing1373Trace2 targets (and convert <key> to a "category").