Git fork

Merge branch 'jh/trace2-sid-fix'

Polishing of the new trace2 facility continues. The system-level
configuration can specify site-wide trace2 settings, which can be
overridden with per-user configuration and environment variables.

* jh/trace2-sid-fix:
trace2: fixup access problem on /etc/gitconfig in read_very_early_config
trace2: update docs to describe system/global config settings
trace2: make SIDs more unique
trace2: clarify UTC datetime formatting
trace2: report peak memory usage of the process
trace2: use system/global config for default trace2 settings
config: add read_very_early_config()
trace2: find exec-dir before trace2 initialization
trace2: add absolute elapsed time to start event
trace2: refactor setting process starting time
config: initialize opts structure in repo_read_config()

+758 -216
+2
Documentation/config.txt
··· 422 422 423 423 include::config/tag.txt[] 424 424 425 + include::config/trace2.txt[] 426 + 425 427 include::config/transfer.txt[] 426 428 427 429 include::config/uploadarchive.txt[]
+56
Documentation/config/trace2.txt
··· 1 + Trace2 config settings are only read from the system and global 2 + config files; repository local and worktree config files and `-c` 3 + command line arguments are not respected. 4 + 5 + trace2.normalTarget:: 6 + This variable controls the normal target destination. 7 + It may be overridden by the `GIT_TR2` environment variable. 8 + The following table shows possible values. 9 + 10 + trace2.perfTarget:: 11 + This variable controls the performance target destination. 12 + It may be overridden by the `GIT_TR2_PERF` environment variable. 13 + The following table shows possible values. 14 + 15 + trace2.eventTarget:: 16 + This variable controls the event target destination. 17 + It may be overridden by the `GIT_TR2_EVENT` environment variable. 18 + The following table shows possible values. 19 + + 20 + include::../trace2-target-values.txt[] 21 + 22 + trace2.normalBrief:: 23 + Boolean. When true `time`, `filename`, and `line` fields are 24 + omitted from normal output. May be overridden by the 25 + `GIT_TR2_BRIEF` environment variable. Defaults to false. 26 + 27 + trace2.perfBrief:: 28 + Boolean. When true `time`, `filename`, and `line` fields are 29 + omitted from PERF output. May be overridden by the 30 + `GIT_TR2_PERF_BRIEF` environment variable. Defaults to false. 31 + 32 + trace2.eventBrief:: 33 + Boolean. When true `time`, `filename`, and `line` fields are 34 + omitted from event output. May be overridden by the 35 + `GIT_TR2_EVENT_BRIEF` environment variable. Defaults to false. 36 + 37 + trace2.eventNesting:: 38 + Integer. Specifies desired depth of nested regions in the 39 + event output. Regions deeper than this value will be 40 + omitted. May be overridden by the `GIT_TR2_EVENT_NESTING` 41 + environment variable. Defaults to 2. 42 + 43 + trace2.configParams:: 44 + A comma-separated list of patterns of "important" config 45 + settings that should be recorded in the trace2 output. 46 + For example, `core.*,remote.*.url` would cause the trace2 47 + output to contain events listing each configured remote. 48 + May be overridden by the `GIT_TR2_CONFIG_PARAMS` environment 49 + variable. Unset by default. 50 + 51 + trace2.destinationDebug:: 52 + Boolean. When true Git will print error messages when a 53 + trace target destination cannot be opened for writing. 54 + By default, these errors are suppressed and tracing is 55 + silently disabled. May be overridden by the 56 + `GIT_TR2_DST_DEBUG` environment variable.
+104 -80
Documentation/technical/api-trace2.txt
··· 22 22 formats in the future. This might be used to define a binary format, 23 23 for example. 24 24 25 + Trace2 is controlled using `trace2.*` config values in the system and 26 + global config files and `GIT_TR2*` environment variables. Trace2 does 27 + not read from repo local or worktree config files or respect `-c` 28 + command line config settings. 29 + 25 30 == Trace2 Targets 26 31 27 32 Trace2 defines the following set of Trace2 Targets. 28 33 Format details are given in a later section. 29 34 30 - `GIT_TR2` (NORMAL):: 35 + === The Normal Format Target 36 + 37 + The normal format target is a tradition printf format and similar 38 + to GIT_TRACE format. This format is enabled with the `GIT_TR` 39 + environment variable or the `trace2.normalTarget` system or global 40 + config setting. 41 + 42 + For example 31 43 32 - a simple printf format like GIT_TRACE. 33 - + 34 44 ------------ 35 45 $ export GIT_TR2=~/log.normal 36 46 $ git version 37 47 git version 2.20.1.155.g426c96fcdb 38 48 ------------ 39 - + 49 + 50 + or 51 + 52 + ------------ 53 + $ git config --global trace2.normalTarget ~/log.normal 54 + $ git version 55 + git version 2.20.1.155.g426c96fcdb 56 + ------------ 57 + 58 + yields 59 + 40 60 ------------ 41 61 $ cat ~/log.normal 42 62 12:28:42.620009 common-main.c:38 version 2.20.1.155.g426c96fcdb ··· 46 66 12:28:42.621250 trace2/tr2_tgt_normal.c:124 atexit elapsed:0.001265 code:0 47 67 ------------ 48 68 49 - `GIT_TR2_PERF` (PERF):: 69 + === The Performance Format Target 70 + 71 + The performance format target (PERF) is a column-based format to 72 + replace GIT_TRACE_PERFORMANCE and is suitable for development and 73 + testing, possibly to complement tools like gprof. This format is 74 + enabled with the `GIT_TR2_PERF` environment variable or the 75 + `trace2.perfTarget` system or global config setting. 50 76 51 - a column-based format to replace GIT_TRACE_PERFORMANCE suitable for 52 - development and testing, possibly to complement tools like gprof. 53 - + 77 + For example 78 + 54 79 ------------ 55 80 $ export GIT_TR2_PERF=~/log.perf 56 81 $ git version 57 82 git version 2.20.1.155.g426c96fcdb 58 83 ------------ 59 - + 84 + 85 + or 86 + 87 + ------------ 88 + $ git config --global trace2.perfTarget ~/log.perf 89 + $ git version 90 + git version 2.20.1.155.g426c96fcdb 91 + ------------ 92 + 93 + yields 94 + 60 95 ------------ 61 96 $ cat ~/log.perf 62 97 12:28:42.620675 common-main.c:38 | d0 | main | version | | | | | 2.20.1.155.g426c96fcdb 63 - 12:28:42.621001 common-main.c:39 | d0 | main | start | | | | | git version 98 + 12:28:42.621001 common-main.c:39 | d0 | main | start | | 0.001173 | | | git version 64 99 12:28:42.621111 git.c:432 | d0 | main | cmd_name | | | | | version (version) 65 100 12:28:42.621225 git.c:662 | d0 | main | exit | | 0.001227 | | | code:0 66 101 12:28:42.621259 trace2/tr2_tgt_perf.c:211 | d0 | main | atexit | | 0.001265 | | | code:0 67 102 ------------ 68 103 69 - `GIT_TR2_EVENT` (EVENT):: 104 + === The Event Format Target 105 + 106 + The event format target is a JSON-based format of event data suitable 107 + for telemetry analysis. This format is enabled with the `GIT_TR2_EVENT` 108 + environment variable or the `trace2.eventTarget` system or global config 109 + setting. 110 + 111 + For example 70 112 71 - a JSON-based format of event data suitable for telemetry analysis. 72 - + 73 113 ------------ 74 114 $ export GIT_TR2_EVENT=~/log.event 75 115 $ git version 76 116 git version 2.20.1.155.g426c96fcdb 77 117 ------------ 78 - + 79 - ------------ 80 - $ cat ~/log.event 81 - {"event":"version","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.620713","file":"common-main.c","line":38,"evt":"1","exe":"2.20.1.155.g426c96fcdb"} 82 - {"event":"start","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621027","file":"common-main.c","line":39,"argv":["git","version"]} 83 - {"event":"cmd_name","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621122","file":"git.c","line":432,"name":"version","hierarchy":"version"} 84 - {"event":"exit","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621236","file":"git.c","line":662,"t_abs":0.001227,"code":0} 85 - {"event":"atexit","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621268","file":"trace2/tr2_tgt_event.c","line":163,"t_abs":0.001265,"code":0} 86 - ------------ 87 118 88 - == Enabling a Target 89 - 90 - A Trace2 Target is enabled when the corresponding environment variable 91 - (`GIT_TR2`, `GIT_TR2_PERF`, or `GIT_TR2_EVENT`) is set. The following 92 - values are recognized. 119 + or 93 120 94 - `0`:: 95 - `false`:: 96 - 97 - Disables the target. 98 - 99 - `1`:: 100 - `true`:: 101 - 102 - Enables the target and writes stream to `STDERR`. 103 - 104 - `[2-9]`:: 121 + ------------ 122 + $ git config --global trace2.eventTarget ~/log.event 123 + $ git version 124 + git version 2.20.1.155.g426c96fcdb 125 + ------------ 105 126 106 - Enables the target and writes to the already opened file descriptor. 127 + yields 107 128 108 - `<absolute-pathname>`:: 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 + ------------ 109 137 110 - Enables the target, opens and writes to the file in append mode. 138 + === Enabling a Target 111 139 112 - If the target already exists and is a directory, the traces will be 113 - written to files (one per process) underneath the given directory. They 114 - will be named according to the last component of the SID (optionally 115 - followed by a counter to avoid filename collisions). 140 + To enable a target, set the corresponding environment variable or 141 + system or global config value to one of the following: 116 142 117 - `af_unix:[<socket_type>:]<absolute-pathname>`:: 143 + include::../trace2-target-values.txt[] 118 144 119 - Enables the target, opens and writes to a Unix Domain Socket 120 - (on platforms that support them). 121 - + 122 - Socket type can be either `stream` or `dgram`. If the socket type is 123 - omitted, Git will try both. 145 + If the target already exists and is a directory, the traces will be 146 + written to files (one per process) underneath the given directory. They 147 + will be named according to the last component of the SID (optionally 148 + followed by a counter to avoid filename collisions). 124 149 125 150 == Trace2 API 126 151 ··· 165 190 166 191 These are concerned with the lifetime of the overall git process. 167 192 193 + `void trace2_initialize_clock()`:: 194 + 195 + Initialize the Trace2 start clock and nothing else. This should 196 + be called at the very top of main() to capture the process start 197 + time and reduce startup order dependencies. 198 + 168 199 `void trace2_initialize()`:: 169 200 170 201 Determines if any Trace2 Targets should be enabled and 171 - initializes the Trace2 facility. This includes starting the 172 - elapsed time clocks and thread local storage (TLS). 202 + initializes the Trace2 facility. This includes setting up the 203 + Trace2 thread local storage (TLS). 173 204 + 174 205 This function emits a "version" message containing the version of git 175 206 and the Trace2 protocol. 176 207 + 177 208 This function should be called from `main()` as early as possible in 178 - the life of the process. 209 + the life of the process after essential process initialization. 179 210 180 211 `int trace2_is_enabled()`:: 181 212 ··· 242 273 Emits a "def_param" messages for "important" configuration 243 274 settings. 244 275 + 245 - The environment variable `GIT_TR2_CONFIG_PARAMS` can be set to a 276 + The environment variable `GIT_TR2_CONFIG_PARAMS` or the `trace2.configParams` 277 + config value can be set to a 246 278 list of patterns of important configuration settings, for example: 247 279 `core.*,remote.*.url`. This function will iterate over all config 248 280 settings and emit a "def_param" message for each match. 249 281 250 282 `void trace2_cmd_set_config(const char *key, const char *value)`:: 251 283 252 - Emits a "def_param" message for a specific configuration 253 - setting IFF it matches the `GIT_TR2_CONFIG_PARAMS` pattern. 284 + Emits a "def_param" message for a new or updated key/value 285 + pair IF `key` is considered important. 254 286 + 255 287 This is used to hook into `git_config_set()` and catch any 256 288 configuration changes and update a value previously reported by ··· 417 449 418 450 === NORMAL Format 419 451 420 - NORMAL format is enabled when the `GIT_TR2` environment variable is 421 - set. 422 - 423 452 Events are written as lines of the form: 424 453 425 454 ------------ ··· 436 465 Note that this may contain embedded LF or CRLF characters that are 437 466 not escaped, so the event may spill across multiple lines. 438 467 439 - If `GIT_TR2_BRIEF` is true, the `time`, `filename`, and `line` fields 440 - are omitted. 468 + If `GIT_TR2_BRIEF` or `trace2.normalBrief` is true, the `time`, `filename`, 469 + and `line` fields are omitted. 441 470 442 471 This target is intended to be more of a summary (like GIT_TRACE) and 443 472 less detailed than the other targets. It ignores thread, region, and 444 473 data messages, for example. 445 474 446 475 === PERF Format 447 - 448 - PERF format is enabled when the `GIT_TR2_PERF` environment variable 449 - is set. 450 476 451 477 Events are written as lines of the form: 452 478 ··· 507 533 15:33:33.532712 wt-status.c:2331 | d0 | main | region_leave | r1 | 0.127568 | 0.001504 | status | label:print 508 534 ------------ 509 535 510 - If `GIT_TR2_PERF_BRIEF` is true, the `time`, `file`, and `line` 511 - fields are omitted. 536 + If `GIT_TR2_PERF_BRIEF` or `trace2.perfBrief` is true, the `time`, `file`, 537 + and `line` fields are omitted. 512 538 513 539 ------------ 514 540 d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload ··· 519 545 520 546 === EVENT Format 521 547 522 - EVENT format is enabled when the `GIT_TR2_EVENT` environment 523 - variable is set. 524 - 525 548 Each event is a JSON-object containing multiple key/value pairs 526 549 written as a single line and followed by a LF. 527 550 ··· 539 562 ------------ 540 563 { 541 564 "event":"version", 542 - "sid":"1547659722619736-11614", 565 + "sid":"20190408T191827.272759Z-H9b68c35f-P00003510", 543 566 "thread":"main", 544 - "time":"2019-01-16 17:28:42.620713", 567 + "time":"2019-04-08T19:18:27.282761Z", 545 568 "file":"common-main.c", 546 - "line":38, 569 + "line":42, 547 570 ... 548 571 } 549 572 ------------ ··· 575 598 `"repo":<repo-id>`:: 576 599 when present, is the integer repo-id as described previously. 577 600 578 - If `GIT_TR2_EVENT_BRIEF` is true, the `file` and `line` fields are omitted 579 - from all events and the `time` field is only present on the "start" and 580 - "atexit" events. 601 + If `GIT_TR2_EVENT_BRIEF` or `trace2.eventBrief` is true, the `file` 602 + and `line` fields are omitted from all events and the `time` field is 603 + only present on the "start" and "atexit" events. 581 604 582 605 ==== Event-Specific Key/Value Pairs 583 606 ··· 600 623 { 601 624 "event":"start", 602 625 ... 626 + "t_abs":0.001227, # elapsed time in seconds 603 627 "argv":["git","version"] 604 628 } 605 629 ------------ ··· 887 911 The `category` field may be used in a future enhancement to 888 912 do category-based filtering. 889 913 + 890 - The `GIT_TR2_EVENT_NESTING` environment variable can be used to 914 + `GIT_TR2_EVENT_NESTING` or `trace2.eventNesting` can be used to 891 915 filter deeply nested regions and data events. It defaults to "2". 892 916 893 917 `"region_leave"`:: ··· 1117 1141 1118 1142 $ cat ~/log.perf 1119 1143 d0 | main | version | | | | | 2.20.1.160.g5676107ecd.dirty 1120 - d0 | main | start | | | | | git status 1144 + d0 | main | start | | 0.001173 | | | git status 1121 1145 d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw 1122 1146 d0 | main | cmd_name | | | | | status (status) 1123 1147 ... ··· 1162 1186 ... 1163 1187 $ cat ~/log.perf 1164 1188 d0 | main | version | | | | | 2.20.1.162.gb4ccea44db.dirty 1165 - d0 | main | start | | | | | git status 1189 + d0 | main | start | | 0.001173 | | | git status 1166 1190 d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw 1167 1191 d0 | main | cmd_name | | | | | status (status) 1168 1192 ... ··· 1218 1242 ... 1219 1243 $ cat ~/log.perf 1220 1244 d0 | main | version | | | | | 2.20.1.156.gf9916ae094.dirty 1221 - d0 | main | start | | | | | git status 1245 + d0 | main | start | | 0.001173 | | | git status 1222 1246 d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw 1223 1247 d0 | main | cmd_name | | | | | status (status) 1224 1248 d0 | main | region_enter | r1 | 0.001791 | | index | label:do_read_index .git/index
+10
Documentation/trace2-target-values.txt
··· 1 + -- 2 + * `0` or `false` - Disables the target. 3 + * `1` or `true` - Writes to `STDERR`. 4 + * `[2-9]` - Writes to the already opened file descriptor. 5 + * `<absolute-pathname>` - Writes to the file in append mode. 6 + * `af_unix:[<socket_type>:]<absolute-pathname>` - Write to a 7 + Unix DomainSocket (on platforms that support them). Socket 8 + type can be either `stream` or `dgram`; if omitted Git will 9 + try both. 10 + --
+1
Makefile
··· 999 999 LIB_OBJS += trace2/tr2_cmd_name.o 1000 1000 LIB_OBJS += trace2/tr2_dst.o 1001 1001 LIB_OBJS += trace2/tr2_sid.o 1002 + LIB_OBJS += trace2/tr2_sysenv.o 1002 1003 LIB_OBJS += trace2/tr2_tbuf.o 1003 1004 LIB_OBJS += trace2/tr2_tgt_event.o 1004 1005 LIB_OBJS += trace2/tr2_tgt_normal.o
+5 -3
common-main.c
··· 27 27 { 28 28 int result; 29 29 30 + trace2_initialize_clock(); 31 + 30 32 /* 31 33 * Always open file descriptors 0/1/2 to avoid clobbering files 32 34 * in die(). It also avoids messing up when the pipes are dup'ed ··· 35 37 sanitize_stdfds(); 36 38 restore_sigpipe_to_default(); 37 39 40 + git_resolve_executable_dir(argv[0]); 41 + 38 42 trace2_initialize(); 39 43 trace2_cmd_start(argv); 40 - trace2_collect_process_info(); 41 - 42 - git_resolve_executable_dir(argv[0]); 44 + trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP); 43 45 44 46 git_setup_gettext(); 45 47
+2
compat/mingw.c
··· 2569 2569 wchar_t **wenv, **wargv; 2570 2570 _startupinfo si; 2571 2571 2572 + trace2_initialize_clock(); 2573 + 2572 2574 maybe_redirect_std_handles(); 2573 2575 2574 2576 /* get wide char arguments and environment */
+47 -3
compat/win32/trace2_win32_process_info.c
··· 1 1 #include "../../cache.h" 2 2 #include "../../json-writer.h" 3 + #include "lazyload.h" 3 4 #include <Psapi.h> 4 5 #include <tlHelp32.h> 5 6 ··· 137 138 "windows/debugger_present", 1); 138 139 } 139 140 140 - void trace2_collect_process_info(void) 141 + /* 142 + * Emit JSON data with the peak memory usage of the current process. 143 + */ 144 + static void get_peak_memory_info(void) 145 + { 146 + DECLARE_PROC_ADDR(psapi.dll, BOOL, GetProcessMemoryInfo, HANDLE, 147 + PPROCESS_MEMORY_COUNTERS, DWORD); 148 + 149 + if (INIT_PROC_ADDR(GetProcessMemoryInfo)) { 150 + PROCESS_MEMORY_COUNTERS pmc; 151 + 152 + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, 153 + sizeof(pmc))) { 154 + struct json_writer jw = JSON_WRITER_INIT; 155 + 156 + jw_object_begin(&jw, 0); 157 + 158 + #define KV(kv) #kv, (intmax_t)pmc.kv 159 + 160 + jw_object_intmax(&jw, KV(PageFaultCount)); 161 + jw_object_intmax(&jw, KV(PeakWorkingSetSize)); 162 + jw_object_intmax(&jw, KV(PeakPagefileUsage)); 163 + 164 + jw_end(&jw); 165 + 166 + trace2_data_json("process", the_repository, 167 + "windows/memory", &jw); 168 + jw_release(&jw); 169 + } 170 + } 171 + } 172 + 173 + void trace2_collect_process_info(enum trace2_process_info_reason reason) 141 174 { 142 175 if (!trace2_is_enabled()) 143 176 return; 144 177 145 - get_is_being_debugged(); 146 - get_ancestry(); 178 + switch (reason) { 179 + case TRACE2_PROCESS_INFO_STARTUP: 180 + get_is_being_debugged(); 181 + get_ancestry(); 182 + return; 183 + 184 + case TRACE2_PROCESS_INFO_EXIT: 185 + get_peak_memory_info(); 186 + return; 187 + 188 + default: 189 + BUG("trace2_collect_process_info: unknown reason '%d'", reason); 190 + } 147 191 }
+25 -5
config.c
··· 1676 1676 repo_config = NULL; 1677 1677 1678 1678 current_parsing_scope = CONFIG_SCOPE_SYSTEM; 1679 - if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) 1679 + if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 1680 + opts->system_gently ? 1681 + ACCESS_EACCES_OK : 0)) 1680 1682 ret += git_config_from_file(fn, git_etc_gitconfig(), 1681 1683 data); 1682 1684 ··· 1688 1690 ret += git_config_from_file(fn, user_config, data); 1689 1691 1690 1692 current_parsing_scope = CONFIG_SCOPE_REPO; 1691 - if (repo_config && !access_or_die(repo_config, R_OK, 0)) 1693 + if (!opts->ignore_repo && repo_config && 1694 + !access_or_die(repo_config, R_OK, 0)) 1692 1695 ret += git_config_from_file(fn, repo_config, data); 1693 1696 1694 1697 /* 1695 1698 * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE. 1696 1699 * But let's not complicate things before it's actually needed. 1697 1700 */ 1698 - if (repository_format_worktree_config) { 1701 + if (!opts->ignore_worktree && repository_format_worktree_config) { 1699 1702 char *path = git_pathdup("config.worktree"); 1700 1703 if (!access_or_die(path, R_OK, 0)) 1701 1704 ret += git_config_from_file(fn, path, data); ··· 1703 1706 } 1704 1707 1705 1708 current_parsing_scope = CONFIG_SCOPE_CMDLINE; 1706 - if (git_config_from_parameters(fn, data) < 0) 1709 + if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0) 1707 1710 die(_("unable to parse command-line config")); 1708 1711 1709 1712 current_parsing_scope = CONFIG_SCOPE_UNKNOWN; ··· 1792 1795 1793 1796 strbuf_release(&commondir); 1794 1797 strbuf_release(&gitdir); 1798 + } 1799 + 1800 + /* 1801 + * Read config but only enumerate system and global settings. 1802 + * Omit any repo-local, worktree-local, or command-line settings. 1803 + */ 1804 + void read_very_early_config(config_fn_t cb, void *data) 1805 + { 1806 + struct config_options opts = { 0 }; 1807 + 1808 + opts.respect_includes = 1; 1809 + opts.ignore_repo = 1; 1810 + opts.ignore_worktree = 1; 1811 + opts.ignore_cmdline = 1; 1812 + opts.system_gently = 1; 1813 + 1814 + config_with_options(cb, data, NULL, &opts); 1795 1815 } 1796 1816 1797 1817 static struct config_set_element *configset_find_element(struct config_set *cs, const char *key) ··· 2011 2031 /* Functions use to read configuration from a repository */ 2012 2032 static void repo_read_config(struct repository *repo) 2013 2033 { 2014 - struct config_options opts; 2034 + struct config_options opts = { 0 }; 2015 2035 2016 2036 opts.respect_includes = 1; 2017 2037 opts.commondir = repo->commondir;
+5
config.h
··· 55 55 56 56 struct config_options { 57 57 unsigned int respect_includes : 1; 58 + unsigned int ignore_repo : 1; 59 + unsigned int ignore_worktree : 1; 60 + unsigned int ignore_cmdline : 1; 61 + unsigned int system_gently : 1; 58 62 const char *commondir; 59 63 const char *git_dir; 60 64 config_parser_event_fn_t event_fn; ··· 83 87 extern void git_config_push_parameter(const char *text); 84 88 extern int git_config_from_parameters(config_fn_t fn, void *data); 85 89 extern void read_early_config(config_fn_t cb, void *data); 90 + extern void read_very_early_config(config_fn_t cb, void *data); 86 91 extern void git_config(config_fn_t fn, void *); 87 92 extern int config_with_options(config_fn_t fn, void *, 88 93 struct git_config_source *config_source,
+44 -5
t/t0210-trace2-normal.sh
··· 3 3 test_description='test trace2 facility (normal target)' 4 4 . ./test-lib.sh 5 5 6 + # Turn off any inherited trace2 settings for this test. 7 + sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 8 + sane_unset GIT_TR2_BRIEF 9 + sane_unset GIT_TR2_CONFIG_PARAMS 10 + 6 11 # Add t/helper directory to PATH so that we can use a relative 7 12 # path to run nested instances of test-tool.exe (see 004child). 8 13 # This helps with HEREDOC comparisons later. ··· 14 19 # Warning: only cover our actual calls to test-tool and/or git. 15 20 # Warning: So you may see extra lines in artifact files when 16 21 # Warning: interactively debugging. 17 - 18 - # Turn off any inherited trace2 settings for this test. 19 - unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 20 - unset GIT_TR2_BRIEF 21 - unset GIT_TR2_CONFIG_PARAMS 22 22 23 23 V=$(git version | sed -e 's/^git version //') && export V 24 24 ··· 141 141 cmd_name trace2 (trace2) 142 142 error hello world 143 143 error this is a test 144 + exit elapsed:_TIME_ code:0 145 + atexit elapsed:_TIME_ code:0 146 + EOF 147 + test_cmp expect actual 148 + ' 149 + 150 + sane_unset GIT_TR2_BRIEF 151 + 152 + # Now test without environment variables and get all Trace2 settings 153 + # from the global config. 154 + 155 + test_expect_success 'using global config, normal stream, return code 0' ' 156 + test_when_finished "rm trace.normal actual expect" && 157 + test_config_global trace2.normalBrief 1 && 158 + test_config_global trace2.normalTarget "$(pwd)/trace.normal" && 159 + test-tool trace2 001return 0 && 160 + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && 161 + cat >expect <<-EOF && 162 + version $V 163 + start _EXE_ trace2 001return 0 164 + cmd_name trace2 (trace2) 165 + exit elapsed:_TIME_ code:0 166 + atexit elapsed:_TIME_ code:0 167 + EOF 168 + test_cmp expect actual 169 + ' 170 + 171 + test_expect_success 'using global config with include' ' 172 + test_when_finished "rm trace.normal actual expect real.gitconfig" && 173 + test_config_global trace2.normalBrief 1 && 174 + test_config_global trace2.normalTarget "$(pwd)/trace.normal" && 175 + mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" && 176 + test_config_global include.path "$(pwd)/real.gitconfig" && 177 + test-tool trace2 001return 0 && 178 + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && 179 + cat >expect <<-EOF && 180 + version $V 181 + start _EXE_ trace2 001return 0 182 + cmd_name trace2 (trace2) 144 183 exit elapsed:_TIME_ code:0 145 184 atexit elapsed:_TIME_ code:0 146 185 EOF
+32 -11
t/t0211-trace2-perf.sh
··· 3 3 test_description='test trace2 facility (perf target)' 4 4 . ./test-lib.sh 5 5 6 + # Turn off any inherited trace2 settings for this test. 7 + sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 8 + sane_unset GIT_TR2_PERF_BRIEF 9 + sane_unset GIT_TR2_CONFIG_PARAMS 10 + 6 11 # Add t/helper directory to PATH so that we can use a relative 7 12 # path to run nested instances of test-tool.exe (see 004child). 8 13 # This helps with HEREDOC comparisons later. ··· 14 19 # Warning: only cover our actual calls to test-tool and/or git. 15 20 # Warning: So you may see extra lines in artifact files when 16 21 # Warning: interactively debugging. 17 - 18 - # Turn off any inherited trace2 settings for this test. 19 - unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 20 - unset GIT_TR2_PERF_BRIEF 21 - unset GIT_TR2_CONFIG_PARAMS 22 22 23 23 V=$(git version | sed -e 's/^git version //') && export V 24 24 ··· 50 50 perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && 51 51 cat >expect <<-EOF && 52 52 d0|main|version|||||$V 53 - d0|main|start|||||_EXE_ trace2 001return 0 53 + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 0 54 54 d0|main|cmd_name|||||trace2 (trace2) 55 55 d0|main|exit||_T_ABS_|||code:0 56 56 d0|main|atexit||_T_ABS_|||code:0 ··· 64 64 perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && 65 65 cat >expect <<-EOF && 66 66 d0|main|version|||||$V 67 - d0|main|start|||||_EXE_ trace2 001return 1 67 + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 1 68 68 d0|main|cmd_name|||||trace2 (trace2) 69 69 d0|main|exit||_T_ABS_|||code:1 70 70 d0|main|atexit||_T_ABS_|||code:1 ··· 82 82 perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && 83 83 cat >expect <<-EOF && 84 84 d0|main|version|||||$V 85 - d0|main|start|||||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' 85 + d0|main|start||_T_ABS_|||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' 86 86 d0|main|cmd_name|||||trace2 (trace2) 87 87 d0|main|error|||||hello world 88 88 d0|main|error|||||this is a test ··· 128 128 perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && 129 129 cat >expect <<-EOF && 130 130 d0|main|version|||||$V 131 - d0|main|start|||||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 131 + d0|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 132 132 d0|main|cmd_name|||||trace2 (trace2) 133 133 d0|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 004child test-tool trace2 001return 0 134 134 d1|main|version|||||$V 135 - d1|main|start|||||_EXE_ trace2 004child test-tool trace2 001return 0 135 + d1|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 001return 0 136 136 d1|main|cmd_name|||||trace2 (trace2/trace2) 137 137 d1|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 001return 0 138 138 d2|main|version|||||$V 139 - d2|main|start|||||_EXE_ trace2 001return 0 139 + d2|main|start||_T_ABS_|||_EXE_ trace2 001return 0 140 140 d2|main|cmd_name|||||trace2 (trace2/trace2/trace2) 141 141 d2|main|exit||_T_ABS_|||code:0 142 142 d2|main|atexit||_T_ABS_|||code:0 ··· 144 144 d1|main|exit||_T_ABS_|||code:0 145 145 d1|main|atexit||_T_ABS_|||code:0 146 146 d0|main|child_exit||_T_ABS_|_T_REL_||[ch0] pid:_PID_ code:0 147 + d0|main|exit||_T_ABS_|||code:0 148 + d0|main|atexit||_T_ABS_|||code:0 149 + EOF 150 + test_cmp expect actual 151 + ' 152 + 153 + sane_unset GIT_TR2_PERF_BRIEF 154 + 155 + # Now test without environment variables and get all Trace2 settings 156 + # from the global config. 157 + 158 + test_expect_success 'using global config, perf stream, return code 0' ' 159 + test_when_finished "rm trace.perf actual expect" && 160 + test_config_global trace2.perfBrief 1 && 161 + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && 162 + test-tool trace2 001return 0 && 163 + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && 164 + cat >expect <<-EOF && 165 + d0|main|version|||||$V 166 + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 0 167 + d0|main|cmd_name|||||trace2 (trace2) 147 168 d0|main|exit||_T_ABS_|||code:0 148 169 d0|main|atexit||_T_ABS_|||code:0 149 170 EOF
+37 -5
t/t0212-trace2-event.sh
··· 3 3 test_description='test trace2 facility' 4 4 . ./test-lib.sh 5 5 6 + # Turn off any inherited trace2 settings for this test. 7 + sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 8 + sane_unset GIT_TR2_BARE 9 + sane_unset GIT_TR2_CONFIG_PARAMS 10 + 6 11 perl -MJSON::PP -e 0 >/dev/null 2>&1 && test_set_prereq JSON_PP 7 12 8 13 # Add t/helper directory to PATH so that we can use a relative ··· 16 21 # Warning: only cover our actual calls to test-tool and/or git. 17 22 # Warning: So you may see extra lines in artifact files when 18 23 # Warning: interactively debugging. 19 - 20 - # Turn off any inherited trace2 settings for this test. 21 - unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT 22 - unset GIT_TR2_BARE 23 - unset GIT_TR2_CONFIG_PARAMS 24 24 25 25 V=$(git version | sed -e 's/^git version //') && export V 26 26 ··· 223 223 | "k2":"v2" 224 224 | } 225 225 | }, 226 + | "exit_code":0, 227 + | "hierarchy":"trace2", 228 + | "name":"trace2", 229 + | "version":"$V" 230 + | } 231 + |}; 232 + EOF 233 + test_cmp expect actual 234 + ' 235 + 236 + # Now test without environment variables and get all Trace2 settings 237 + # from the global config. 238 + 239 + test_expect_success JSON_PP 'using global config, event stream, error event' ' 240 + test_when_finished "rm trace.event actual expect" && 241 + test_config_global trace2.eventTarget "$(pwd)/trace.event" && 242 + test-tool trace2 003error "hello world" "this is a test" && 243 + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && 244 + sed -e "s/^|//" >expect <<-EOF && 245 + |VAR1 = { 246 + | "_SID0_":{ 247 + | "argv":[ 248 + | "_EXE_", 249 + | "trace2", 250 + | "003error", 251 + | "hello world", 252 + | "this is a test" 253 + | ], 254 + | "errors":[ 255 + | "%s", 256 + | "%s" 257 + | ], 226 258 | "exit_code":0, 227 259 | "hierarchy":"trace2", 228 260 | "name":"trace2",
+19 -2
trace2.c
··· 10 10 #include "trace2/tr2_cmd_name.h" 11 11 #include "trace2/tr2_dst.h" 12 12 #include "trace2/tr2_sid.h" 13 + #include "trace2/tr2_sysenv.h" 13 14 #include "trace2/tr2_tgt.h" 14 15 #include "trace2/tr2_tls.h" 15 16 ··· 120 121 tr2_sid_release(); 121 122 tr2_cmd_name_release(); 122 123 tr2_cfg_free_patterns(); 124 + tr2_sysenv_release(); 123 125 124 126 trace2_enabled = 0; 125 127 } ··· 142 144 raise(signo); 143 145 } 144 146 147 + void trace2_initialize_clock(void) 148 + { 149 + tr2tls_start_process_clock(); 150 + } 151 + 145 152 void trace2_initialize_fl(const char *file, int line) 146 153 { 147 154 struct tr2_tgt *tgt_j; ··· 149 156 150 157 if (trace2_enabled) 151 158 return; 159 + 160 + tr2_sysenv_load(); 152 161 153 162 if (!tr2_tgt_want_builtins()) 154 163 return; ··· 177 186 { 178 187 struct tr2_tgt *tgt_j; 179 188 int j; 189 + uint64_t us_now; 190 + uint64_t us_elapsed_absolute; 180 191 181 192 if (!trace2_enabled) 182 193 return; 183 194 195 + us_now = getnanotime() / 1000; 196 + us_elapsed_absolute = tr2tls_absolute_elapsed(us_now); 197 + 184 198 for_each_wanted_builtin (j, tgt_j) 185 199 if (tgt_j->pfn_start_fl) 186 - tgt_j->pfn_start_fl(file, line, argv); 200 + tgt_j->pfn_start_fl(file, line, us_elapsed_absolute, 201 + argv); 187 202 } 188 203 189 204 int trace2_cmd_exit_fl(const char *file, int line, int code) ··· 197 212 198 213 if (!trace2_enabled) 199 214 return code; 215 + 216 + trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT); 200 217 201 218 tr2main_exit_code = code; 202 219 ··· 428 445 us_now = getnanotime() / 1000; 429 446 us_elapsed_absolute = tr2tls_absolute_elapsed(us_now); 430 447 431 - tr2tls_create_self(thread_name); 448 + tr2tls_create_self(thread_name, us_now); 432 449 433 450 for_each_wanted_builtin (j, tgt_j) 434 451 if (tgt_j->pfn_thread_start_fl)
+34 -9
trace2.h
··· 20 20 */ 21 21 22 22 /* 23 + * Initialize the TRACE2 clock and do nothing else, in particular 24 + * no mallocs, no system inspection, and no environment inspection. 25 + * 26 + * This should be called at the very top of main() to capture the 27 + * process start time. This is intended to reduce chicken-n-egg 28 + * bootstrap pressure. 29 + * 30 + * It is safe to call this more than once. This allows capturing 31 + * absolute startup costs on Windows which uses a little trickery 32 + * to do setup work before common-main.c:main() is called. 33 + * 34 + * The main trace2_initialize_fl() may be called a little later 35 + * after more infrastructure is established. 36 + */ 37 + void trace2_initialize_clock(void); 38 + 39 + /* 23 40 * Initialize TRACE2 tracing facility if any of the builtin TRACE2 24 - * targets are enabled in the environment. Emits a 'version' event. 41 + * targets are enabled in the system config or the environment. 42 + * Emits a 'version' event. 25 43 * 26 44 * Cleanup/Termination is handled automatically by a registered 27 45 * atexit() routine. ··· 108 126 * Emit one or more 'def_param' events for "interesting" configuration 109 127 * settings. 110 128 * 111 - * The environment variable "GIT_TR2_CONFIG_PARAMS" can be set to a 112 - * list of patterns considered important. For example: 113 - * 114 - * GIT_TR2_CONFIG_PARAMS="core.*,remote.*.url" 129 + * Use the TR2_SYSENV_CFG_PARAM setting to register a comma-separated 130 + * list of patterns configured important. For example: 131 + * git config --system trace2.configParams 'core.*,remote.*.url' 132 + * or: 133 + * GIT_TR2_CONFIG_PARAMS=core.*,remote.*.url" 115 134 * 116 135 * Note: this routine does a read-only iteration on the config data 117 136 * (using read_early_config()), so it must not be called until enough ··· 372 391 * Optional platform-specific code to dump information about the 373 392 * current and any parent process(es). This is intended to allow 374 393 * post-processors to know who spawned this git instance and anything 375 - * else the platform may be able to tell us about the current process. 394 + * else that the platform may be able to tell us about the current process. 376 395 */ 396 + 397 + enum trace2_process_info_reason { 398 + TRACE2_PROCESS_INFO_STARTUP, 399 + TRACE2_PROCESS_INFO_EXIT, 400 + }; 401 + 377 402 #if defined(GIT_WINDOWS_NATIVE) 378 - void trace2_collect_process_info(void); 403 + void trace2_collect_process_info(enum trace2_process_info_reason reason); 379 404 #else 380 - #define trace2_collect_process_info() \ 381 - do { \ 405 + #define trace2_collect_process_info(reason) \ 406 + do { \ 382 407 } while (0) 383 408 #endif 384 409
+3 -4
trace2/tr2_cfg.c
··· 1 1 #include "cache.h" 2 2 #include "config.h" 3 - #include "tr2_cfg.h" 4 - 5 - #define TR2_ENVVAR_CFG_PARAM "GIT_TR2_CONFIG_PARAMS" 3 + #include "trace2/tr2_cfg.h" 4 + #include "trace2/tr2_sysenv.h" 6 5 7 6 static struct strbuf **tr2_cfg_patterns; 8 7 static int tr2_cfg_count_patterns; ··· 21 20 return tr2_cfg_count_patterns; 22 21 tr2_cfg_loaded = 1; 23 22 24 - envvar = getenv(TR2_ENVVAR_CFG_PARAM); 23 + envvar = tr2_sysenv_get(TR2_SYSENV_CFG_PARAM); 25 24 if (!envvar || !*envvar) 26 25 return tr2_cfg_count_patterns; 27 26
+16 -20
trace2/tr2_dst.c
··· 1 1 #include "cache.h" 2 2 #include "trace2/tr2_dst.h" 3 3 #include "trace2/tr2_sid.h" 4 - 5 - /* 6 - * If a Trace2 target cannot be opened for writing, we should issue a 7 - * warning to stderr, but this is very annoying if the target is a pipe 8 - * or socket and beyond the user's control -- especially since every 9 - * git command (and sub-command) will print the message. So we silently 10 - * eat these warnings and just discard the trace data. 11 - * 12 - * Enable the following environment variable to see these warnings. 13 - */ 14 - #define TR2_ENVVAR_DST_DEBUG "GIT_TR2_DST_DEBUG" 4 + #include "trace2/tr2_sysenv.h" 15 5 16 6 /* 17 7 * How many attempts we will make at creating an automatically-named trace file. ··· 23 13 static int tr2env_dst_debug = -1; 24 14 25 15 if (tr2env_dst_debug == -1) { 26 - const char *env_value = getenv(TR2_ENVVAR_DST_DEBUG); 16 + const char *env_value = tr2_sysenv_get(TR2_SYSENV_DST_DEBUG); 27 17 if (!env_value || !*env_value) 28 18 tr2env_dst_debug = 0; 29 19 else ··· 75 65 if (tr2_dst_want_warning()) 76 66 warning("trace2: could not open '%.*s' for '%s' tracing: %s", 77 67 (int) base_path_len, path.buf, 78 - dst->env_var_name, strerror(errno)); 68 + tr2_sysenv_display_name(dst->sysenv_var), 69 + strerror(errno)); 79 70 80 71 tr2_dst_trace_disable(dst); 81 72 strbuf_release(&path); ··· 97 88 if (fd == -1) { 98 89 if (tr2_dst_want_warning()) 99 90 warning("trace2: could not open '%s' for '%s' tracing: %s", 100 - tgt_value, dst->env_var_name, strerror(errno)); 91 + tgt_value, 92 + tr2_sysenv_display_name(dst->sysenv_var), 93 + strerror(errno)); 101 94 102 95 tr2_dst_trace_disable(dst); 103 96 return 0; ··· 171 164 if (!path || !*path) { 172 165 if (tr2_dst_want_warning()) 173 166 warning("trace2: invalid AF_UNIX value '%s' for '%s' tracing", 174 - tgt_value, dst->env_var_name); 167 + tgt_value, 168 + tr2_sysenv_display_name(dst->sysenv_var)); 175 169 176 170 tr2_dst_trace_disable(dst); 177 171 return 0; ··· 181 175 strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { 182 176 if (tr2_dst_want_warning()) 183 177 warning("trace2: invalid AF_UNIX path '%s' for '%s' tracing", 184 - path, dst->env_var_name); 178 + path, tr2_sysenv_display_name(dst->sysenv_var)); 185 179 186 180 tr2_dst_trace_disable(dst); 187 181 return 0; ··· 203 197 error: 204 198 if (tr2_dst_want_warning()) 205 199 warning("trace2: could not connect to socket '%s' for '%s' tracing: %s", 206 - path, dst->env_var_name, strerror(e)); 200 + path, tr2_sysenv_display_name(dst->sysenv_var), 201 + strerror(e)); 207 202 208 203 tr2_dst_trace_disable(dst); 209 204 return 0; ··· 223 218 struct strbuf buf = STRBUF_INIT; 224 219 225 220 strbuf_addf(&buf, "trace2: unknown value for '%s': '%s'", 226 - dst->env_var_name, tgt_value); 221 + tr2_sysenv_display_name(dst->sysenv_var), tgt_value); 227 222 warning("%s", buf.buf); 228 223 229 224 strbuf_release(&buf); ··· 239 234 240 235 dst->initialized = 1; 241 236 242 - tgt_value = getenv(dst->env_var_name); 237 + tgt_value = tr2_sysenv_get(dst->sysenv_var); 243 238 244 239 if (!tgt_value || !strcmp(tgt_value, "") || !strcmp(tgt_value, "0") || 245 240 !strcasecmp(tgt_value, "false")) { ··· 305 300 return; 306 301 307 302 if (tr2_dst_want_warning()) 308 - warning("unable to write trace to '%s': %s", dst->env_var_name, 303 + warning("unable to write trace to '%s': %s", 304 + tr2_sysenv_display_name(dst->sysenv_var), 309 305 strerror(errno)); 310 306 tr2_dst_trace_disable(dst); 311 307 }
+2 -1
trace2/tr2_dst.h
··· 2 2 #define TR2_DST_H 3 3 4 4 struct strbuf; 5 + #include "trace2/tr2_sysenv.h" 5 6 6 7 struct tr2_dst { 7 - const char *const env_var_name; 8 + enum tr2_sysenv_variable sysenv_var; 8 9 int fd; 9 10 unsigned int initialized : 1; 10 11 unsigned int need_close : 1;
+49 -4
trace2/tr2_sid.c
··· 1 1 #include "cache.h" 2 + #include "trace2/tr2_tbuf.h" 2 3 #include "trace2/tr2_sid.h" 3 4 4 5 #define TR2_ENVVAR_PARENT_SID "GIT_TR2_PARENT_SID" ··· 7 8 static int tr2sid_nr_git_parents; 8 9 9 10 /* 11 + * Compute the final component of the SID representing the current process. 12 + * This should uniquely identify the process and be a valid filename (to 13 + * allow writing trace2 data to per-process files). It should also be fixed 14 + * length for possible use as a database key. 15 + * 16 + * "<yyyymmdd>T<hhmmss>.<fraction>Z-<host>-<process>" 17 + * 18 + * where <host> is a 9 character string: 19 + * "H<first_8_chars_of_sha1_of_hostname>" 20 + * "Localhost" when no hostname. 21 + * 22 + * where <process> is a 9 character string containing the least signifcant 23 + * 32 bits in the process-id. 24 + * "P<pid>" 25 + * (This is an abribrary choice. On most systems pid_t is a 32 bit value, 26 + * so limit doesn't matter. On larger systems, a truncated value is fine 27 + * for our purposes here.) 28 + */ 29 + static void tr2_sid_append_my_sid_component(void) 30 + { 31 + const struct git_hash_algo *algo = &hash_algos[GIT_HASH_SHA1]; 32 + struct tr2_tbuf tb_now; 33 + git_hash_ctx ctx; 34 + pid_t pid = getpid(); 35 + unsigned char hash[GIT_MAX_RAWSZ + 1]; 36 + char hex[GIT_MAX_HEXSZ + 1]; 37 + char hostname[HOST_NAME_MAX + 1]; 38 + 39 + tr2_tbuf_utc_datetime(&tb_now); 40 + strbuf_addstr(&tr2sid_buf, tb_now.buf); 41 + 42 + strbuf_addch(&tr2sid_buf, '-'); 43 + if (xgethostname(hostname, sizeof(hostname))) 44 + strbuf_add(&tr2sid_buf, "Localhost", 9); 45 + else { 46 + algo->init_fn(&ctx); 47 + algo->update_fn(&ctx, hostname, strlen(hostname)); 48 + algo->final_fn(hash, &ctx); 49 + hash_to_hex_algop_r(hex, hash, algo); 50 + strbuf_addch(&tr2sid_buf, 'H'); 51 + strbuf_add(&tr2sid_buf, hex, 8); 52 + } 53 + 54 + strbuf_addf(&tr2sid_buf, "-P%08"PRIx32, (uint32_t)pid); 55 + } 56 + 57 + /* 10 58 * Compute a "unique" session id (SID) for the current process. This allows 11 59 * all events from this process to have a single label (much like a PID). 12 60 * ··· 20 68 */ 21 69 static void tr2_sid_compute(void) 22 70 { 23 - uint64_t us_now; 24 71 const char *parent_sid; 25 72 26 73 if (tr2sid_buf.len) ··· 38 85 tr2sid_nr_git_parents++; 39 86 } 40 87 41 - us_now = getnanotime() / 1000; 42 - strbuf_addf(&tr2sid_buf, "%" PRIuMAX "-%" PRIdMAX, (uintmax_t)us_now, 43 - (intmax_t)getpid()); 88 + tr2_sid_append_my_sid_component(); 44 89 45 90 setenv(TR2_ENVVAR_PARENT_SID, tr2sid_buf.buf, 1); 46 91 }
+127
trace2/tr2_sysenv.c
··· 1 + #include "cache.h" 2 + #include "config.h" 3 + #include "dir.h" 4 + #include "tr2_sysenv.h" 5 + 6 + /* 7 + * Each entry represents a trace2 setting. 8 + * See Documentation/technical/api-trace2.txt 9 + */ 10 + struct tr2_sysenv_entry { 11 + const char *env_var_name; 12 + const char *git_config_name; 13 + 14 + char *value; 15 + unsigned int getenv_called : 1; 16 + }; 17 + 18 + /* 19 + * This table must match "enum tr2_sysenv_variable" in tr2_sysenv.h. 20 + * 21 + * The strings in this table are constant and must match the published 22 + * config and environment variable names as described in the documentation. 23 + * 24 + * We do not define entries for the GIT_TR2_PARENT_* environment 25 + * variables because they are transient and used to pass information 26 + * from parent to child git processes, rather than settings. 27 + */ 28 + /* clang-format off */ 29 + static struct tr2_sysenv_entry tr2_sysenv_settings[] = { 30 + [TR2_SYSENV_CFG_PARAM] = { "GIT_TR2_CONFIG_PARAMS", 31 + "trace2.configparams" }, 32 + 33 + [TR2_SYSENV_DST_DEBUG] = { "GIT_TR2_DST_DEBUG", 34 + "trace2.destinationdebug" }, 35 + 36 + [TR2_SYSENV_NORMAL] = { "GIT_TR2", 37 + "trace2.normaltarget" }, 38 + [TR2_SYSENV_NORMAL_BRIEF] = { "GIT_TR2_BRIEF", 39 + "trace2.normalbrief" }, 40 + 41 + [TR2_SYSENV_EVENT] = { "GIT_TR2_EVENT", 42 + "trace2.eventtarget" }, 43 + [TR2_SYSENV_EVENT_BRIEF] = { "GIT_TR2_EVENT_BRIEF", 44 + "trace2.eventbrief" }, 45 + [TR2_SYSENV_EVENT_NESTING] = { "GIT_TR2_EVENT_NESTING", 46 + "trace2.eventnesting" }, 47 + 48 + [TR2_SYSENV_PERF] = { "GIT_TR2_PERF", 49 + "trace2.perftarget" }, 50 + [TR2_SYSENV_PERF_BRIEF] = { "GIT_TR2_PERF_BRIEF", 51 + "trace2.perfbrief" }, 52 + }; 53 + /* clang-format on */ 54 + 55 + static int tr2_sysenv_cb(const char *key, const char *value, void *d) 56 + { 57 + int k; 58 + 59 + if (!starts_with(key, "trace2.")) 60 + return 0; 61 + 62 + for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) { 63 + if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) { 64 + free(tr2_sysenv_settings[k].value); 65 + tr2_sysenv_settings[k].value = xstrdup(value); 66 + return 0; 67 + } 68 + } 69 + 70 + return 0; 71 + } 72 + 73 + /* 74 + * Load Trace2 settings from the system config (usually "/etc/gitconfig" 75 + * unless we were built with a runtime-prefix). These are intended to 76 + * define the default values for Trace2 as requested by the administrator. 77 + * 78 + * Then override with the Trace2 settings from the global config. 79 + */ 80 + void tr2_sysenv_load(void) 81 + { 82 + if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST) 83 + BUG("tr2_sysenv_settings size is wrong"); 84 + 85 + read_very_early_config(tr2_sysenv_cb, NULL); 86 + } 87 + 88 + /* 89 + * Return the value for the requested Trace2 setting from these sources: 90 + * the system config, the global config, and the environment. 91 + */ 92 + const char *tr2_sysenv_get(enum tr2_sysenv_variable var) 93 + { 94 + if (var >= TR2_SYSENV_MUST_BE_LAST) 95 + BUG("tr2_sysenv_get invalid var '%d'", var); 96 + 97 + if (!tr2_sysenv_settings[var].getenv_called) { 98 + const char *v = getenv(tr2_sysenv_settings[var].env_var_name); 99 + if (v && *v) { 100 + free(tr2_sysenv_settings[var].value); 101 + tr2_sysenv_settings[var].value = xstrdup(v); 102 + } 103 + tr2_sysenv_settings[var].getenv_called = 1; 104 + } 105 + 106 + return tr2_sysenv_settings[var].value; 107 + } 108 + 109 + /* 110 + * Return a friendly name for this setting that is suitable for printing 111 + * in an error messages. 112 + */ 113 + const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var) 114 + { 115 + if (var >= TR2_SYSENV_MUST_BE_LAST) 116 + BUG("tr2_sysenv_get invalid var '%d'", var); 117 + 118 + return tr2_sysenv_settings[var].env_var_name; 119 + } 120 + 121 + void tr2_sysenv_release(void) 122 + { 123 + int k; 124 + 125 + for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) 126 + free(tr2_sysenv_settings[k].value); 127 + }
+36
trace2/tr2_sysenv.h
··· 1 + #ifndef TR2_SYSENV_H 2 + #define TR2_SYSENV_H 3 + 4 + /* 5 + * The Trace2 settings that can be loaded from /etc/gitconfig 6 + * and/or user environment variables. 7 + * 8 + * Note that this set does not contain any of the transient 9 + * environment variables used to pass information from parent 10 + * to child git processes, such "GIT_TR2_PARENT_SID". 11 + */ 12 + enum tr2_sysenv_variable { 13 + TR2_SYSENV_CFG_PARAM = 0, 14 + 15 + TR2_SYSENV_DST_DEBUG, 16 + 17 + TR2_SYSENV_NORMAL, 18 + TR2_SYSENV_NORMAL_BRIEF, 19 + 20 + TR2_SYSENV_EVENT, 21 + TR2_SYSENV_EVENT_BRIEF, 22 + TR2_SYSENV_EVENT_NESTING, 23 + 24 + TR2_SYSENV_PERF, 25 + TR2_SYSENV_PERF_BRIEF, 26 + 27 + TR2_SYSENV_MUST_BE_LAST 28 + }; 29 + 30 + void tr2_sysenv_load(void); 31 + 32 + const char *tr2_sysenv_get(enum tr2_sysenv_variable); 33 + const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var); 34 + void tr2_sysenv_release(void); 35 + 36 + #endif /* TR2_SYSENV_H */
+17 -2
trace2/tr2_tbuf.c
··· 15 15 tm.tm_min, tm.tm_sec, (long)tv.tv_usec); 16 16 } 17 17 18 - void tr2_tbuf_utc_time(struct tr2_tbuf *tb) 18 + void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb) 19 19 { 20 20 struct timeval tv; 21 21 struct tm tm; ··· 26 26 gmtime_r(&secs, &tm); 27 27 28 28 xsnprintf(tb->buf, sizeof(tb->buf), 29 - "%4d-%02d-%02d %02d:%02d:%02d.%06ld", tm.tm_year + 1900, 29 + "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", tm.tm_year + 1900, 30 30 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 31 31 (long)tv.tv_usec); 32 32 } 33 + 34 + void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb) 35 + { 36 + struct timeval tv; 37 + struct tm tm; 38 + time_t secs; 39 + 40 + gettimeofday(&tv, NULL); 41 + secs = tv.tv_sec; 42 + gmtime_r(&secs, &tm); 43 + 44 + xsnprintf(tb->buf, sizeof(tb->buf), "%4d%02d%02dT%02d%02d%02d.%06ldZ", 45 + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, 46 + tm.tm_min, tm.tm_sec, (long)tv.tv_usec); 47 + }
+3 -2
trace2/tr2_tbuf.h
··· 16 16 void tr2_tbuf_local_time(struct tr2_tbuf *tb); 17 17 18 18 /* 19 - * Fill buffer with formatted UTC time string. 19 + * Fill buffer with formatted UTC datatime string. 20 20 */ 21 - void tr2_tbuf_utc_time(struct tr2_tbuf *tb); 21 + void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb); 22 + void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb); 22 23 23 24 #endif /* TR2_TBUF_H */
+1
trace2/tr2_tgt.h
··· 15 15 typedef void(tr2_tgt_evt_version_fl_t)(const char *file, int line); 16 16 17 17 typedef void(tr2_tgt_evt_start_fl_t)(const char *file, int line, 18 + uint64_t us_elapsed_absolute, 18 19 const char **argv); 19 20 typedef void(tr2_tgt_evt_exit_fl_t)(const char *file, int line, 20 21 uint64_t us_elapsed_absolute, int code);
+28 -25
trace2/tr2_tgt_event.c
··· 6 6 #include "trace2/tr2_dst.h" 7 7 #include "trace2/tr2_tbuf.h" 8 8 #include "trace2/tr2_sid.h" 9 + #include "trace2/tr2_sysenv.h" 9 10 #include "trace2/tr2_tgt.h" 10 11 #include "trace2/tr2_tls.h" 11 12 12 - static struct tr2_dst tr2dst_event = { "GIT_TR2_EVENT", 0, 0, 0 }; 13 + static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0 }; 13 14 14 15 /* 15 16 * The version number of the JSON data generated by the EVENT target ··· 28 29 * are primarily intended for the performance target during debugging. 29 30 * 30 31 * Some of the outer-most messages, however, may be of interest to the 31 - * event target. Set this environment variable to a larger integer for 32 - * more detail in the event target. 32 + * event target. Use the TR2_SYSENV_EVENT_NESTING setting to increase 33 + * region details in the event target. 33 34 */ 34 - #define TR2_ENVVAR_EVENT_NESTING "GIT_TR2_EVENT_NESTING" 35 - static int tr2env_event_nesting_wanted = 2; 35 + static int tr2env_event_max_nesting_levels = 2; 36 36 37 37 /* 38 - * Set this environment variable to true to omit the <time>, <file>, and 38 + * Use the TR2_SYSENV_EVENT_BRIEF to omit the <time>, <file>, and 39 39 * <line> fields from most events. 40 40 */ 41 - #define TR2_ENVVAR_EVENT_BRIEF "GIT_TR2_EVENT_BRIEF" 42 - static int tr2env_event_brief; 41 + static int tr2env_event_be_brief; 43 42 44 43 static int fn_init(void) 45 44 { 46 45 int want = tr2_dst_trace_want(&tr2dst_event); 47 - int want_nesting; 46 + int max_nesting; 48 47 int want_brief; 49 - char *nesting; 50 - char *brief; 48 + const char *nesting; 49 + const char *brief; 51 50 52 51 if (!want) 53 52 return want; 54 53 55 - nesting = getenv(TR2_ENVVAR_EVENT_NESTING); 56 - if (nesting && ((want_nesting = atoi(nesting)) > 0)) 57 - tr2env_event_nesting_wanted = want_nesting; 54 + nesting = tr2_sysenv_get(TR2_SYSENV_EVENT_NESTING); 55 + if (nesting && *nesting && ((max_nesting = atoi(nesting)) > 0)) 56 + tr2env_event_max_nesting_levels = max_nesting; 58 57 59 - brief = getenv(TR2_ENVVAR_EVENT_BRIEF); 60 - if (brief && ((want_brief = atoi(brief)) > 0)) 61 - tr2env_event_brief = want_brief; 58 + brief = tr2_sysenv_get(TR2_SYSENV_EVENT_BRIEF); 59 + if (brief && *brief && 60 + ((want_brief = git_parse_maybe_bool(brief)) != -1)) 61 + tr2env_event_be_brief = want_brief; 62 62 63 63 return want; 64 64 } ··· 92 92 /* 93 93 * In brief mode, only emit <time> on these 2 event types. 94 94 */ 95 - if (!tr2env_event_brief || !strcmp(event_name, "version") || 95 + if (!tr2env_event_be_brief || !strcmp(event_name, "version") || 96 96 !strcmp(event_name, "atexit")) { 97 - tr2_tbuf_utc_time(&tb_now); 97 + tr2_tbuf_utc_datetime_extended(&tb_now); 98 98 jw_object_string(jw, "time", tb_now.buf); 99 99 } 100 100 101 - if (!tr2env_event_brief && file && *file) { 101 + if (!tr2env_event_be_brief && file && *file) { 102 102 jw_object_string(jw, "file", file); 103 103 jw_object_intmax(jw, "line", line); 104 104 } ··· 122 122 jw_release(&jw); 123 123 } 124 124 125 - static void fn_start_fl(const char *file, int line, const char **argv) 125 + static void fn_start_fl(const char *file, int line, 126 + uint64_t us_elapsed_absolute, const char **argv) 126 127 { 127 128 const char *event_name = "start"; 128 129 struct json_writer jw = JSON_WRITER_INIT; 130 + double t_abs = (double)us_elapsed_absolute / 1000000.0; 129 131 130 132 jw_object_begin(&jw, 0); 131 133 event_fmt_prepare(event_name, file, line, NULL, &jw); 134 + jw_object_double(&jw, "t_abs", 6, t_abs); 132 135 jw_object_inline_begin_array(&jw, "argv"); 133 136 jw_array_argv(&jw, argv); 134 137 jw_end(&jw); ··· 456 459 { 457 460 const char *event_name = "region_enter"; 458 461 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 459 - if (ctx->nr_open_regions <= tr2env_event_nesting_wanted) { 462 + if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) { 460 463 struct json_writer jw = JSON_WRITER_INIT; 461 464 462 465 jw_object_begin(&jw, 0); ··· 481 484 { 482 485 const char *event_name = "region_leave"; 483 486 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 484 - if (ctx->nr_open_regions <= tr2env_event_nesting_wanted) { 487 + if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) { 485 488 struct json_writer jw = JSON_WRITER_INIT; 486 489 double t_rel = (double)us_elapsed_region / 1000000.0; 487 490 ··· 508 511 { 509 512 const char *event_name = "data"; 510 513 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 511 - if (ctx->nr_open_regions <= tr2env_event_nesting_wanted) { 514 + if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) { 512 515 struct json_writer jw = JSON_WRITER_INIT; 513 516 double t_abs = (double)us_elapsed_absolute / 1000000.0; 514 517 double t_rel = (double)us_elapsed_region / 1000000.0; ··· 536 539 { 537 540 const char *event_name = "data_json"; 538 541 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 539 - if (ctx->nr_open_regions <= tr2env_event_nesting_wanted) { 542 + if (ctx->nr_open_regions <= tr2env_event_max_nesting_levels) { 540 543 struct json_writer jw = JSON_WRITER_INIT; 541 544 double t_abs = (double)us_elapsed_absolute / 1000000.0; 542 545 double t_rel = (double)us_elapsed_region / 1000000.0;
+10 -9
trace2/tr2_tgt_normal.c
··· 4 4 #include "quote.h" 5 5 #include "version.h" 6 6 #include "trace2/tr2_dst.h" 7 + #include "trace2/tr2_sysenv.h" 7 8 #include "trace2/tr2_tbuf.h" 8 9 #include "trace2/tr2_tgt.h" 9 10 #include "trace2/tr2_tls.h" 10 11 11 - static struct tr2_dst tr2dst_normal = { "GIT_TR2", 0, 0, 0 }; 12 + static struct tr2_dst tr2dst_normal = { TR2_SYSENV_NORMAL, 0, 0, 0 }; 12 13 13 14 /* 14 - * Set this environment variable to true to omit the "<time> <file>:<line>" 15 + * Use the TR2_SYSENV_NORMAL_BRIEF setting to omit the "<time> <file>:<line>" 15 16 * fields from each line written to the builtin normal target. 16 17 * 17 18 * Unit tests may want to use this to help with testing. 18 19 */ 19 - #define TR2_ENVVAR_NORMAL_BRIEF "GIT_TR2_BRIEF" 20 - static int tr2env_normal_brief; 20 + static int tr2env_normal_be_brief; 21 21 22 22 #define TR2FMT_NORMAL_FL_WIDTH (50) 23 23 ··· 25 25 { 26 26 int want = tr2_dst_trace_want(&tr2dst_normal); 27 27 int want_brief; 28 - char *brief; 28 + const char *brief; 29 29 30 30 if (!want) 31 31 return want; 32 32 33 - brief = getenv(TR2_ENVVAR_NORMAL_BRIEF); 33 + brief = tr2_sysenv_get(TR2_SYSENV_NORMAL_BRIEF); 34 34 if (brief && *brief && 35 35 ((want_brief = git_parse_maybe_bool(brief)) != -1)) 36 - tr2env_normal_brief = want_brief; 36 + tr2env_normal_be_brief = want_brief; 37 37 38 38 return want; 39 39 } ··· 47 47 { 48 48 strbuf_setlen(buf, 0); 49 49 50 - if (!tr2env_normal_brief) { 50 + if (!tr2env_normal_be_brief) { 51 51 struct tr2_tbuf tb_now; 52 52 53 53 tr2_tbuf_local_time(&tb_now); ··· 81 81 strbuf_release(&buf_payload); 82 82 } 83 83 84 - static void fn_start_fl(const char *file, int line, const char **argv) 84 + static void fn_start_fl(const char *file, int line, 85 + uint64_t us_elapsed_absolute, const char **argv) 85 86 { 86 87 struct strbuf buf_payload = STRBUF_INIT; 87 88
+12 -11
trace2/tr2_tgt_perf.c
··· 6 6 #include "json-writer.h" 7 7 #include "trace2/tr2_dst.h" 8 8 #include "trace2/tr2_sid.h" 9 + #include "trace2/tr2_sysenv.h" 9 10 #include "trace2/tr2_tbuf.h" 10 11 #include "trace2/tr2_tgt.h" 11 12 #include "trace2/tr2_tls.h" 12 13 13 - static struct tr2_dst tr2dst_perf = { "GIT_TR2_PERF", 0, 0, 0 }; 14 + static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 }; 14 15 15 16 /* 16 - * Set this environment variable to true to omit the "<time> <file>:<line>" 17 + * Use TR2_SYSENV_PERF_BRIEF to omit the "<time> <file>:<line>" 17 18 * fields from each line written to the builtin performance target. 18 19 * 19 20 * Unit tests may want to use this to help with testing. 20 21 */ 21 - #define TR2_ENVVAR_PERF_BRIEF "GIT_TR2_PERF_BRIEF" 22 - static int tr2env_perf_brief; 22 + static int tr2env_perf_be_brief; 23 23 24 24 #define TR2FMT_PERF_FL_WIDTH (50) 25 25 #define TR2FMT_PERF_MAX_EVENT_NAME (12) ··· 36 36 { 37 37 int want = tr2_dst_trace_want(&tr2dst_perf); 38 38 int want_brief; 39 - char *brief; 39 + const char *brief; 40 40 41 41 if (!want) 42 42 return want; 43 43 44 44 strbuf_addchars(&dots, '.', TR2_DOTS_BUFFER_SIZE); 45 45 46 - brief = getenv(TR2_ENVVAR_PERF_BRIEF); 46 + brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF); 47 47 if (brief && *brief && 48 48 ((want_brief = git_parse_maybe_bool(brief)) != -1)) 49 - tr2env_perf_brief = want_brief; 49 + tr2env_perf_be_brief = want_brief; 50 50 51 51 return want; 52 52 } ··· 77 77 78 78 strbuf_setlen(buf, 0); 79 79 80 - if (!tr2env_perf_brief) { 80 + if (!tr2env_perf_be_brief) { 81 81 struct tr2_tbuf tb_now; 82 82 83 83 tr2_tbuf_local_time(&tb_now); ··· 159 159 strbuf_release(&buf_payload); 160 160 } 161 161 162 - static void fn_start_fl(const char *file, int line, const char **argv) 162 + static void fn_start_fl(const char *file, int line, 163 + uint64_t us_elapsed_absolute, const char **argv) 163 164 { 164 165 const char *event_name = "start"; 165 166 struct strbuf buf_payload = STRBUF_INIT; 166 167 167 168 sq_quote_argv_pretty(&buf_payload, argv); 168 169 169 - perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL, 170 - &buf_payload); 170 + perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute, 171 + NULL, NULL, &buf_payload); 171 172 strbuf_release(&buf_payload); 172 173 } 173 174
+24 -14
trace2/tr2_tls.c
··· 10 10 #define TR2_REGION_NESTING_INITIAL_SIZE (100) 11 11 12 12 static struct tr2tls_thread_ctx *tr2tls_thread_main; 13 - static uint64_t tr2tls_us_start_main; 13 + static uint64_t tr2tls_us_start_process; 14 14 15 15 static pthread_mutex_t tr2tls_mutex; 16 16 static pthread_key_t tr2tls_key; 17 17 18 18 static int tr2_next_thread_id; /* modify under lock */ 19 19 20 - struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name) 20 + void tr2tls_start_process_clock(void) 21 21 { 22 - uint64_t us_now = getnanotime() / 1000; 22 + if (tr2tls_us_start_process) 23 + return; 24 + 25 + /* 26 + * Keep the absolute start time of the process (i.e. the main 27 + * process) in a fixed variable since other threads need to 28 + * access it. This allows them to do that without a lock on 29 + * main thread's array data (because of reallocs). 30 + */ 31 + tr2tls_us_start_process = getnanotime() / 1000; 32 + } 33 + 34 + struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name, 35 + uint64_t us_thread_start) 36 + { 23 37 struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); 24 38 25 39 /* ··· 29 43 */ 30 44 ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; 31 45 ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); 32 - ctx->array_us_start[ctx->nr_open_regions++] = us_now; 46 + ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; 33 47 34 48 ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); 35 49 ··· 55 69 * here and silently continue. 56 70 */ 57 71 if (!ctx) 58 - ctx = tr2tls_create_self("unknown"); 72 + ctx = tr2tls_create_self("unknown", getnanotime() / 1000); 59 73 60 74 return ctx; 61 75 } ··· 124 138 if (!tr2tls_thread_main) 125 139 return 0; 126 140 127 - return us - tr2tls_us_start_main; 141 + return us - tr2tls_us_start_process; 128 142 } 129 143 130 144 void tr2tls_init(void) 131 145 { 146 + tr2tls_start_process_clock(); 147 + 132 148 pthread_key_create(&tr2tls_key, NULL); 133 149 init_recursive_mutex(&tr2tls_mutex); 134 150 135 - tr2tls_thread_main = tr2tls_create_self("main"); 136 - /* 137 - * Keep a copy of the absolute start time of the main thread 138 - * in a fixed variable since other threads need to access it. 139 - * This also eliminates the need to lock accesses to the main 140 - * thread's array (because of reallocs). 141 - */ 142 - tr2tls_us_start_main = tr2tls_thread_main->array_us_start[0]; 151 + tr2tls_thread_main = 152 + tr2tls_create_self("main", tr2tls_us_start_process); 143 153 } 144 154 145 155 void tr2tls_release(void)
+7 -1
trace2/tr2_tls.h
··· 31 31 * In this and all following functions the term "self" refers to the 32 32 * current thread. 33 33 */ 34 - struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name); 34 + struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name, 35 + uint64_t us_thread_start); 35 36 36 37 /* 37 38 * Get our TLS data. ··· 93 94 * Protected increment of an integer. 94 95 */ 95 96 int tr2tls_locked_increment(int *p); 97 + 98 + /* 99 + * Capture the process start time and do nothing else. 100 + */ 101 + void tr2tls_start_process_clock(void); 96 102 97 103 #endif /* TR2_TLS_H */