Skip to content

Commit 9f2de9c

Browse files
committed
Merge branch 'kb/perf-trace'
* kb/perf-trace: api-trace.txt: add trace API documentation progress: simplify performance measurement by using getnanotime() wt-status: simplify performance measurement by using getnanotime() git: add performance tracing for git's main() function to debug scripts trace: add trace_performance facility to debug performance issues trace: add high resolution timer function to debug performance issues trace: add 'file:line' to all trace output trace: move code around, in preparation to file:line output trace: add current timestamp to all trace output trace: disable additional trace output for unit tests trace: add infrastructure to augment trace output with additional info sha1_file: change GIT_TRACE_PACK_ACCESS logging to use trace API Documentation/git.txt: improve documentation of 'GIT_TRACE*' variables trace: improve trace performance trace: remove redundant printf format attribute trace: consistently name the format parameter trace: move trace declarations from cache.h to new trace.h
2 parents 9ab0882 + c7d3f8c commit 9f2de9c

File tree

17 files changed

+629
-176
lines changed

17 files changed

+629
-176
lines changed

Documentation/git.txt

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -906,31 +906,54 @@ for further details.
906906
based on whether stdout appears to be redirected to a file or not.
907907

908908
'GIT_TRACE'::
909-
If this variable is set to "1", "2" or "true" (comparison
910-
is case insensitive), Git will print `trace:` messages on
911-
stderr telling about alias expansion, built-in command
912-
execution and external command execution.
913-
If this variable is set to an integer value greater than 1
914-
and lower than 10 (strictly) then Git will interpret this
915-
value as an open file descriptor and will try to write the
916-
trace messages into this file descriptor.
917-
Alternatively, if this variable is set to an absolute path
918-
(starting with a '/' character), Git will interpret this
919-
as a file path and will try to write the trace messages
920-
into it.
909+
Enables general trace messages, e.g. alias expansion, built-in
910+
command execution and external command execution.
911+
+
912+
If this variable is set to "1", "2" or "true" (comparison
913+
is case insensitive), trace messages will be printed to
914+
stderr.
915+
+
916+
If the variable is set to an integer value greater than 2
917+
and lower than 10 (strictly) then Git will interpret this
918+
value as an open file descriptor and will try to write the
919+
trace messages into this file descriptor.
920+
+
921+
Alternatively, if the variable is set to an absolute path
922+
(starting with a '/' character), Git will interpret this
923+
as a file path and will try to write the trace messages
924+
into it.
925+
+
926+
Unsetting the variable, or setting it to empty, "0" or
927+
"false" (case insensitive) disables trace messages.
921928

922929
'GIT_TRACE_PACK_ACCESS'::
923-
If this variable is set to a path, a file will be created at
924-
the given path logging all accesses to any packs. For each
930+
Enables trace messages for all accesses to any packs. For each
925931
access, the pack file name and an offset in the pack is
926932
recorded. This may be helpful for troubleshooting some
927933
pack-related performance problems.
934+
See 'GIT_TRACE' for available trace output options.
928935

929936
'GIT_TRACE_PACKET'::
930-
If this variable is set, it shows a trace of all packets
931-
coming in or out of a given program. This can help with
932-
debugging object negotiation or other protocol issues. Tracing
933-
is turned off at a packet starting with "PACK".
937+
Enables trace messages for all packets coming in or out of a
938+
given program. This can help with debugging object negotiation
939+
or other protocol issues. Tracing is turned off at a packet
940+
starting with "PACK".
941+
See 'GIT_TRACE' for available trace output options.
942+
943+
'GIT_TRACE_PERFORMANCE'::
944+
Enables performance related trace messages, e.g. total execution
945+
time of each Git command.
946+
See 'GIT_TRACE' for available trace output options.
947+
948+
'GIT_TRACE_SETUP'::
949+
Enables trace messages printing the .git, working tree and current
950+
working directory after Git has completed its setup phase.
951+
See 'GIT_TRACE' for available trace output options.
952+
953+
'GIT_TRACE_SHALLOW'::
954+
Enables trace messages that can help debugging fetching /
955+
cloning of shallow repositories.
956+
See 'GIT_TRACE' for available trace output options.
934957

935958
GIT_LITERAL_PATHSPECS::
936959
Setting this variable to `1` will cause Git to treat all

Documentation/technical/api-trace.txt

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
trace API
2+
=========
3+
4+
The trace API can be used to print debug messages to stderr or a file. Trace
5+
code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment
6+
variables.
7+
8+
The trace implementation automatically adds `timestamp file:line ... \n` to
9+
all trace messages. E.g.:
10+
11+
------------
12+
23:59:59.123456 git.c:312 trace: built-in: git 'foo'
13+
00:00:00.000001 builtin/foo.c:99 foo: some message
14+
------------
15+
16+
Data Structures
17+
---------------
18+
19+
`struct trace_key`::
20+
21+
Defines a trace key (or category). The default (for API functions that
22+
don't take a key) is `GIT_TRACE`.
23+
+
24+
E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`:
25+
+
26+
------------
27+
static struct trace_key trace_foo = TRACE_KEY_INIT(FOO);
28+
29+
static void trace_print_foo(const char *message)
30+
{
31+
trace_print_key(&trace_foo, message);
32+
}
33+
------------
34+
+
35+
Note: don't use `const` as the trace implementation stores internal state in
36+
the `trace_key` structure.
37+
38+
Functions
39+
---------
40+
41+
`int trace_want(struct trace_key *key)`::
42+
43+
Checks whether the trace key is enabled. Used to prevent expensive
44+
string formatting before calling one of the printing APIs.
45+
46+
`void trace_disable(struct trace_key *key)`::
47+
48+
Disables tracing for the specified key, even if the environment
49+
variable was set.
50+
51+
`void trace_printf(const char *format, ...)`::
52+
`void trace_printf_key(struct trace_key *key, const char *format, ...)`::
53+
54+
Prints a formatted message, similar to printf.
55+
56+
`void trace_argv_printf(const char **argv, const char *format, ...)``::
57+
58+
Prints a formatted message, followed by a quoted list of arguments.
59+
60+
`void trace_strbuf(struct trace_key *key, const struct strbuf *data)`::
61+
62+
Prints the strbuf, without additional formatting (i.e. doesn't
63+
choke on `%` or even `\0`).
64+
65+
`uint64_t getnanotime(void)`::
66+
67+
Returns nanoseconds since the epoch (01/01/1970), typically used
68+
for performance measurements.
69+
+
70+
Currently there are high precision timer implementations for Linux (using
71+
`clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`).
72+
Other platforms use `gettimeofday` as time source.
73+
74+
`void trace_performance(uint64_t nanos, const char *format, ...)`::
75+
`void trace_performance_since(uint64_t start, const char *format, ...)`::
76+
77+
Prints the elapsed time (in nanoseconds), or elapsed time since
78+
`start`, followed by a formatted message. Enabled via environment
79+
variable `GIT_TRACE_PERFORMANCE`. Used for manual profiling, e.g.:
80+
+
81+
------------
82+
uint64_t start = getnanotime();
83+
/* code section to measure */
84+
trace_performance_since(start, "foobar");
85+
------------
86+
+
87+
------------
88+
uint64_t t = 0;
89+
for (;;) {
90+
/* ignore */
91+
t -= getnanotime();
92+
/* code section to measure */
93+
t += getnanotime();
94+
/* ignore */
95+
}
96+
trace_performance(t, "frotz");
97+
------------

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ all::
340340
#
341341
# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
342342
# return NULL when it receives a bogus time_t.
343+
#
344+
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
343345

344346
GIT-VERSION-FILE: FORCE
345347
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -1500,6 +1502,11 @@ ifdef GMTIME_UNRELIABLE_ERRORS
15001502
BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS
15011503
endif
15021504

1505+
ifdef HAVE_CLOCK_GETTIME
1506+
BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
1507+
EXTLIBS += -lrt
1508+
endif
1509+
15031510
ifeq ($(TCLTK_PATH),)
15041511
NO_TCLTK = NoThanks
15051512
endif

builtin/receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
438438
uint32_t mask = 1 << (cmd->index % 32);
439439
int i;
440440

441-
trace_printf_key("GIT_TRACE_SHALLOW",
441+
trace_printf_key(&trace_shallow,
442442
"shallow: update_shallow_ref %s\n", cmd->ref_name);
443443
for (i = 0; i < si->shallow->nr; i++)
444444
if (si->used_shallow[i] &&

cache.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "advice.h"
88
#include "gettext.h"
99
#include "convert.h"
10+
#include "trace.h"
1011

1112
#include SHA1_HEADER
1213
#ifndef git_SHA_CTX
@@ -1402,17 +1403,7 @@ extern void *alloc_tag_node(void);
14021403
extern void *alloc_object_node(void);
14031404
extern void alloc_report(void);
14041405

1405-
/* trace.c */
1406-
__attribute__((format (printf, 1, 2)))
1407-
extern void trace_printf(const char *format, ...);
1408-
__attribute__((format (printf, 2, 3)))
1409-
extern void trace_argv_printf(const char **argv, const char *format, ...);
1410-
extern void trace_repo_setup(const char *prefix);
1411-
extern int trace_want(const char *key);
1412-
__attribute__((format (printf, 2, 3)))
1413-
extern void trace_printf_key(const char *key, const char *fmt, ...);
1414-
extern void trace_strbuf(const char *key, const struct strbuf *buf);
1415-
1406+
/* pkt-line.c */
14161407
void packet_trace_identity(const char *prog);
14171408

14181409
/* add */

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info,
271271
int *ref_status);
272272
extern int delayed_reachability_test(struct shallow_info *si, int c);
273273
extern void prune_shallow(int show_only);
274+
extern struct trace_key trace_shallow;
274275

275276
int is_descendant_of(struct commit *, struct commit_list *);
276277
int in_merge_bases(struct commit *, struct commit *);

config.mak.uname

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ ifeq ($(uname_S),Linux)
3434
HAVE_PATHS_H = YesPlease
3535
LIBC_CONTAINS_LIBINTL = YesPlease
3636
HAVE_DEV_TTY = YesPlease
37+
HAVE_CLOCK_GETTIME = YesPlease
3738
endif
3839
ifeq ($(uname_S),GNU/kFreeBSD)
3940
HAVE_ALLOCA_H = YesPlease

git-compat-util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
761761
#endif
762762
#endif
763763

764+
#if defined(__GNUC__) || (_MSC_VER >= 1400)
765+
#define HAVE_VARIADIC_MACROS 1
766+
#endif
767+
764768
/*
765769
* Preserves errno, prints a message, but gives no warning for ENOENT.
766770
* Always returns the return value of unlink(2).

git.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,8 @@ int main(int argc, char **av)
613613

614614
git_setup_gettext();
615615

616+
trace_command_performance(argv);
617+
616618
/*
617619
* "git-xxxx" is the same as "git xxxx", but we obviously:
618620
*

pkt-line.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
char packet_buffer[LARGE_PACKET_MAX];
55
static const char *packet_trace_prefix = "git";
6-
static const char trace_key[] = "GIT_TRACE_PACKET";
6+
static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET);
77

88
void packet_trace_identity(const char *prog)
99
{
@@ -15,7 +15,7 @@ static void packet_trace(const char *buf, unsigned int len, int write)
1515
int i;
1616
struct strbuf out;
1717

18-
if (!trace_want(trace_key))
18+
if (!trace_want(&trace_packet))
1919
return;
2020

2121
/* +32 is just a guess for header + quoting */
@@ -27,7 +27,7 @@ static void packet_trace(const char *buf, unsigned int len, int write)
2727
if ((len >= 4 && starts_with(buf, "PACK")) ||
2828
(len >= 5 && starts_with(buf+1, "PACK"))) {
2929
strbuf_addstr(&out, "PACK ...");
30-
unsetenv(trace_key);
30+
trace_disable(&trace_packet);
3131
}
3232
else {
3333
/* XXX we should really handle printable utf8 */
@@ -43,7 +43,7 @@ static void packet_trace(const char *buf, unsigned int len, int write)
4343
}
4444

4545
strbuf_addch(&out, '\n');
46-
trace_strbuf(trace_key, &out);
46+
trace_strbuf(&trace_packet, &out);
4747
strbuf_release(&out);
4848
}
4949

0 commit comments

Comments
 (0)