Skip to content

Commit a089724

Browse files
jeffhostetlergitster
authored andcommitted
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>
1 parent 1703751 commit a089724

File tree

7 files changed

+67
-19
lines changed

7 files changed

+67
-19
lines changed

Documentation/technical/api-trace2.txt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,17 +160,23 @@ purposes.
160160

161161
These are concerned with the lifetime of the overall git process.
162162

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+
163169
`void trace2_initialize()`::
164170

165171
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).
168174
+
169175
This function emits a "version" message containing the version of git
170176
and the Trace2 protocol.
171177
+
172178
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.
174180

175181
`int trace2_is_enabled()`::
176182

common-main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ int main(int argc, const char **argv)
2727
{
2828
int result;
2929

30+
trace2_initialize_clock();
31+
3032
/*
3133
* Always open file descriptors 0/1/2 to avoid clobbering files
3234
* in die(). It also avoids messing up when the pipes are dup'ed

compat/mingw.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,6 +2569,8 @@ void mingw_startup(void)
25692569
wchar_t **wenv, **wargv;
25702570
_startupinfo si;
25712571

2572+
trace2_initialize_clock();
2573+
25722574
maybe_redirect_std_handles();
25732575

25742576
/* get wide char arguments and environment */

trace2.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ static void tr2main_signal_handler(int signo)
142142
raise(signo);
143143
}
144144

145+
void trace2_initialize_clock(void)
146+
{
147+
tr2tls_start_process_clock();
148+
}
149+
145150
void trace2_initialize_fl(const char *file, int line)
146151
{
147152
struct tr2_tgt *tgt_j;
@@ -428,7 +433,7 @@ void trace2_thread_start_fl(const char *file, int line, const char *thread_name)
428433
us_now = getnanotime() / 1000;
429434
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
430435

431-
tr2tls_create_self(thread_name);
436+
tr2tls_create_self(thread_name, us_now);
432437

433438
for_each_wanted_builtin (j, tgt_j)
434439
if (tgt_j->pfn_thread_start_fl)

trace2.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ struct json_writer;
1919
* [] trace2_printf* -- legacy trace[1] messages.
2020
*/
2121

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+
2239
/*
2340
* Initialize TRACE2 tracing facility if any of the builtin TRACE2
2441
* targets are enabled in the environment. Emits a 'version' event.

trace2/tr2_tls.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,30 @@
1010
#define TR2_REGION_NESTING_INITIAL_SIZE (100)
1111

1212
static struct tr2tls_thread_ctx *tr2tls_thread_main;
13-
static uint64_t tr2tls_us_start_main;
13+
static uint64_t tr2tls_us_start_process;
1414

1515
static pthread_mutex_t tr2tls_mutex;
1616
static pthread_key_t tr2tls_key;
1717

1818
static int tr2_next_thread_id; /* modify under lock */
1919

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)
2136
{
22-
uint64_t us_now = getnanotime() / 1000;
2337
struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx));
2438

2539
/*
@@ -29,7 +43,7 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
2943
*/
3044
ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
3145
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;
3347

3448
ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
3549

@@ -55,7 +69,7 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void)
5569
* here and silently continue.
5670
*/
5771
if (!ctx)
58-
ctx = tr2tls_create_self("unknown");
72+
ctx = tr2tls_create_self("unknown", getnanotime() / 1000);
5973

6074
return ctx;
6175
}
@@ -124,22 +138,18 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
124138
if (!tr2tls_thread_main)
125139
return 0;
126140

127-
return us - tr2tls_us_start_main;
141+
return us - tr2tls_us_start_process;
128142
}
129143

130144
void tr2tls_init(void)
131145
{
146+
tr2tls_start_process_clock();
147+
132148
pthread_key_create(&tr2tls_key, NULL);
133149
init_recursive_mutex(&tr2tls_mutex);
134150

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);
143153
}
144154

145155
void tr2tls_release(void)

trace2/tr2_tls.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ struct tr2tls_thread_ctx {
3131
* In this and all following functions the term "self" refers to the
3232
* current thread.
3333
*/
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);
3536

3637
/*
3738
* Get our TLS data.
@@ -94,4 +95,9 @@ void tr2tls_release(void);
9495
*/
9596
int tr2tls_locked_increment(int *p);
9697

98+
/*
99+
* Capture the process start time and do nothing else.
100+
*/
101+
void tr2tls_start_process_clock(void);
102+
97103
#endif /* TR2_TLS_H */

0 commit comments

Comments
 (0)