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>maint
							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
	
	 Jeff Hostetler
						Jeff Hostetler