trace2 / tr2_tls.con commit Merge branch 'jh/trace2' (32038fe)
   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
  12static struct tr2tls_thread_ctx *tr2tls_thread_main;
  13static uint64_t tr2tls_us_start_main;
  14
  15static pthread_mutex_t tr2tls_mutex;
  16static pthread_key_t tr2tls_key;
  17
  18static int tr2_next_thread_id; /* modify under lock */
  19
  20struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
  21{
  22        uint64_t us_now = getnanotime() / 1000;
  23        struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx));
  24
  25        /*
  26         * Implicitly "tr2tls_push_self()" to capture the thread's start
  27         * time in array_us_start[0].  For the main thread this gives us the
  28         * application run time.
  29         */
  30        ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
  31        ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t));
  32        ctx->array_us_start[ctx->nr_open_regions++] = us_now;
  33
  34        ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
  35
  36        strbuf_init(&ctx->thread_name, 0);
  37        if (ctx->thread_id)
  38                strbuf_addf(&ctx->thread_name, "th%02d:", ctx->thread_id);
  39        strbuf_addstr(&ctx->thread_name, thread_name);
  40        if (ctx->thread_name.len > TR2_MAX_THREAD_NAME)
  41                strbuf_setlen(&ctx->thread_name, TR2_MAX_THREAD_NAME);
  42
  43        pthread_setspecific(tr2tls_key, ctx);
  44
  45        return ctx;
  46}
  47
  48struct tr2tls_thread_ctx *tr2tls_get_self(void)
  49{
  50        struct tr2tls_thread_ctx *ctx = pthread_getspecific(tr2tls_key);
  51
  52        /*
  53         * If the thread-proc did not call trace2_thread_start(), we won't
  54         * have any TLS data associated with the current thread.  Fix it
  55         * here and silently continue.
  56         */
  57        if (!ctx)
  58                ctx = tr2tls_create_self("unknown");
  59
  60        return ctx;
  61}
  62
  63int tr2tls_is_main_thread(void)
  64{
  65        struct tr2tls_thread_ctx *ctx = pthread_getspecific(tr2tls_key);
  66
  67        return ctx == tr2tls_thread_main;
  68}
  69
  70void tr2tls_unset_self(void)
  71{
  72        struct tr2tls_thread_ctx *ctx;
  73
  74        ctx = tr2tls_get_self();
  75
  76        pthread_setspecific(tr2tls_key, NULL);
  77
  78        free(ctx->array_us_start);
  79        free(ctx);
  80}
  81
  82void tr2tls_push_self(uint64_t us_now)
  83{
  84        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  85
  86        ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc);
  87        ctx->array_us_start[ctx->nr_open_regions++] = us_now;
  88}
  89
  90void tr2tls_pop_self(void)
  91{
  92        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  93
  94        if (!ctx->nr_open_regions)
  95                BUG("no open regions in thread '%s'", ctx->thread_name.buf);
  96
  97        ctx->nr_open_regions--;
  98}
  99
 100void tr2tls_pop_unwind_self(void)
 101{
 102        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
 103
 104        while (ctx->nr_open_regions > 1)
 105                tr2tls_pop_self();
 106}
 107
 108uint64_t tr2tls_region_elasped_self(uint64_t us)
 109{
 110        struct tr2tls_thread_ctx *ctx;
 111        uint64_t us_start;
 112
 113        ctx = tr2tls_get_self();
 114        if (!ctx->nr_open_regions)
 115                return 0;
 116
 117        us_start = ctx->array_us_start[ctx->nr_open_regions - 1];
 118
 119        return us - us_start;
 120}
 121
 122uint64_t tr2tls_absolute_elapsed(uint64_t us)
 123{
 124        if (!tr2tls_thread_main)
 125                return 0;
 126
 127        return us - tr2tls_us_start_main;
 128}
 129
 130void tr2tls_init(void)
 131{
 132        pthread_key_create(&tr2tls_key, NULL);
 133        init_recursive_mutex(&tr2tls_mutex);
 134
 135        tr2tls_thread_main = tr2tls_create_self("main");
 136        /*
 137         * Keep a copy of the absolute start time of the main thread
 138         * in a fixed variable since other threads need to access it.
 139         * This also eliminates the need to lock accesses to the main
 140         * thread's array (because of reallocs).
 141         */
 142        tr2tls_us_start_main = tr2tls_thread_main->array_us_start[0];
 143}
 144
 145void tr2tls_release(void)
 146{
 147        tr2tls_unset_self();
 148        tr2tls_thread_main = NULL;
 149
 150        pthread_mutex_destroy(&tr2tls_mutex);
 151        pthread_key_delete(tr2tls_key);
 152}
 153
 154int tr2tls_locked_increment(int *p)
 155{
 156        int current_value;
 157
 158        pthread_mutex_lock(&tr2tls_mutex);
 159        current_value = *p;
 160        *p = current_value + 1;
 161        pthread_mutex_unlock(&tr2tls_mutex);
 162
 163        return current_value;
 164}