🌐 AI搜索 & 代理 主页
blob: 9b99460db82a28634c09260b42f311f7c69f4d59 [file] [log] [blame]
Christian Couder6ce4e612006-09-02 16:23:481/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
5 * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
6 * Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
7 * Copyright (C) 2006 Mike McCormack
8 * Copyright (C) 2006 Christian Couder
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
Josh Sorefd05b08c2023-11-24 03:35:1321 * along with this program; if not, see <https://www.gnu.org/licenses/>.
Christian Couder6ce4e612006-09-02 16:23:4822 */
23
Patrick Steinhardt41f43b82024-12-06 10:27:1924#define DISABLE_SIGN_COMPARE_WARNINGS
Patrick Steinhardt246deea2024-09-12 11:29:2425
Elijah Newren5579f442023-04-11 07:41:4826#include "git-compat-util.h"
Elijah Newren0b027f62023-03-21 06:25:5827#include "abspath.h"
Patrick Steinhardt246deea2024-09-12 11:29:2428#include "repository.h"
Christian Couder6ce4e612006-09-02 16:23:4829#include "quote.h"
Elijah Newrene38da482023-03-21 06:26:0530#include "setup.h"
Elijah Newren74ea5c92023-04-11 03:00:3831#include "trace.h"
Christian Couder6ce4e612006-09-02 16:23:4832
Gennady Kupava406102a2017-11-26 20:11:1833struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 };
Gennady Kupava8eeb25c2017-11-26 20:11:1934struct trace_key trace_perf_key = TRACE_KEY_INIT(PERFORMANCE);
Nguyễn Thái Ngọc Duycb507612018-03-30 18:34:5935struct trace_key trace_setup_key = TRACE_KEY_INIT(SETUP);
Jeff Kingc81539b2016-08-03 22:56:5736
Jeff King06796602011-02-24 14:28:4137/* Get a trace file descriptor from "key" env variable. */
Jonathan Tan7167a622020-05-11 17:43:1038static int get_trace_fd(struct trace_key *key, const char *override_envvar)
Christian Couder6ce4e612006-09-02 16:23:4839{
Karsten Blees6aa30852014-07-12 00:00:0640 const char *trace;
41
Karsten Blees6aa30852014-07-12 00:00:0642 /* don't open twice */
43 if (key->initialized)
44 return key->fd;
45
Jonathan Tan7167a622020-05-11 17:43:1046 trace = override_envvar ? override_envvar : getenv(key->key);
Christian Couder6ce4e612006-09-02 16:23:4847
Christian Couder6844fc82006-10-14 14:05:2548 if (!trace || !strcmp(trace, "") ||
49 !strcmp(trace, "0") || !strcasecmp(trace, "false"))
Karsten Blees6aa30852014-07-12 00:00:0650 key->fd = 0;
51 else if (!strcmp(trace, "1") || !strcasecmp(trace, "true"))
52 key->fd = STDERR_FILENO;
53 else if (strlen(trace) == 1 && isdigit(*trace))
54 key->fd = atoi(trace);
55 else if (is_absolute_path(trace)) {
Christian Couder6ce4e612006-09-02 16:23:4856 int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
57 if (fd == -1) {
Jeff King6f253052016-08-05 07:58:3858 warning("could not open '%s' for tracing: %s",
Christian Couder6ce4e612006-09-02 16:23:4859 trace, strerror(errno));
Jeff King6f253052016-08-05 07:58:3860 trace_disable(key);
Karsten Blees6aa30852014-07-12 00:00:0661 } else {
62 key->fd = fd;
63 key->need_close = 1;
Christian Couder6ce4e612006-09-02 16:23:4864 }
Karsten Blees6aa30852014-07-12 00:00:0665 } else {
Jeff Kingb3a1c5d2016-08-03 23:00:2366 warning("unknown trace value for '%s': %s\n"
67 " If you want to trace into a file, then please set %s\n"
Jeff King6f253052016-08-05 07:58:3868 " to an absolute pathname (starting with /)",
Jeff Kingb3a1c5d2016-08-03 23:00:2369 key->key, trace, key->key);
Jeff King6f253052016-08-05 07:58:3870 trace_disable(key);
Christian Couder6ce4e612006-09-02 16:23:4871 }
72
Karsten Blees6aa30852014-07-12 00:00:0673 key->initialized = 1;
74 return key->fd;
75}
Christian Couder6ce4e612006-09-02 16:23:4876
Jonathan Tan7167a622020-05-11 17:43:1077void trace_override_envvar(struct trace_key *key, const char *value)
78{
79 trace_disable(key);
80 key->initialized = 0;
81
82 /*
83 * Invoke get_trace_fd() to initialize key using the given value
84 * instead of the value of the environment variable.
85 */
86 get_trace_fd(key, value);
87}
88
Karsten Blees6aa30852014-07-12 00:00:0689void trace_disable(struct trace_key *key)
90{
91 if (key->need_close)
92 close(key->fd);
93 key->fd = 0;
94 key->initialized = 1;
95 key->need_close = 0;
Christian Couder6ce4e612006-09-02 16:23:4896}
97
Karsten Bleese05bed92014-07-12 00:05:0398static int prepare_trace_line(const char *file, int line,
99 struct trace_key *key, struct strbuf *buf)
Karsten Bleesc69dfd22014-07-12 00:02:18100{
Karsten Blees124647c2014-07-12 00:03:01101 static struct trace_key trace_bare = TRACE_KEY_INIT(BARE);
Karsten Bleesb72be022014-07-12 00:03:50102 struct timeval tv;
103 struct tm tm;
104 time_t secs;
Karsten Blees124647c2014-07-12 00:03:01105
Karsten Bleesc69dfd22014-07-12 00:02:18106 if (!trace_want(key))
107 return 0;
108
Karsten Blees124647c2014-07-12 00:03:01109 /* unit tests may want to disable additional trace output */
110 if (trace_want(&trace_bare))
111 return 1;
112
Karsten Bleesb72be022014-07-12 00:03:50113 /* print current timestamp */
114 gettimeofday(&tv, NULL);
115 secs = tv.tv_sec;
116 localtime_r(&secs, &tm);
Ævar Arnfjörð Bjarmason56a29d22022-02-21 16:05:27117 strbuf_addf(buf, "%02d:%02d:%02d.%06ld %s:%d", tm.tm_hour, tm.tm_min,
118 tm.tm_sec, (long) tv.tv_usec, file, line);
Karsten Bleese05bed92014-07-12 00:05:03119 /* align trace output (column 40 catches most files names in git) */
120 while (buf->len < 40)
121 strbuf_addch(buf, ' ');
Karsten Bleese05bed92014-07-12 00:05:03122
Karsten Bleesc69dfd22014-07-12 00:02:18123 return 1;
124}
125
Jeff Kingc0222e72016-08-03 22:58:00126static void trace_write(struct trace_key *key, const void *buf, unsigned len)
127{
Jonathan Tan7167a622020-05-11 17:43:10128 if (write_in_full(get_trace_fd(key, NULL), buf, len) < 0) {
Jeff King3b0c3ab2016-08-03 23:00:32129 warning("unable to write trace for %s: %s",
130 key->key, strerror(errno));
Jeff King46ac74b2016-08-03 23:01:04131 trace_disable(key);
Jeff King3b0c3ab2016-08-03 23:00:32132 }
Jeff Kingc0222e72016-08-03 22:58:00133}
134
Jeff King32359832015-06-16 17:23:20135void trace_verbatim(struct trace_key *key, const void *buf, unsigned len)
136{
137 if (!trace_want(key))
138 return;
Jeff Kingc0222e72016-08-03 22:58:00139 trace_write(key, buf, len);
Jeff King32359832015-06-16 17:23:20140}
141
Karsten Bleesc69dfd22014-07-12 00:02:18142static void print_trace_line(struct trace_key *key, struct strbuf *buf)
143{
René Scharfea0d49232014-12-12 19:16:38144 strbuf_complete_line(buf);
Jeff Kingc0222e72016-08-03 22:58:00145 trace_write(key, buf->buf, buf->len);
Karsten Bleesc69dfd22014-07-12 00:02:18146}
147
Karsten Bleese05bed92014-07-12 00:05:03148static void trace_vprintf_fl(const char *file, int line, struct trace_key *key,
149 const char *format, va_list ap)
Christian Couder6ce4e612006-09-02 16:23:48150{
Jeff Kingebeb6092011-02-26 05:08:53151 struct strbuf buf = STRBUF_INIT;
Christian Couder6ce4e612006-09-02 16:23:48152
Karsten Bleese05bed92014-07-12 00:05:03153 if (!prepare_trace_line(file, line, key, &buf))
Christian Couder6ce4e612006-09-02 16:23:48154 return;
155
Karsten Blees4a3b0b22014-06-11 07:57:23156 strbuf_vaddf(&buf, format, ap);
Karsten Bleesc69dfd22014-07-12 00:02:18157 print_trace_line(key, &buf);
Nguyễn Thái Ngọc Duy33011e72018-01-15 10:59:45158 strbuf_release(&buf);
Christian Couder6ce4e612006-09-02 16:23:48159}
160
Karsten Bleese05bed92014-07-12 00:05:03161static void trace_argv_vprintf_fl(const char *file, int line,
162 const char **argv, const char *format,
163 va_list ap)
Christian Couder6ce4e612006-09-02 16:23:48164{
Jeff Kingebeb6092011-02-26 05:08:53165 struct strbuf buf = STRBUF_INIT;
Karsten Bleesc69dfd22014-07-12 00:02:18166
Gennady Kupava406102a2017-11-26 20:11:18167 if (!prepare_trace_line(file, line, &trace_default_key, &buf))
Christian Couder6ce4e612006-09-02 16:23:48168 return;
169
Karsten Blees4a3b0b22014-06-11 07:57:23170 strbuf_vaddf(&buf, format, ap);
Pierre Habouzit19247e52007-09-20 08:43:11171
Jeff King1fbdab22018-01-15 10:59:44172 sq_quote_argv_pretty(&buf, argv);
Gennady Kupava406102a2017-11-26 20:11:18173 print_trace_line(&trace_default_key, &buf);
Nguyễn Thái Ngọc Duy33011e72018-01-15 10:59:45174 strbuf_release(&buf);
Christian Couder6ce4e612006-09-02 16:23:48175}
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57176
Karsten Bleese05bed92014-07-12 00:05:03177void trace_strbuf_fl(const char *file, int line, struct trace_key *key,
178 const struct strbuf *data)
Karsten Blees66f66c52014-07-12 00:04:29179{
180 struct strbuf buf = STRBUF_INIT;
181
Karsten Bleese05bed92014-07-12 00:05:03182 if (!prepare_trace_line(file, line, key, &buf))
Karsten Blees66f66c52014-07-12 00:04:29183 return;
184
185 strbuf_addbuf(&buf, data);
186 print_trace_line(key, &buf);
Nguyễn Thái Ngọc Duy33011e72018-01-15 10:59:45187 strbuf_release(&buf);
Karsten Blees66f66c52014-07-12 00:04:29188}
189
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22190static uint64_t perf_start_times[10];
191static int perf_indent;
192
193uint64_t trace_performance_enter(void)
194{
195 uint64_t now;
196
197 if (!trace_want(&trace_perf_key))
198 return 0;
199
200 now = getnanotime();
201 perf_start_times[perf_indent] = now;
202 if (perf_indent + 1 < ARRAY_SIZE(perf_start_times))
203 perf_indent++;
204 else
205 BUG("Too deep indentation");
206 return now;
207}
208
Karsten Blees09b2c1c2014-07-12 00:06:28209static void trace_performance_vprintf_fl(const char *file, int line,
210 uint64_t nanos, const char *format,
211 va_list ap)
212{
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22213 static const char space[] = " ";
Karsten Blees09b2c1c2014-07-12 00:06:28214 struct strbuf buf = STRBUF_INIT;
215
216 if (!prepare_trace_line(file, line, &trace_perf_key, &buf))
217 return;
218
219 strbuf_addf(&buf, "performance: %.9f s", (double) nanos / 1000000000);
220
221 if (format && *format) {
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22222 if (perf_indent >= strlen(space))
223 BUG("Too deep indentation");
224
225 strbuf_addf(&buf, ":%.*s ", perf_indent, space);
Karsten Blees09b2c1c2014-07-12 00:06:28226 strbuf_vaddf(&buf, format, ap);
227 }
228
229 print_trace_line(&trace_perf_key, &buf);
Nguyễn Thái Ngọc Duy33011e72018-01-15 10:59:45230 strbuf_release(&buf);
Karsten Blees09b2c1c2014-07-12 00:06:28231}
232
Karsten Bleese05bed92014-07-12 00:05:03233void trace_printf_key_fl(const char *file, int line, struct trace_key *key,
234 const char *format, ...)
235{
236 va_list ap;
237 va_start(ap, format);
238 trace_vprintf_fl(file, line, key, format, ap);
239 va_end(ap);
240}
241
242void trace_argv_printf_fl(const char *file, int line, const char **argv,
243 const char *format, ...)
244{
245 va_list ap;
246 va_start(ap, format);
247 trace_argv_vprintf_fl(file, line, argv, format, ap);
248 va_end(ap);
249}
250
Karsten Blees09b2c1c2014-07-12 00:06:28251void trace_performance_fl(const char *file, int line, uint64_t nanos,
252 const char *format, ...)
253{
254 va_list ap;
255 va_start(ap, format);
256 trace_performance_vprintf_fl(file, line, nanos, format, ap);
257 va_end(ap);
258}
259
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22260void trace_performance_leave_fl(const char *file, int line,
261 uint64_t nanos, const char *format, ...)
262{
263 va_list ap;
264 uint64_t since;
265
266 if (perf_indent)
267 perf_indent--;
268
269 if (!format) /* Allow callers to leave without tracing anything */
270 return;
271
272 since = perf_start_times[perf_indent];
273 va_start(ap, format);
274 trace_performance_vprintf_fl(file, line, nanos - since, format, ap);
275 va_end(ap);
276}
277
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57278static const char *quote_crnl(const char *path)
279{
Jeff King0bb443f2015-09-24 21:05:54280 static struct strbuf new_path = STRBUF_INIT;
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57281
282 if (!path)
283 return NULL;
284
Jeff King0bb443f2015-09-24 21:05:54285 strbuf_reset(&new_path);
286
287 while (*path) {
288 switch (*path) {
289 case '\\': strbuf_addstr(&new_path, "\\\\"); break;
290 case '\n': strbuf_addstr(&new_path, "\\n"); break;
291 case '\r': strbuf_addstr(&new_path, "\\r"); break;
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57292 default:
Jeff King0bb443f2015-09-24 21:05:54293 strbuf_addch(&new_path, *path);
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57294 }
Jeff King0bb443f2015-09-24 21:05:54295 path++;
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57296 }
Jeff King0bb443f2015-09-24 21:05:54297 return new_path.buf;
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57298}
299
Patrick Steinhardtbd0c0fb2024-12-17 06:43:50300void trace_repo_setup(struct repository *r)
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57301{
idriss fekir17ab64e2023-02-19 00:25:27302 const char *git_work_tree, *prefix = startup_info->prefix;
René Scharfe56b9f6e2014-07-28 18:30:39303 char *cwd;
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57304
Nguyễn Thái Ngọc Duycb507612018-03-30 18:34:59305 if (!trace_want(&trace_setup_key))
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57306 return;
307
René Scharfe56b9f6e2014-07-28 18:30:39308 cwd = xgetcwd();
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57309
Patrick Steinhardtbd0c0fb2024-12-17 06:43:50310 if (!(git_work_tree = repo_get_work_tree(r)))
Brandon Caseye83c2672011-01-06 00:30:01311 git_work_tree = "(null)";
312
idriss fekir17ab64e2023-02-19 00:25:27313 if (!startup_info->prefix)
Brandon Caseye83c2672011-01-06 00:30:01314 prefix = "(null)";
315
Patrick Steinhardtbd0c0fb2024-12-17 06:43:50316 trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(r)));
317 trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(r)));
Nguyễn Thái Ngọc Duycb507612018-03-30 18:34:59318 trace_printf_key(&trace_setup_key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
319 trace_printf_key(&trace_setup_key, "setup: cwd: %s\n", quote_crnl(cwd));
320 trace_printf_key(&trace_setup_key, "setup: prefix: %s\n", quote_crnl(prefix));
René Scharfe56b9f6e2014-07-28 18:30:39321
322 free(cwd);
Nguyễn Thái Ngọc Duya9ca8a82010-11-26 15:31:57323}
Jeff King39bc5e42011-02-24 14:28:59324
Karsten Blees6aa30852014-07-12 00:00:06325int trace_want(struct trace_key *key)
Jeff King39bc5e42011-02-24 14:28:59326{
Jonathan Tan7167a622020-05-11 17:43:10327 return !!get_trace_fd(key, NULL);
Jeff King39bc5e42011-02-24 14:28:59328}
Karsten Blees148d6772014-07-12 00:05:42329
Reuben Hawkinsa6c3c632015-01-08 20:00:56330#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
Karsten Blees148d6772014-07-12 00:05:42331
332static inline uint64_t highres_nanos(void)
333{
334 struct timespec ts;
335 if (clock_gettime(CLOCK_MONOTONIC, &ts))
336 return 0;
337 return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
338}
339
340#elif defined (GIT_WINDOWS_NATIVE)
341
342static inline uint64_t highres_nanos(void)
343{
344 static uint64_t high_ns, scaled_low_ns;
345 static int scale;
346 LARGE_INTEGER cnt;
347
348 if (!scale) {
349 if (!QueryPerformanceFrequency(&cnt))
350 return 0;
351
352 /* high_ns = number of ns per cnt.HighPart */
353 high_ns = (1000000000LL << 32) / (uint64_t) cnt.QuadPart;
354
355 /*
356 * Number of ns per cnt.LowPart is 10^9 / frequency (or
357 * high_ns >> 32). For maximum precision, we scale this factor
358 * so that it just fits within 32 bit (i.e. won't overflow if
359 * multiplied with cnt.LowPart).
360 */
361 scaled_low_ns = high_ns;
362 scale = 32;
363 while (scaled_low_ns >= 0x100000000LL) {
364 scaled_low_ns >>= 1;
365 scale--;
366 }
367 }
368
369 /* if QPF worked on initialization, we expect QPC to work as well */
370 QueryPerformanceCounter(&cnt);
371
372 return (high_ns * cnt.HighPart) +
373 ((scaled_low_ns * cnt.LowPart) >> scale);
374}
375
376#else
377# define highres_nanos() 0
378#endif
379
380static inline uint64_t gettimeofday_nanos(void)
381{
382 struct timeval tv;
383 gettimeofday(&tv, NULL);
384 return (uint64_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
385}
386
387/*
388 * Returns nanoseconds since the epoch (01/01/1970), for performance tracing
389 * (i.e. favoring high precision over wall clock time accuracy).
390 */
Ben Walton6433d562014-09-28 07:50:26391uint64_t getnanotime(void)
Karsten Blees148d6772014-07-12 00:05:42392{
393 static uint64_t offset;
394 if (offset > 1) {
395 /* initialization succeeded, return offset + high res time */
396 return offset + highres_nanos();
397 } else if (offset == 1) {
398 /* initialization failed, fall back to gettimeofday */
399 return gettimeofday_nanos();
400 } else {
401 /* initialize offset if high resolution timer works */
402 uint64_t now = gettimeofday_nanos();
403 uint64_t highres = highres_nanos();
404 if (highres)
405 offset = now - highres;
406 else
407 offset = 1;
408 return now;
409 }
410}
Karsten Blees578da032014-07-12 00:07:01411
Karsten Blees578da032014-07-12 00:07:01412static struct strbuf command_line = STRBUF_INIT;
413
414static void print_command_performance_atexit(void)
415{
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22416 trace_performance_leave("git command:%s", command_line.buf);
Karsten Blees578da032014-07-12 00:07:01417}
418
419void trace_command_performance(const char **argv)
420{
421 if (!trace_want(&trace_perf_key))
422 return;
423
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22424 if (!command_line.len)
Karsten Blees578da032014-07-12 00:07:01425 atexit(print_command_performance_atexit);
426
427 strbuf_reset(&command_line);
Jeff King1fbdab22018-01-15 10:59:44428 sq_quote_argv_pretty(&command_line, argv);
Nguyễn Thái Ngọc Duyc46c4062018-08-18 14:41:22429 trace_performance_enter();
Karsten Blees578da032014-07-12 00:07:01430}