Skip to content

Commit

Permalink
mcount: Change TLS type to initial-exec
Browse files Browse the repository at this point in the history
-. Benefit
changed the model of the TLS variable mtd to initial-exec.
The initial-exec model doesn't ocurred problem because it is not make
any calls to refer the TLS. the way to refer to variables in the
intial-exec is adding or subtracting offsets from static TLS blocks
as follows.

mov 0x2d6a6 (% rip),% rax # 35fc8 <.got + 0x38>
mov% fs: (% rax),% rbx

as a rough bench result, the initial-exec type TLS variable can be
expected to increase the reference speed by about x2 times or more
than the TLS variable using the POSIX pthread.

In addition, the initial-exec type TLS variable could be expected to
improve the reference speed by about 20% compared to the dynamic type
TLS variable created when using a general __thread.

-. Limitation
the initial-exec TLS model have limitation. TLS will allocated by
loader and the initial-exec TLS block allocate statically. after
process already running and the initial-exec allocated, it can be
that there is not enough space in initial-exec static TLS block to
allocate mtd. typical execution environment no need to worry about.

--. Limitation mitigation
but to prepare future update, there is need to reduce size of
`tls_mtd` to minimized. added new two TLS variable pointer `mtd_tls`
and bool `mcount_recursion_marker`.

allocate `struct mcount_thread_data` to heap. and manage it by
`*tls_mtd` which declared as TLS variable. and `mcount_recursion_marker`
has same role with `mcount_recursion_marker` that inside of
`struct mcount_thread_data`.

-.. reference
For more information on this, please see the following link:
https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt

reference document written in Korean :
https://die4taoam.tistory.com/37

Signed-off-by: Hanbum Park <kese111@gmail.com>
  • Loading branch information
ParkHanbum committed Dec 18, 2022
1 parent 2a30257 commit 8851fa6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 32 deletions.
19 changes: 11 additions & 8 deletions libmcount/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ struct mcount_thread_data {
int tid;
int idx;
int record_idx;
bool recursion_marker;
bool in_exception;
bool dead;
bool warned;
Expand Down Expand Up @@ -158,20 +157,24 @@ static inline void mcount_restore_arch_context(struct mcount_arch_context *ctx)

#ifdef SINGLE_THREAD
#define TLS
#define get_thread_data() &mtd
#define check_thread_data(mtdp) (mtdp->rstack == NULL)
#define TLS_ATTR
#else
#define TLS __thread
#define get_thread_data() pthread_getspecific(mtd_key)
#define check_thread_data(mtdp) (mtdp == NULL)
#define TLS_ATTR __attribute__((tls_model("initial-exec")))
#endif

extern TLS struct mcount_thread_data mtd;
#define check_thread_data(mtdp) (mtdp == NULL)
#define get_thread_data() tls_mtd

extern TLS struct mcount_thread_data *tls_mtd TLS_ATTR;
extern TLS bool mcount_recursion_marker TLS_ATTR;

void __mcount_guard_recursion(struct mcount_thread_data *mtdp);
void __mcount_unguard_recursion(struct mcount_thread_data *mtdp);
void __mcount_guard_recursion(void);
void __mcount_unguard_recursion(void);
bool mcount_guard_recursion(struct mcount_thread_data *mtdp);
void mcount_unguard_recursion(struct mcount_thread_data *mtdp);
bool mcount_need_dead(struct mcount_thread_data *mtdp);
void mcount_should_dead(struct mcount_thread_data *mtdp);

extern uint64_t mcount_threshold; /* nsec */
extern pthread_key_t mtd_key;
Expand Down
60 changes: 39 additions & 21 deletions libmcount/mcount.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ unsigned long mcount_global_flags = MCOUNT_GFL_SETUP;
pthread_key_t mtd_key = (pthread_key_t)-1;

/* thread local data to trace function execution */
TLS struct mcount_thread_data mtd;
TLS struct mcount_thread_data *tls_mtd TLS_ATTR;
TLS bool mcount_recursion_marker TLS_ATTR;

/* pipe file descriptor to communite to uftrace */
int pfd = -1;
Expand Down Expand Up @@ -592,15 +593,15 @@ void mtd_dtor(void *arg)
struct mcount_thread_data *mtdp = arg;
struct uftrace_msg_task tmsg;

if (mtdp->dead)
if (mcount_need_dead(mtdp))
return;

if (mcount_should_stop())
mcount_trace_finish(true);

/* this thread is done, do not enter anymore */
mtdp->recursion_marker = true;
mtdp->dead = true;
__mcount_guard_recursion();
mcount_should_dead(get_thread_data());

if (mcount_estimate_return)
mcount_rstack_estimate_finish(mtdp);
Expand All @@ -617,6 +618,7 @@ void mtd_dtor(void *arg)
mcount_watch_release(mtdp);
finish_mem_region(&mtdp->mem_regions);
shmem_finish(mtdp);
free(mtdp);

tmsg.pid = getpid();
tmsg.tid = mcount_gettid(mtdp);
Expand All @@ -625,33 +627,43 @@ void mtd_dtor(void *arg)
uftrace_send_message(UFTRACE_MSG_TASK_END, &tmsg, sizeof(tmsg));
}

void __mcount_guard_recursion(struct mcount_thread_data *mtdp)
bool mcount_need_dead(struct mcount_thread_data *mtdp)
{
mtdp->recursion_marker = true;
return mtdp->dead;
}

void __mcount_unguard_recursion(struct mcount_thread_data *mtdp)
void mcount_should_dead(struct mcount_thread_data *mtdp)
{
mtdp->recursion_marker = false;
mtdp->dead = true;
}

void __mcount_guard_recursion(void)
{
mcount_recursion_marker = true;
}

void __mcount_unguard_recursion(void)
{
mcount_recursion_marker = false;
}

bool mcount_guard_recursion(struct mcount_thread_data *mtdp)
{
if (unlikely(mtdp->recursion_marker))
if (unlikely(mcount_recursion_marker))
return false;

if (unlikely(mcount_should_stop())) {
mtd_dtor(mtdp);
return false;
}

mtdp->recursion_marker = true;
__mcount_guard_recursion();
return true;
}

void mcount_unguard_recursion(struct mcount_thread_data *mtdp)
{
mtdp->recursion_marker = false;
__mcount_unguard_recursion();

if (unlikely(mcount_should_stop()))
mtd_dtor(mtdp);
Expand Down Expand Up @@ -754,7 +766,7 @@ static void mcount_init_file(void)
.sa_flags = SA_SIGINFO,
};

send_session_msg(&mtd, mcount_session_name());
send_session_msg(get_thread_data(), mcount_session_name());
pr_dbg("new session started: %.*s: %s\n", SESSION_ID_LEN, mcount_session_name(),
basename(mcount_exename));

Expand All @@ -763,10 +775,15 @@ static void mcount_init_file(void)
sigaction(SIGSEGV, &sa, &old_sigact[1]);
}

struct mcount_thread_data *mcount_thread_data_alloc(void)
{
return get_thread_data() = xzalloc(sizeof(struct mcount_thread_data));
}

struct mcount_thread_data *mcount_prepare(void)
{
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
struct mcount_thread_data *mtdp = &mtd;
struct mcount_thread_data *mtdp = get_thread_data();
struct uftrace_msg_task tmsg;

if (unlikely(mcount_should_stop()))
Expand All @@ -783,15 +800,16 @@ struct mcount_thread_data *mcount_prepare(void)

compiler_barrier();

if (!mtdp)
mtdp = mcount_thread_data_alloc();

mcount_filter_setup(mtdp);
mcount_watch_setup(mtdp);
mtdp->rstack = xmalloc(mcount_rstack_max * sizeof(*mtd.rstack));
mtdp->rstack = xmalloc(mcount_rstack_max * sizeof(*mtdp->rstack));

pthread_once(&once_control, mcount_init_file);
prepare_shmem_buffer(mtdp);

pthread_setspecific(mtd_key, mtdp);

/* time should be get after session message sent */
tmsg.pid = getpid(), tmsg.tid = mcount_gettid(mtdp), tmsg.time = mcount_gettime();

Expand Down Expand Up @@ -1364,14 +1382,14 @@ static unsigned long __mcount_exit(long *retval)

mtdp = get_thread_data();
ASSERT(mtdp != NULL);
ASSERT(!mtdp->dead);
ASSERT(!mcount_need_dead(mtdp));

/*
* it's only called when mcount_entry() was succeeded and
* no need to check recursion here. But still needs to
* prevent recursion during this call.
*/
__mcount_guard_recursion(mtdp);
__mcount_guard_recursion();

rstack = &mtdp->rstack[mtdp->idx - 1];

Expand All @@ -1385,7 +1403,7 @@ static unsigned long __mcount_exit(long *retval)
if (mcount_auto_recover)
mcount_auto_reset(mtdp);

__mcount_unguard_recursion(mtdp);
__mcount_unguard_recursion();

if (unlikely(mcount_should_stop())) {
mtd_dtor(mtdp);
Expand Down Expand Up @@ -1901,7 +1919,7 @@ static __used void mcount_startup(void)
if (!(mcount_global_flags & MCOUNT_GFL_SETUP))
return;

mtd.recursion_marker = true;
__mcount_guard_recursion();

outfp = stdout;
logfp = stderr;
Expand Down Expand Up @@ -2047,7 +2065,7 @@ static __used void mcount_startup(void)
pr_dbg("mcount setup done\n");

mcount_global_flags &= ~MCOUNT_GFL_SETUP;
mtd.recursion_marker = false;
__mcount_unguard_recursion();
}

static void mcount_cleanup(void)
Expand Down
6 changes: 3 additions & 3 deletions libmcount/plthook.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ static unsigned long __plthook_exit(long *retval)
* no need to check recursion here. But still needs to
* prevent recursion during this call.
*/
__mcount_guard_recursion(mtdp);
__mcount_guard_recursion();

again:
if (likely(mtdp->idx > 0))
Expand All @@ -951,7 +951,7 @@ static unsigned long __plthook_exit(long *retval)
if (unlikely(dyn_idx == MCOUNT_INVALID_DYNIDX || dyn_idx >= rstack->pd->dsymtab.nr_sym))
pr_err_ns("<%d> invalid dynsym idx: %d\n", mtdp->idx, dyn_idx);

if (!ARCH_CAN_RESTORE_PLTHOOK && unlikely(mtdp->dead)) {
if (!ARCH_CAN_RESTORE_PLTHOOK && unlikely(mcount_need_dead(mtdp))) {
ret_addr = rstack->parent_ip;

/* make sure it doesn't have plthook below */
Expand Down Expand Up @@ -989,7 +989,7 @@ static unsigned long __plthook_exit(long *retval)
if (mcount_auto_recover)
mcount_auto_reset(mtdp);

__mcount_unguard_recursion(mtdp);
__mcount_unguard_recursion();

if (unlikely(mcount_should_stop())) {
mtd_dtor(mtdp);
Expand Down

0 comments on commit 8851fa6

Please sign in to comment.