From: eranian@googlemail.com
To: linux-kernel@vger.kernel.org
Subject: [patch 15/21] perfmon2 minimal: attach/detach support
Date: Mon, 09 Jun 2008 15:34:40 -0700 (PDT) [thread overview]
Message-ID: <484db000.0aec660a.2b01.6499@mx.google.com> (raw)
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 <eranian@gmail.com>
--
Index: o/perfmon/perfmon_attach.c
===================================================================
--- o.orig/perfmon/perfmon_attach.c 2008-06-09 11:17:31.000000000 +0200
+++ o/perfmon/perfmon_attach.c 2008-06-09 11:19:08.000000000 +0200
@@ -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)
Index: o/perfmon/perfmon_priv.h
===================================================================
--- o.orig/perfmon/perfmon_priv.h 2008-06-09 11:18:31.000000000 +0200
+++ o/perfmon/perfmon_priv.h 2008-06-09 11:19:08.000000000 +0200
@@ -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);
--
reply other threads:[~2008-06-09 22:40 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=484db000.0aec660a.2b01.6499@mx.google.com \
--to=eranian@googlemail.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.