trace.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  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
  21. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include "cache.h"
  24. #include "quote.h"
  25. struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 };
  26. struct trace_key trace_perf_key = TRACE_KEY_INIT(PERFORMANCE);
  27. struct trace_key trace_setup_key = TRACE_KEY_INIT(SETUP);
  28. /* Get a trace file descriptor from "key" env variable. */
  29. static int get_trace_fd(struct trace_key *key, const char *override_envvar)
  30. {
  31. const char *trace;
  32. /* don't open twice */
  33. if (key->initialized)
  34. return key->fd;
  35. trace = override_envvar ? override_envvar : getenv(key->key);
  36. if (!trace || !strcmp(trace, "") ||
  37. !strcmp(trace, "0") || !strcasecmp(trace, "false"))
  38. key->fd = 0;
  39. else if (!strcmp(trace, "1") || !strcasecmp(trace, "true"))
  40. key->fd = STDERR_FILENO;
  41. else if (strlen(trace) == 1 && isdigit(*trace))
  42. key->fd = atoi(trace);
  43. else if (is_absolute_path(trace)) {
  44. int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
  45. if (fd == -1) {
  46. warning("could not open '%s' for tracing: %s",
  47. trace, strerror(errno));
  48. trace_disable(key);
  49. } else {
  50. key->fd = fd;
  51. key->need_close = 1;
  52. }
  53. } else {
  54. warning("unknown trace value for '%s': %s\n"
  55. " If you want to trace into a file, then please set %s\n"
  56. " to an absolute pathname (starting with /)",
  57. key->key, trace, key->key);
  58. trace_disable(key);
  59. }
  60. key->initialized = 1;
  61. return key->fd;
  62. }
  63. void trace_override_envvar(struct trace_key *key, const char *value)
  64. {
  65. trace_disable(key);
  66. key->initialized = 0;
  67. /*
  68. * Invoke get_trace_fd() to initialize key using the given value
  69. * instead of the value of the environment variable.
  70. */
  71. get_trace_fd(key, value);
  72. }
  73. void trace_disable(struct trace_key *key)
  74. {
  75. if (key->need_close)
  76. close(key->fd);
  77. key->fd = 0;
  78. key->initialized = 1;
  79. key->need_close = 0;
  80. }
  81. static int prepare_trace_line(const char *file, int line,
  82. struct trace_key *key, struct strbuf *buf)
  83. {
  84. static struct trace_key trace_bare = TRACE_KEY_INIT(BARE);
  85. struct timeval tv;
  86. struct tm tm;
  87. time_t secs;
  88. if (!trace_want(key))
  89. return 0;
  90. /* unit tests may want to disable additional trace output */
  91. if (trace_want(&trace_bare))
  92. return 1;
  93. /* print current timestamp */
  94. gettimeofday(&tv, NULL);
  95. secs = tv.tv_sec;
  96. localtime_r(&secs, &tm);
  97. strbuf_addf(buf, "%02d:%02d:%02d.%06ld ", tm.tm_hour, tm.tm_min,
  98. tm.tm_sec, (long) tv.tv_usec);
  99. #ifdef HAVE_VARIADIC_MACROS
  100. /* print file:line */
  101. strbuf_addf(buf, "%s:%d ", file, line);
  102. /* align trace output (column 40 catches most files names in git) */
  103. while (buf->len < 40)
  104. strbuf_addch(buf, ' ');
  105. #endif
  106. return 1;
  107. }
  108. static void trace_write(struct trace_key *key, const void *buf, unsigned len)
  109. {
  110. if (write_in_full(get_trace_fd(key, NULL), buf, len) < 0) {
  111. warning("unable to write trace for %s: %s",
  112. key->key, strerror(errno));
  113. trace_disable(key);
  114. }
  115. }
  116. void trace_verbatim(struct trace_key *key, const void *buf, unsigned len)
  117. {
  118. if (!trace_want(key))
  119. return;
  120. trace_write(key, buf, len);
  121. }
  122. static void print_trace_line(struct trace_key *key, struct strbuf *buf)
  123. {
  124. strbuf_complete_line(buf);
  125. trace_write(key, buf->buf, buf->len);
  126. }
  127. static void trace_vprintf_fl(const char *file, int line, struct trace_key *key,
  128. const char *format, va_list ap)
  129. {
  130. struct strbuf buf = STRBUF_INIT;
  131. if (!prepare_trace_line(file, line, key, &buf))
  132. return;
  133. strbuf_vaddf(&buf, format, ap);
  134. print_trace_line(key, &buf);
  135. strbuf_release(&buf);
  136. }
  137. static void trace_argv_vprintf_fl(const char *file, int line,
  138. const char **argv, const char *format,
  139. va_list ap)
  140. {
  141. struct strbuf buf = STRBUF_INIT;
  142. if (!prepare_trace_line(file, line, &trace_default_key, &buf))
  143. return;
  144. strbuf_vaddf(&buf, format, ap);
  145. sq_quote_argv_pretty(&buf, argv);
  146. print_trace_line(&trace_default_key, &buf);
  147. strbuf_release(&buf);
  148. }
  149. void trace_strbuf_fl(const char *file, int line, struct trace_key *key,
  150. const struct strbuf *data)
  151. {
  152. struct strbuf buf = STRBUF_INIT;
  153. if (!prepare_trace_line(file, line, key, &buf))
  154. return;
  155. strbuf_addbuf(&buf, data);
  156. print_trace_line(key, &buf);
  157. strbuf_release(&buf);
  158. }
  159. static uint64_t perf_start_times[10];
  160. static int perf_indent;
  161. uint64_t trace_performance_enter(void)
  162. {
  163. uint64_t now;
  164. if (!trace_want(&trace_perf_key))
  165. return 0;
  166. now = getnanotime();
  167. perf_start_times[perf_indent] = now;
  168. if (perf_indent + 1 < ARRAY_SIZE(perf_start_times))
  169. perf_indent++;
  170. else
  171. BUG("Too deep indentation");
  172. return now;
  173. }
  174. static void trace_performance_vprintf_fl(const char *file, int line,
  175. uint64_t nanos, const char *format,
  176. va_list ap)
  177. {
  178. static const char space[] = " ";
  179. struct strbuf buf = STRBUF_INIT;
  180. if (!prepare_trace_line(file, line, &trace_perf_key, &buf))
  181. return;
  182. strbuf_addf(&buf, "performance: %.9f s", (double) nanos / 1000000000);
  183. if (format && *format) {
  184. if (perf_indent >= strlen(space))
  185. BUG("Too deep indentation");
  186. strbuf_addf(&buf, ":%.*s ", perf_indent, space);
  187. strbuf_vaddf(&buf, format, ap);
  188. }
  189. print_trace_line(&trace_perf_key, &buf);
  190. strbuf_release(&buf);
  191. }
  192. #ifndef HAVE_VARIADIC_MACROS
  193. void trace_printf(const char *format, ...)
  194. {
  195. va_list ap;
  196. va_start(ap, format);
  197. trace_vprintf_fl(NULL, 0, &trace_default_key, format, ap);
  198. va_end(ap);
  199. }
  200. void trace_printf_key(struct trace_key *key, const char *format, ...)
  201. {
  202. va_list ap;
  203. va_start(ap, format);
  204. trace_vprintf_fl(NULL, 0, key, format, ap);
  205. va_end(ap);
  206. }
  207. void trace_argv_printf(const char **argv, const char *format, ...)
  208. {
  209. va_list ap;
  210. va_start(ap, format);
  211. trace_argv_vprintf_fl(NULL, 0, argv, format, ap);
  212. va_end(ap);
  213. }
  214. void trace_strbuf(struct trace_key *key, const struct strbuf *data)
  215. {
  216. trace_strbuf_fl(NULL, 0, key, data);
  217. }
  218. void trace_performance(uint64_t nanos, const char *format, ...)
  219. {
  220. va_list ap;
  221. va_start(ap, format);
  222. trace_performance_vprintf_fl(NULL, 0, nanos, format, ap);
  223. va_end(ap);
  224. }
  225. void trace_performance_since(uint64_t start, const char *format, ...)
  226. {
  227. va_list ap;
  228. va_start(ap, format);
  229. trace_performance_vprintf_fl(NULL, 0, getnanotime() - start,
  230. format, ap);
  231. va_end(ap);
  232. }
  233. void trace_performance_leave(const char *format, ...)
  234. {
  235. va_list ap;
  236. uint64_t since;
  237. if (perf_indent)
  238. perf_indent--;
  239. if (!format) /* Allow callers to leave without tracing anything */
  240. return;
  241. since = perf_start_times[perf_indent];
  242. va_start(ap, format);
  243. trace_performance_vprintf_fl(NULL, 0, getnanotime() - since,
  244. format, ap);
  245. va_end(ap);
  246. }
  247. #else
  248. void trace_printf_key_fl(const char *file, int line, struct trace_key *key,
  249. const char *format, ...)
  250. {
  251. va_list ap;
  252. va_start(ap, format);
  253. trace_vprintf_fl(file, line, key, format, ap);
  254. va_end(ap);
  255. }
  256. void trace_argv_printf_fl(const char *file, int line, const char **argv,
  257. const char *format, ...)
  258. {
  259. va_list ap;
  260. va_start(ap, format);
  261. trace_argv_vprintf_fl(file, line, argv, format, ap);
  262. va_end(ap);
  263. }
  264. void trace_performance_fl(const char *file, int line, uint64_t nanos,
  265. const char *format, ...)
  266. {
  267. va_list ap;
  268. va_start(ap, format);
  269. trace_performance_vprintf_fl(file, line, nanos, format, ap);
  270. va_end(ap);
  271. }
  272. void trace_performance_leave_fl(const char *file, int line,
  273. uint64_t nanos, const char *format, ...)
  274. {
  275. va_list ap;
  276. uint64_t since;
  277. if (perf_indent)
  278. perf_indent--;
  279. if (!format) /* Allow callers to leave without tracing anything */
  280. return;
  281. since = perf_start_times[perf_indent];
  282. va_start(ap, format);
  283. trace_performance_vprintf_fl(file, line, nanos - since, format, ap);
  284. va_end(ap);
  285. }
  286. #endif /* HAVE_VARIADIC_MACROS */
  287. static const char *quote_crnl(const char *path)
  288. {
  289. static struct strbuf new_path = STRBUF_INIT;
  290. if (!path)
  291. return NULL;
  292. strbuf_reset(&new_path);
  293. while (*path) {
  294. switch (*path) {
  295. case '\\': strbuf_addstr(&new_path, "\\\\"); break;
  296. case '\n': strbuf_addstr(&new_path, "\\n"); break;
  297. case '\r': strbuf_addstr(&new_path, "\\r"); break;
  298. default:
  299. strbuf_addch(&new_path, *path);
  300. }
  301. path++;
  302. }
  303. return new_path.buf;
  304. }
  305. /* FIXME: move prefix to startup_info struct and get rid of this arg */
  306. void trace_repo_setup(const char *prefix)
  307. {
  308. const char *git_work_tree;
  309. char *cwd;
  310. if (!trace_want(&trace_setup_key))
  311. return;
  312. cwd = xgetcwd();
  313. if (!(git_work_tree = get_git_work_tree()))
  314. git_work_tree = "(null)";
  315. if (!prefix)
  316. prefix = "(null)";
  317. trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
  318. trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
  319. trace_printf_key(&trace_setup_key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
  320. trace_printf_key(&trace_setup_key, "setup: cwd: %s\n", quote_crnl(cwd));
  321. trace_printf_key(&trace_setup_key, "setup: prefix: %s\n", quote_crnl(prefix));
  322. free(cwd);
  323. }
  324. int trace_want(struct trace_key *key)
  325. {
  326. return !!get_trace_fd(key, NULL);
  327. }
  328. #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
  329. static inline uint64_t highres_nanos(void)
  330. {
  331. struct timespec ts;
  332. if (clock_gettime(CLOCK_MONOTONIC, &ts))
  333. return 0;
  334. return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
  335. }
  336. #elif defined (GIT_WINDOWS_NATIVE)
  337. static inline uint64_t highres_nanos(void)
  338. {
  339. static uint64_t high_ns, scaled_low_ns;
  340. static int scale;
  341. LARGE_INTEGER cnt;
  342. if (!scale) {
  343. if (!QueryPerformanceFrequency(&cnt))
  344. return 0;
  345. /* high_ns = number of ns per cnt.HighPart */
  346. high_ns = (1000000000LL << 32) / (uint64_t) cnt.QuadPart;
  347. /*
  348. * Number of ns per cnt.LowPart is 10^9 / frequency (or
  349. * high_ns >> 32). For maximum precision, we scale this factor
  350. * so that it just fits within 32 bit (i.e. won't overflow if
  351. * multiplied with cnt.LowPart).
  352. */
  353. scaled_low_ns = high_ns;
  354. scale = 32;
  355. while (scaled_low_ns >= 0x100000000LL) {
  356. scaled_low_ns >>= 1;
  357. scale--;
  358. }
  359. }
  360. /* if QPF worked on initialization, we expect QPC to work as well */
  361. QueryPerformanceCounter(&cnt);
  362. return (high_ns * cnt.HighPart) +
  363. ((scaled_low_ns * cnt.LowPart) >> scale);
  364. }
  365. #else
  366. # define highres_nanos() 0
  367. #endif
  368. static inline uint64_t gettimeofday_nanos(void)
  369. {
  370. struct timeval tv;
  371. gettimeofday(&tv, NULL);
  372. return (uint64_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
  373. }
  374. /*
  375. * Returns nanoseconds since the epoch (01/01/1970), for performance tracing
  376. * (i.e. favoring high precision over wall clock time accuracy).
  377. */
  378. uint64_t getnanotime(void)
  379. {
  380. static uint64_t offset;
  381. if (offset > 1) {
  382. /* initialization succeeded, return offset + high res time */
  383. return offset + highres_nanos();
  384. } else if (offset == 1) {
  385. /* initialization failed, fall back to gettimeofday */
  386. return gettimeofday_nanos();
  387. } else {
  388. /* initialize offset if high resolution timer works */
  389. uint64_t now = gettimeofday_nanos();
  390. uint64_t highres = highres_nanos();
  391. if (highres)
  392. offset = now - highres;
  393. else
  394. offset = 1;
  395. return now;
  396. }
  397. }
  398. static struct strbuf command_line = STRBUF_INIT;
  399. static void print_command_performance_atexit(void)
  400. {
  401. trace_performance_leave("git command:%s", command_line.buf);
  402. }
  403. void trace_command_performance(const char **argv)
  404. {
  405. if (!trace_want(&trace_perf_key))
  406. return;
  407. if (!command_line.len)
  408. atexit(print_command_performance_atexit);
  409. strbuf_reset(&command_line);
  410. sq_quote_argv_pretty(&command_line, argv);
  411. trace_performance_enter();
  412. }