summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/technical/api-trace2.txt12
-rw-r--r--common-main.c2
-rw-r--r--compat/mingw.c2
-rw-r--r--trace2.c7
-rw-r--r--trace2.h17
-rw-r--r--trace2/tr2_tls.c38
-rw-r--r--trace2/tr2_tls.h8
7 files changed, 67 insertions, 19 deletions
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index 2de565f..f37fccf 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -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()`::
diff --git a/common-main.c b/common-main.c
index d484aec..6137af0 100644
--- a/common-main.c
+++ b/common-main.c
@@ -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
diff --git a/compat/mingw.c b/compat/mingw.c
index 6b04514..a2f74ac 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -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 */
diff --git a/trace2.c b/trace2.c
index ccccd4e..6dd51e6 100644
--- a/trace2.c
+++ b/trace2.c
@@ -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)
diff --git a/trace2.h b/trace2.h
index ae5020d..8f89e70 100644
--- a/trace2.h
+++ b/trace2.h
@@ -20,6 +20,23 @@ struct json_writer;
*/
/*
+ * 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.
*
diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c
index 8e65b03..e76d8c5 100644
--- a/trace2/tr2_tls.c
+++ b/trace2/tr2_tls.c
@@ -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)
diff --git a/trace2/tr2_tls.h b/trace2/tr2_tls.h
index bb80e3f..b1e327a 100644
--- a/trace2/tr2_tls.h
+++ b/trace2/tr2_tls.h
@@ -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 */