trace2: refactor setting process starting time
Create trace2_initialize_clock() and call from main() to capture process start time in isolation and before other sub-systems are ready. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff Hostetler committed
Apr 15, 2019 at 13:39 UTC
a089724958a99924d9ec7ff60a6aea63d03448f2
7 files changed
+67
-19
Documentation/technical/api-trace2.txt
+9
-3
@@ -160,17 +160,23 @@ purposes.
160
161
These are concerned with the lifetime of the overall git process.
162
163
+`void trace2_initialize_clock()`::
164
+
165
+ Initialize the Trace2 start clock and nothing else. This should
166
+ be called at the very top of main() to capture the process start
167
+ time and reduce startup order dependencies.
168
+
169
`void trace2_initialize()`::
170
171
Determines if any Trace2 Targets should be enabled and
166
- initializes the Trace2 facility. This includes starting the
167
- elapsed time clocks and thread local storage (TLS).
172
+ initializes the Trace2 facility. This includes setting up the
173
+ Trace2 thread local storage (TLS).
174
+
175
This function emits a "version" message containing the version of git
176
and the Trace2 protocol.
177
+
178
This function should be called from `main()` as early as possible in
173
-the life of the process.
179
+the life of the process after essential process initialization.
180
181
`int trace2_is_enabled()`::
182
common-main.c
+2
@@ -27,6 +27,8 @@ int main(int argc, const char **argv)
27
{
28
int result;
29
30
+ trace2_initialize_clock();
31
+
32
/*
33
* Always open file descriptors 0/1/2 to avoid clobbering files
34
* in die(). It also avoids messing up when the pipes are dup'ed
compat/mingw.c
+2
@@ -2569,6 +2569,8 @@ void mingw_startup(void)
2569
wchar_t **wenv, **wargv;
2570
_startupinfo si;
2571
2572
+ trace2_initialize_clock();
2573
+
2574
maybe_redirect_std_handles();
2575
2576
/* get wide char arguments and environment */
trace2.c
+6
-1
@@ -142,6 +142,11 @@ static void tr2main_signal_handler(int signo)
142
raise(signo);
143
}
144
145
+void trace2_initialize_clock(void)
146
+{
147
+ tr2tls_start_process_clock();
148
+}
149
+
150
void trace2_initialize_fl(const char *file, int line)
151
{
152
struct tr2_tgt *tgt_j;
@@ -428,7 +433,7 @@ void trace2_thread_start_fl(const char *file, int line, const char *thread_name)
433
us_now = getnanotime() / 1000;
434
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
435
431
- tr2tls_create_self(thread_name);
436
+ tr2tls_create_self(thread_name, us_now);
437
438
for_each_wanted_builtin (j, tgt_j)
439
if (tgt_j->pfn_thread_start_fl)
trace2.h
+17
@@ -19,6 +19,23 @@ struct json_writer;
19
* [] trace2_printf* -- legacy trace[1] messages.
20
*/
21
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
/*
40
* Initialize TRACE2 tracing facility if any of the builtin TRACE2
41
* targets are enabled in the environment. Emits a 'version' event.
trace2/tr2_tls.c
+24
-14
@@ -10,16 +10,30 @@
10
#define TR2_REGION_NESTING_INITIAL_SIZE (100)
11
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
15
static pthread_mutex_t tr2tls_mutex;
16
static pthread_key_t tr2tls_key;
17
18
static int tr2_next_thread_id; /* modify under lock */
19
20
-struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
20
+void tr2tls_start_process_clock(void)
21
+{
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
{
22
- uint64_t us_now = getnanotime() / 1000;
37
struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx));
38
39
/*
@@ -29,7 +43,7 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
43
*/
44
ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
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;
47
48
ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
49
@@ -55,7 +69,7 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void)
69
* here and silently continue.
70
*/
71
if (!ctx)
58
- ctx = tr2tls_create_self("unknown");
72
+ ctx = tr2tls_create_self("unknown", getnanotime() / 1000);
73
74
return ctx;
75
}
@@ -124,22 +138,18 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
138
if (!tr2tls_thread_main)
139
return 0;
140
127
- return us - tr2tls_us_start_main;
141
+ return us - tr2tls_us_start_process;
142
}
143
144
void tr2tls_init(void)
145
{
146
+ tr2tls_start_process_clock();
147
+
148
pthread_key_create(&tr2tls_key, NULL);
149
init_recursive_mutex(&tr2tls_mutex);
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);
153
}
154
155
void tr2tls_release(void)
trace2/tr2_tls.h
+7
-1
@@ -31,7 +31,8 @@ struct tr2tls_thread_ctx {
31
* In this and all following functions the term "self" refers to the
32
* current thread.
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);
36
37
/*
38
* Get our TLS data.
@@ -94,4 +95,9 @@ void tr2tls_release(void);
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);
102
+
103
#endif /* TR2_TLS_H */