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>
This commit is contained in:
Jeff Hostetler 2019-04-15 13:39:43 -07:00 committed by Junio C Hamano
parent 1703751f21
commit a089724958
7 changed files with 67 additions and 19 deletions

View File

@ -160,17 +160,23 @@ purposes.
These are concerned with the lifetime of the overall git process.
`void trace2_initialize_clock()`::
Initialize the Trace2 start clock and nothing else. This should
be called at the very top of main() to capture the process start
time and reduce startup order dependencies.
`void trace2_initialize()`::
Determines if any Trace2 Targets should be enabled and
initializes the Trace2 facility. This includes starting the
elapsed time clocks and thread local storage (TLS).
initializes the Trace2 facility. This includes setting up the
Trace2 thread local storage (TLS).
+
This function emits a "version" message containing the version of git
and the Trace2 protocol.
+
This function should be called from `main()` as early as possible in
the life of the process.
the life of the process after essential process initialization.
`int trace2_is_enabled()`::

View File

@ -27,6 +27,8 @@ int main(int argc, const char **argv)
{
int result;
trace2_initialize_clock();
/*
* Always open file descriptors 0/1/2 to avoid clobbering files
* in die(). It also avoids messing up when the pipes are dup'ed

View File

@ -2569,6 +2569,8 @@ void mingw_startup(void)
wchar_t **wenv, **wargv;
_startupinfo si;
trace2_initialize_clock();
maybe_redirect_std_handles();
/* get wide char arguments and environment */

View File

@ -142,6 +142,11 @@ static void tr2main_signal_handler(int signo)
raise(signo);
}
void trace2_initialize_clock(void)
{
tr2tls_start_process_clock();
}
void trace2_initialize_fl(const char *file, int line)
{
struct tr2_tgt *tgt_j;
@ -428,7 +433,7 @@ void trace2_thread_start_fl(const char *file, int line, const char *thread_name)
us_now = getnanotime() / 1000;
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
tr2tls_create_self(thread_name);
tr2tls_create_self(thread_name, us_now);
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_thread_start_fl)

View File

@ -19,6 +19,23 @@ struct json_writer;
* [] trace2_printf* -- legacy trace[1] messages.
*/
/*
* Initialize the TRACE2 clock and do nothing else, in particular
* no mallocs, no system inspection, and no environment inspection.
*
* This should be called at the very top of main() to capture the
* process start time. This is intended to reduce chicken-n-egg
* bootstrap pressure.
*
* It is safe to call this more than once. This allows capturing
* absolute startup costs on Windows which uses a little trickery
* to do setup work before common-main.c:main() is called.
*
* The main trace2_initialize_fl() may be called a little later
* after more infrastructure is established.
*/
void trace2_initialize_clock(void);
/*
* Initialize TRACE2 tracing facility if any of the builtin TRACE2
* targets are enabled in the environment. Emits a 'version' event.

View File

@ -10,16 +10,30 @@
#define TR2_REGION_NESTING_INITIAL_SIZE (100)
static struct tr2tls_thread_ctx *tr2tls_thread_main;
static uint64_t tr2tls_us_start_main;
static uint64_t tr2tls_us_start_process;
static pthread_mutex_t tr2tls_mutex;
static pthread_key_t tr2tls_key;
static int tr2_next_thread_id; /* modify under lock */
struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
void tr2tls_start_process_clock(void)
{
if (tr2tls_us_start_process)
return;
/*
* Keep the absolute start time of the process (i.e. the main
* process) in a fixed variable since other threads need to
* access it. This allows them to do that without a lock on
* main thread's array data (because of reallocs).
*/
tr2tls_us_start_process = getnanotime() / 1000;
}
struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name,
uint64_t us_thread_start)
{
uint64_t us_now = getnanotime() / 1000;
struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx));
/*
@ -29,7 +43,7 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
*/
ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t));
ctx->array_us_start[ctx->nr_open_regions++] = us_now;
ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start;
ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
@ -55,7 +69,7 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void)
* here and silently continue.
*/
if (!ctx)
ctx = tr2tls_create_self("unknown");
ctx = tr2tls_create_self("unknown", getnanotime() / 1000);
return ctx;
}
@ -124,22 +138,18 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
if (!tr2tls_thread_main)
return 0;
return us - tr2tls_us_start_main;
return us - tr2tls_us_start_process;
}
void tr2tls_init(void)
{
tr2tls_start_process_clock();
pthread_key_create(&tr2tls_key, NULL);
init_recursive_mutex(&tr2tls_mutex);
tr2tls_thread_main = tr2tls_create_self("main");
/*
* Keep a copy of the absolute start time of the main thread
* in a fixed variable since other threads need to access it.
* This also eliminates the need to lock accesses to the main
* thread's array (because of reallocs).
*/
tr2tls_us_start_main = tr2tls_thread_main->array_us_start[0];
tr2tls_thread_main =
tr2tls_create_self("main", tr2tls_us_start_process);
}
void tr2tls_release(void)

View File

@ -31,7 +31,8 @@ struct tr2tls_thread_ctx {
* In this and all following functions the term "self" refers to the
* current thread.
*/
struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name);
struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name,
uint64_t us_thread_start);
/*
* Get our TLS data.
@ -94,4 +95,9 @@ void tr2tls_release(void);
*/
int tr2tls_locked_increment(int *p);
/*
* Capture the process start time and do nothing else.
*/
void tr2tls_start_process_clock(void);
#endif /* TR2_TLS_H */