perfmon2 minimal v3: attach/detach support
PATCH 13/19 perfmon2 minimal v3: attach/detach support
This patch adds the attach and detach functionalities. A perfmon session can be dynamically attached and detached from a thread.
Signed-off-by Stephane Eranian <[email protected]>
--
perfmon/perfmon_attach.c +237 -0
@@ -42,6 +42,243 @@#include "perfmon_priv.h" /** +* __pfm_load_ctx_thread - attach context to a thread +* @ctx: context to operate on +* @task: thread to attach to +* +* The function must be called with the context locked and interrupts disabled. +*/ +static int pfm_load_ctx_thread (struct pfm_context *ctx, +struct task_struct *task) +{ +struct pfm_event_set *set; +struct pfm_context *old; +int ret; +u16 max; + +PFM_DBG ("pid=%d" , task->pid); + +/* +* per-thread: +* - task to attach to is checked in sys_pfm_load_context() to avoid +* locking issues. if found, and not self, task refcount was +* incremented. +*/ + old =cmpxchg (&task->pfm_context,NULL , ctx); +if (old) { +PFM_DBG ("load_pid=%d has a context " +"old=%p new=%p cur=%p" , + task->pid, + old, + ctx, + task->pfm_context); +return -EEXIST ; + } + +/* +* initialize sets +*/ + set = ctx->active_set; + + max = pfm_pmu_conf->regs.max_intr_pmd; + +/* +* cleanup bitvectors +*/ +bitmap_zero (cast_ulp (set->povfl_pmds), max); + + set->npend_ovfls =0 ; + +/* +* we cannot just use plain clear because of arch-specific flags +*/ + set->priv_flags &= ~PFM_SETFL_PRIV_MOD_BOTH ; + + ctx->task = task; + +/* +* perform any architecture specific actions +*/ + ret =pfm_arch_load_context (ctx); +if (ret) + goto error_noload; + +/* +* now reserve the session, before we can proceed with +* actually accessing the PMU hardware +*/ + ret =pfm_session_acquire (); +if (ret) + goto error; + + +if (ctx->task != current) { + + ctx->flags.is_self =0 ; + +/* force a full reload */ + ctx->last_act =PFM_INVALID_ACTIVATION ; + ctx->last_cpu =-1 ; + set->priv_flags |=PFM_SETFL_PRIV_MOD_BOTH ; + + }else { +pfm_check_save_prev_ctx (); + + ctx->last_cpu =smp_processor_id (); +__get_cpu_var (pmu_activation_number)++; + ctx->last_act =__get_cpu_var (pmu_activation_number); + + ctx->flags.is_self =1 ; + +/* +* load PMD from set +* load PMC from set +*/ +pfm_arch_restore_pmds (ctx, set); +pfm_arch_restore_pmcs (ctx, set); + +/* +* set new ownership +*/ +pfm_set_pmu_owner (ctx->task, ctx); + } +set_tsk_thread_flag (task,TIF_PERFMON_CTXSW ); + + ctx->state =PFM_CTX_LOADED ; + +return 0 ; + +error: +pfm_arch_unload_context (ctx); + ctx->task =NULL ; +error_noload: +/* +* detach context +*/ + task->pfm_context =NULL ; +return ret; +} + +/** +* __pfm_load_context - attach context to a thread +* @ctx: context to operate on +* @task: thread to attach to +*/ +int __pfm_load_context (struct pfm_context *ctx,struct task_struct *task) +{ +return pfm_load_ctx_thread (ctx, task); +} + +/** +* pfm_update_ovfl_pmds - account for pending ovfls on PMDs +* @ctx: context to operate on +* +* This function is always called after pfm_stop has been issued +*/ +static void pfm_update_ovfl_pmds (struct pfm_context *ctx) +{ +struct pfm_event_set *set; +u64 *cnt_pmds; +u64 ovfl_mask; +u16 num_ovfls, i; + + ovfl_mask = pfm_pmu_conf->ovfl_mask; + cnt_pmds = pfm_pmu_conf->regs.cnt_pmds; + set = ctx->active_set; + +if (!set->npend_ovfls) +return ; + + num_ovfls = set->npend_ovfls; +PFM_DBG ("novfls=%u" , num_ovfls); + +for (i =0 ; num_ovfls; i++) { +if (test_bit (i,cast_ulp (set->povfl_pmds))) { +/* only correct value for counters */ +if (test_bit (i,cast_ulp (cnt_pmds))) + set->pmds[i].value +=1 + ovfl_mask; + num_ovfls--; + } +PFM_DBG ("pmd%u val=0x%llx" , + i, + (unsigned long long )set->pmds[i].value); + } +/* +* we need to clear to prevent a pfm_getinfo_evtsets() from +* returning stale data even after the context is unloaded +*/ + set->npend_ovfls =0 ; +bitmap_zero (cast_ulp (set->povfl_pmds), + pfm_pmu_conf->regs.max_intr_pmd); +} + +/** +* __pfm_unload_context - detach context from CPU or thread +* @ctx: context to operate on +* +* The function must be called with the context locked and interrupts disabled. +*/ +int __pfm_unload_context (struct pfm_context *ctx) +{ +int ret; + +PFM_DBG ("ctx_state=%d task [%d]" , + ctx->state, + ctx->task ? ctx->task->pid :-1 ); + +/* +* check unload-able state +*/ +if (ctx->state ==PFM_CTX_UNLOADED ) +return -EINVAL ; + +/* +* stop monitoring +*/ + ret =__pfm_stop (ctx); +if (ret) +return ret; + + ctx->state =PFM_CTX_UNLOADED ; + +/* +* save active set +* UP: +* if not current task and due to lazy, state may +* still be live +* for system-wide, guaranteed to run on correct CPU +*/ +if (__get_cpu_var (pmu_ctx) == ctx) { +/* +* pending overflows have been saved by pfm_stop() +*/ +pfm_save_pmds (ctx); +pfm_set_pmu_owner (NULL ,NULL ); +PFM_DBG ("released ownership" ); + } + +/* +* account for pending overflows +*/ +pfm_update_ovfl_pmds (ctx); + +/* +* arch-specific unload operations +*/ +pfm_arch_unload_context (ctx); + +/* +* per-thread: disconnect from monitored task +*/ +if (ctx->task) { + ctx->task->pfm_context =NULL ; +clear_tsk_thread_flag (ctx->task,TIF_PERFMON_CTXSW ); + ctx->task =NULL ; + } +return 0 ; +} + +/** * __pfm_exit_thread - detach and free context on thread exit */ void __pfm_exit_thread (void )
perfmon/perfmon_priv.h +3 -0
@@ -60,6 +60,9 @@int __pfm_stop (struct pfm_context *ctx);int __pfm_start (struct pfm_context *ctx); +int __pfm_load_context (struct pfm_context *ctx,struct task_struct *task); +int __pfm_unload_context (struct pfm_context *ctx); +ssize_t pfm_sysfs_res_show (char *buf,size_t sz,int what);int pfm_pmu_acquire (void );
perfmon/Makefile +1 -1
@@ -7,4 +7,4 @@ perfmon_init.o perfmon_ctxsw.o \ perfmon_intr.o perfmon_pmu.o \ perfmon_sysfs.o perfmon_rw.o \ - perfmon_activate.o + perfmon_activate.o perfmon_attach.o