Elijah Newren | 36bf195 | 2023-02-24 00:09:24 +0000 | [diff] [blame] | 1 | #include "git-compat-util.h" |
Elijah Newren | 0a4d5b9 | 2023-12-23 17:14:58 +0000 | [diff] [blame] | 2 | #include "strbuf.h" |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 3 | #include "thread-utils.h" |
Elijah Newren | 36bf195 | 2023-02-24 00:09:24 +0000 | [diff] [blame] | 4 | #include "trace.h" |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 5 | #include "trace2/tr2_tls.h" |
| 6 | |
| 7 | /* |
| 8 | * Initialize size of the thread stack for nested regions. |
| 9 | * This is used to store nested region start times. Note that |
| 10 | * this stack is per-thread and not per-trace-key. |
| 11 | */ |
| 12 | #define TR2_REGION_NESTING_INITIAL_SIZE (100) |
| 13 | |
| 14 | static struct tr2tls_thread_ctx *tr2tls_thread_main; |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 15 | static uint64_t tr2tls_us_start_process; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 16 | |
| 17 | static pthread_mutex_t tr2tls_mutex; |
| 18 | static pthread_key_t tr2tls_key; |
| 19 | |
| 20 | static int tr2_next_thread_id; /* modify under lock */ |
| 21 | |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 22 | void tr2tls_start_process_clock(void) |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 23 | { |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 24 | if (tr2tls_us_start_process) |
| 25 | return; |
| 26 | |
| 27 | /* |
| 28 | * Keep the absolute start time of the process (i.e. the main |
| 29 | * process) in a fixed variable since other threads need to |
| 30 | * access it. This allows them to do that without a lock on |
| 31 | * main thread's array data (because of reallocs). |
| 32 | */ |
| 33 | tr2tls_us_start_process = getnanotime() / 1000; |
| 34 | } |
| 35 | |
Jeff Hostetler | a70839c | 2022-10-24 13:41:03 +0000 | [diff] [blame] | 36 | struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 37 | uint64_t us_thread_start) |
| 38 | { |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 39 | struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); |
Jeff Hostetler | 24a4c45 | 2022-10-24 13:41:05 +0000 | [diff] [blame] | 40 | struct strbuf buf = STRBUF_INIT; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 41 | |
| 42 | /* |
| 43 | * Implicitly "tr2tls_push_self()" to capture the thread's start |
| 44 | * time in array_us_start[0]. For the main thread this gives us the |
| 45 | * application run time. |
| 46 | */ |
| 47 | ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; |
| 48 | ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 49 | ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 50 | |
| 51 | ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); |
| 52 | |
Jeff Hostetler | 24a4c45 | 2022-10-24 13:41:05 +0000 | [diff] [blame] | 53 | strbuf_init(&buf, 0); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 54 | if (ctx->thread_id) |
Jeff Hostetler | 24a4c45 | 2022-10-24 13:41:05 +0000 | [diff] [blame] | 55 | strbuf_addf(&buf, "th%02d:", ctx->thread_id); |
| 56 | strbuf_addstr(&buf, thread_base_name); |
| 57 | if (buf.len > TR2_MAX_THREAD_NAME) |
| 58 | strbuf_setlen(&buf, TR2_MAX_THREAD_NAME); |
| 59 | ctx->thread_name = strbuf_detach(&buf, NULL); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 60 | |
| 61 | pthread_setspecific(tr2tls_key, ctx); |
| 62 | |
| 63 | return ctx; |
| 64 | } |
| 65 | |
| 66 | struct tr2tls_thread_ctx *tr2tls_get_self(void) |
| 67 | { |
Jeff Hostetler | 5fdae9d | 2019-05-21 12:33:59 -0700 | [diff] [blame] | 68 | struct tr2tls_thread_ctx *ctx; |
| 69 | |
| 70 | if (!HAVE_THREADS) |
| 71 | return tr2tls_thread_main; |
| 72 | |
| 73 | ctx = pthread_getspecific(tr2tls_key); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 74 | |
| 75 | /* |
Jeff Hostetler | 5bbb925 | 2022-10-24 13:41:01 +0000 | [diff] [blame] | 76 | * If the current thread's thread-proc did not call |
| 77 | * trace2_thread_start(), then the thread will not have any |
| 78 | * thread-local storage. Create it now and silently continue. |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 79 | */ |
| 80 | if (!ctx) |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 81 | ctx = tr2tls_create_self("unknown", getnanotime() / 1000); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 82 | |
| 83 | return ctx; |
| 84 | } |
| 85 | |
| 86 | int tr2tls_is_main_thread(void) |
| 87 | { |
Jeff Hostetler | 5fdae9d | 2019-05-21 12:33:59 -0700 | [diff] [blame] | 88 | if (!HAVE_THREADS) |
| 89 | return 1; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 90 | |
Jeff Hostetler | 5fdae9d | 2019-05-21 12:33:59 -0700 | [diff] [blame] | 91 | return pthread_getspecific(tr2tls_key) == tr2tls_thread_main; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | void tr2tls_unset_self(void) |
| 95 | { |
| 96 | struct tr2tls_thread_ctx *ctx; |
| 97 | |
| 98 | ctx = tr2tls_get_self(); |
| 99 | |
| 100 | pthread_setspecific(tr2tls_key, NULL); |
| 101 | |
Jeff Hostetler | 24a4c45 | 2022-10-24 13:41:05 +0000 | [diff] [blame] | 102 | free((char *)ctx->thread_name); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 103 | free(ctx->array_us_start); |
| 104 | free(ctx); |
| 105 | } |
| 106 | |
| 107 | void tr2tls_push_self(uint64_t us_now) |
| 108 | { |
| 109 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); |
| 110 | |
| 111 | ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc); |
| 112 | ctx->array_us_start[ctx->nr_open_regions++] = us_now; |
| 113 | } |
| 114 | |
| 115 | void tr2tls_pop_self(void) |
| 116 | { |
| 117 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); |
| 118 | |
| 119 | if (!ctx->nr_open_regions) |
Jeff Hostetler | 24a4c45 | 2022-10-24 13:41:05 +0000 | [diff] [blame] | 120 | BUG("no open regions in thread '%s'", ctx->thread_name); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 121 | |
| 122 | ctx->nr_open_regions--; |
| 123 | } |
| 124 | |
| 125 | void tr2tls_pop_unwind_self(void) |
| 126 | { |
| 127 | struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); |
| 128 | |
| 129 | while (ctx->nr_open_regions > 1) |
| 130 | tr2tls_pop_self(); |
| 131 | } |
| 132 | |
| 133 | uint64_t tr2tls_region_elasped_self(uint64_t us) |
| 134 | { |
| 135 | struct tr2tls_thread_ctx *ctx; |
| 136 | uint64_t us_start; |
| 137 | |
| 138 | ctx = tr2tls_get_self(); |
| 139 | if (!ctx->nr_open_regions) |
| 140 | return 0; |
| 141 | |
| 142 | us_start = ctx->array_us_start[ctx->nr_open_regions - 1]; |
| 143 | |
| 144 | return us - us_start; |
| 145 | } |
| 146 | |
| 147 | uint64_t tr2tls_absolute_elapsed(uint64_t us) |
| 148 | { |
| 149 | if (!tr2tls_thread_main) |
| 150 | return 0; |
| 151 | |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 152 | return us - tr2tls_us_start_process; |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 153 | } |
| 154 | |
Patrick Steinhardt | 64d9ada | 2024-09-26 13:46:45 +0200 | [diff] [blame] | 155 | static void tr2tls_key_destructor(void *payload) |
| 156 | { |
| 157 | struct tr2tls_thread_ctx *ctx = payload; |
| 158 | free((char *)ctx->thread_name); |
| 159 | free(ctx->array_us_start); |
| 160 | free(ctx); |
| 161 | } |
| 162 | |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 163 | void tr2tls_init(void) |
| 164 | { |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 165 | tr2tls_start_process_clock(); |
| 166 | |
Patrick Steinhardt | 64d9ada | 2024-09-26 13:46:45 +0200 | [diff] [blame] | 167 | pthread_key_create(&tr2tls_key, tr2tls_key_destructor); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 168 | init_recursive_mutex(&tr2tls_mutex); |
| 169 | |
Jeff Hostetler | a089724 | 2019-04-15 13:39:43 -0700 | [diff] [blame] | 170 | tr2tls_thread_main = |
| 171 | tr2tls_create_self("main", tr2tls_us_start_process); |
Jeff Hostetler | ee4512e | 2019-02-22 14:25:01 -0800 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | void tr2tls_release(void) |
| 175 | { |
| 176 | tr2tls_unset_self(); |
| 177 | tr2tls_thread_main = NULL; |
| 178 | |
| 179 | pthread_mutex_destroy(&tr2tls_mutex); |
| 180 | pthread_key_delete(tr2tls_key); |
| 181 | } |
| 182 | |
| 183 | int tr2tls_locked_increment(int *p) |
| 184 | { |
| 185 | int current_value; |
| 186 | |
| 187 | pthread_mutex_lock(&tr2tls_mutex); |
| 188 | current_value = *p; |
| 189 | *p = current_value + 1; |
| 190 | pthread_mutex_unlock(&tr2tls_mutex); |
| 191 | |
| 192 | return current_value; |
| 193 | } |
Jeff Hostetler | 8ad5756 | 2022-10-24 13:41:06 +0000 | [diff] [blame] | 194 | |
| 195 | void tr2tls_lock(void) |
| 196 | { |
| 197 | pthread_mutex_lock(&tr2tls_mutex); |
| 198 | } |
| 199 | |
| 200 | void tr2tls_unlock(void) |
| 201 | { |
| 202 | pthread_mutex_unlock(&tr2tls_mutex); |
| 203 | } |