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:
parent
1703751f21
commit
a089724958
@ -160,17 +160,23 @@ purposes.
|
|||||||
|
|
||||||
These are concerned with the lifetime of the overall git process.
|
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()`::
|
`void trace2_initialize()`::
|
||||||
|
|
||||||
Determines if any Trace2 Targets should be enabled and
|
Determines if any Trace2 Targets should be enabled and
|
||||||
initializes the Trace2 facility. This includes starting the
|
initializes the Trace2 facility. This includes setting up the
|
||||||
elapsed time clocks and thread local storage (TLS).
|
Trace2 thread local storage (TLS).
|
||||||
+
|
+
|
||||||
This function emits a "version" message containing the version of git
|
This function emits a "version" message containing the version of git
|
||||||
and the Trace2 protocol.
|
and the Trace2 protocol.
|
||||||
+
|
+
|
||||||
This function should be called from `main()` as early as possible in
|
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()`::
|
`int trace2_is_enabled()`::
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ int main(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
trace2_initialize_clock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Always open file descriptors 0/1/2 to avoid clobbering files
|
* Always open file descriptors 0/1/2 to avoid clobbering files
|
||||||
* in die(). It also avoids messing up when the pipes are dup'ed
|
* in die(). It also avoids messing up when the pipes are dup'ed
|
||||||
|
@ -2569,6 +2569,8 @@ void mingw_startup(void)
|
|||||||
wchar_t **wenv, **wargv;
|
wchar_t **wenv, **wargv;
|
||||||
_startupinfo si;
|
_startupinfo si;
|
||||||
|
|
||||||
|
trace2_initialize_clock();
|
||||||
|
|
||||||
maybe_redirect_std_handles();
|
maybe_redirect_std_handles();
|
||||||
|
|
||||||
/* get wide char arguments and environment */
|
/* get wide char arguments and environment */
|
||||||
|
7
trace2.c
7
trace2.c
@ -142,6 +142,11 @@ static void tr2main_signal_handler(int signo)
|
|||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void trace2_initialize_clock(void)
|
||||||
|
{
|
||||||
|
tr2tls_start_process_clock();
|
||||||
|
}
|
||||||
|
|
||||||
void trace2_initialize_fl(const char *file, int line)
|
void trace2_initialize_fl(const char *file, int line)
|
||||||
{
|
{
|
||||||
struct tr2_tgt *tgt_j;
|
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_now = getnanotime() / 1000;
|
||||||
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
|
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)
|
for_each_wanted_builtin (j, tgt_j)
|
||||||
if (tgt_j->pfn_thread_start_fl)
|
if (tgt_j->pfn_thread_start_fl)
|
||||||
|
17
trace2.h
17
trace2.h
@ -19,6 +19,23 @@ struct json_writer;
|
|||||||
* [] trace2_printf* -- legacy trace[1] messages.
|
* [] 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
|
* Initialize TRACE2 tracing facility if any of the builtin TRACE2
|
||||||
* targets are enabled in the environment. Emits a 'version' event.
|
* targets are enabled in the environment. Emits a 'version' event.
|
||||||
|
@ -10,16 +10,30 @@
|
|||||||
#define TR2_REGION_NESTING_INITIAL_SIZE (100)
|
#define TR2_REGION_NESTING_INITIAL_SIZE (100)
|
||||||
|
|
||||||
static struct tr2tls_thread_ctx *tr2tls_thread_main;
|
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_mutex_t tr2tls_mutex;
|
||||||
static pthread_key_t tr2tls_key;
|
static pthread_key_t tr2tls_key;
|
||||||
|
|
||||||
static int tr2_next_thread_id; /* modify under lock */
|
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));
|
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->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
|
||||||
ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t));
|
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);
|
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.
|
* here and silently continue.
|
||||||
*/
|
*/
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
ctx = tr2tls_create_self("unknown");
|
ctx = tr2tls_create_self("unknown", getnanotime() / 1000);
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@ -124,22 +138,18 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
|
|||||||
if (!tr2tls_thread_main)
|
if (!tr2tls_thread_main)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return us - tr2tls_us_start_main;
|
return us - tr2tls_us_start_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tr2tls_init(void)
|
void tr2tls_init(void)
|
||||||
{
|
{
|
||||||
|
tr2tls_start_process_clock();
|
||||||
|
|
||||||
pthread_key_create(&tr2tls_key, NULL);
|
pthread_key_create(&tr2tls_key, NULL);
|
||||||
init_recursive_mutex(&tr2tls_mutex);
|
init_recursive_mutex(&tr2tls_mutex);
|
||||||
|
|
||||||
tr2tls_thread_main = tr2tls_create_self("main");
|
tr2tls_thread_main =
|
||||||
/*
|
tr2tls_create_self("main", tr2tls_us_start_process);
|
||||||
* 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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tr2tls_release(void)
|
void tr2tls_release(void)
|
||||||
|
@ -31,7 +31,8 @@ struct tr2tls_thread_ctx {
|
|||||||
* In this and all following functions the term "self" refers to the
|
* In this and all following functions the term "self" refers to the
|
||||||
* current thread.
|
* 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.
|
* Get our TLS data.
|
||||||
@ -94,4 +95,9 @@ void tr2tls_release(void);
|
|||||||
*/
|
*/
|
||||||
int tr2tls_locked_increment(int *p);
|
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 */
|
#endif /* TR2_TLS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user