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