Hi,
I'm using Kevin's initial Cell support patch which is posted on May 29th.
It works well on my platform.
Now, I'm considering the Cell SPE support.
I think we have two issues for the Cell SPE support .
1. The trigger of pfm context switch
When we measure SPE events, we expects that the SPE events are
measured while the target SPE task uses SPEs actually
(In detail, the mesurement should be executed while the
spe_thread(context) is
binded to a SPE).
So, I think it is the solution that the pfm context switch is
triggered from
spu_bind_context()/spu_unbind_context() in SPUFS
(arch/powerpc/platform/cell/spufs/sched.c).
2. Changing the target SPE dynamically
The SPE which is binded to the target SPE task changes dynamically.
We have to change the target SPE of perfmon2 at each SPE context
switch.
In detail, the sub_unit field of pmX_event pmc should be changed
dynamically.
Here is my trial patch against the perfmon2 kernel patch which is released
on May 9th.
Please give me comments about it.
(I know that I added the architecture depended changes to the perfmon2
common
files. But I didn't know the proper files(way) to add this change.
Because this change relates to the pfm context switch.)
Thanks.
Takashi Yamamoto
-----------------------------------------------------------------------------------------------
Index: linux-2.6.21-20070425/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.21-20070425/arch/powerpc/platforms/cell/spufs/sched.c
(revision 6)
+++ linux-2.6.21-20070425/arch/powerpc/platforms/cell/spufs/sched.c
(working copy)
@@ -36,6 +36,7 @@
#include <linux/numa.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/perfmon.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
@@ -173,6 +174,9 @@
spu_switch_notify(spu, ctx);
spu_add_to_active_list(spu);
ctx->state = SPU_STATE_RUNNABLE;
+
+ if (test_tsk_thread_flag(current, TIF_PERFMON_SPE_CTXSW))
+ pfm_spe_ctxsw(NULL, current, spu->spe_id);
}
/**
@@ -182,9 +186,16 @@
*/
static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
{
+ struct task_struct *task;
+
pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
spu->pid, spu->number, spu->node);
+ task = find_task_by_pid(spu->pid);
+ if (task != NULL &&
+ test_tsk_thread_flag(task, TIF_PERFMON_SPE_CTXSW))
+ pfm_spe_ctxsw(task, NULL, spu->spe_id);
+
spu_remove_from_active_list(spu);
spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
Index: linux-2.6.21-20070425/include/asm-powerpc/thread_info.h
===================================================================
--- linux-2.6.21-20070425/include/asm-powerpc/thread_info.h (revision
8)
+++ linux-2.6.21-20070425/include/asm-powerpc/thread_info.h (working
copy)
@@ -126,6 +126,8 @@
#define TIF_RUNLATCH 17 /* Is the runlatch enabled? */
#define TIF_ABI_PENDING 18 /* 32/64 bit switch needed
*/
+#define TIF_PERFMON_SPE_CTXSW 19 /* perfmon needs ctxsw calls */
+
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -135,6 +137,7 @@
#define _TIF_32BIT (1<<TIF_32BIT)
#define _TIF_PERFMON_WORK (1<<TIF_PERFMON_WORK)
#define _TIF_PERFMON_CTXSW (1<<TIF_PERFMON_CTXSW)
+#define _TIF_PERFMON_SPE_CTXSW (1<<TIF_PERFMON_SPE_CTXSW)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
Index: linux-2.6.21-20070425/include/linux/perfmon.h
===================================================================
--- linux-2.6.21-20070425/include/linux/perfmon.h (revision 6)
+++ linux-2.6.21-20070425/include/linux/perfmon.h (working copy)
@@ -726,6 +726,7 @@
void __pfm_exit_thread(struct task_struct *task);
void __pfm_copy_thread(struct task_struct *task);
void __pfm_ctxsw(struct task_struct *prev, struct task_struct *next);
+void __pfm_spe_ctxsw(struct task_struct *p, struct task_struct *n, u64
spe_id);
void __pfm_handle_work(struct pt_regs *regs);
void __pfm_handle_switch_timeout(void);
void __pfm_init_percpu (void *dummy);
@@ -751,6 +752,7 @@
task->pfm_context = NULL;
clear_tsk_thread_flag(task, TIF_PERFMON_CTXSW);
clear_tsk_thread_flag(task, TIF_PERFMON_WORK);
+ clear_tsk_thread_flag(task, TIF_PERFMON_SPE_CTXSW);
}
static inline void pfm_ctxsw(struct task_struct *p, struct task_struct
*n)
@@ -758,6 +760,12 @@
__pfm_ctxsw(p, n);
}
+static inline void pfm_spe_ctxsw(struct task_struct *p, struct
task_struct *n,
+ u64 spe_id)
+{
+ __pfm_spe_ctxsw(p, n, spe_id);
+}
+
static inline void pfm_handle_switch_timeout(void)
{
unsigned long info;
Index: linux-2.6.21-20070425/perfmon/perfmon.c
===================================================================
--- linux-2.6.21-20070425/perfmon/perfmon.c (revision 8)
+++ linux-2.6.21-20070425/perfmon/perfmon.c (working copy)
@@ -1208,7 +1208,32 @@
return 0;
}
+
/*
+ * This function returns whether spe ctxsw should be used for
+ * the pfm context switch.
+ *
+ * The following implementation is very tentative.
+ * If a pfm target event which is described in pmcs[8] -
pmc[16](pmX_event reg)
+ * is included in SPE signal group, this function returns 1.
+ */
+static int is_ctxsw_type_spe(struct pfm_event_set *set)
+{
+ int i;
+ u64 signal_group;
+
+ for (i = 8; i < 16; i++) {
+ signal_group = set->pmcs[i] & 0x00000000FFFFFFFF;
+ signal_group = signal_group / 100;
+ if ((41 <= signal_group && signal_group <= 43) ||
+ (51 <= signal_group && signal_group <= 56)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
* function used to attach a context to either a CPU or a thread.
* In per-thread mode, and when not self-monitoring, the thread must be
* stopped. In system-wide mode, the cpu specified in the
pfarg_load.load_tgt
@@ -1362,8 +1387,13 @@
pfm_modview_end(set);
if (!ctx->flags.system) {
- set_tsk_thread_flag(task, TIF_PERFMON_CTXSW);
- PFM_DBG("[%d] set TIF", task->pid);
+ if (is_ctxsw_type_spe(set)) {
+ set_tsk_thread_flag(task, TIF_PERFMON_SPE_CTXSW);
+ PFM_DBG("[%d] set SPE TIF", task->pid);
+ } else {
+ set_tsk_thread_flag(task, TIF_PERFMON_CTXSW);
+ PFM_DBG("[%d] set TIF", task->pid);
+ }
}
ctx->flags.work_type = PFM_WORK_NONE;
@@ -1462,7 +1492,11 @@
if (task) {
task->pfm_context = NULL;
ctx->task = NULL;
- clear_tsk_thread_flag(task, TIF_PERFMON_CTXSW);
+ if (is_ctxsw_type_spe(set)) {
+ clear_tsk_thread_flag(task,
TIF_PERFMON_SPE_CTXSW);
+ } else {
+ clear_tsk_thread_flag(task, TIF_PERFMON_CTXSW);
+ }
}
*can_release = 1;
Index: linux-2.6.21-20070425/perfmon/perfmon_ctxsw.c
===================================================================
--- linux-2.6.21-20070425/perfmon/perfmon_ctxsw.c (revision 6)
+++ linux-2.6.21-20070425/perfmon/perfmon_ctxsw.c (working copy)
@@ -339,3 +339,57 @@
__get_cpu_var(pfm_stats).ctxsw_count++;
__get_cpu_var(pfm_stats).ctxsw_ns += sched_clock() - now;
}
+
+static void pfm_prepare_ctxswin_thread(struct pfm_context *ctx, u64
spe_id)
+{
+ struct pfm_event_set *set;
+ int i;
+ u64 signal_group;
+
+ set = ctx->active_set;
+ for (i = 8; i < 16; i++) {
+ signal_group = set->pmcs[i] & 0x00000000FFFFFFFF;
+ signal_group = signal_group / 100;
+
+ /*
+ * If the target event is included SPE signal group,
+ * The sub_unit field in pmX_event pmc is changed to the
+ * specified spe_id.
+ */
+ if ((41 <= signal_group && signal_group <= 43) ||
+ (51 <= signal_group && signal_group <= 56)) {
+ set->pmcs[i] = (set->pmcs[i] & 0xFFFF0000FFFFFFFF)
+ | (spe_id << 32);
+ PFM_INFO("pmcs[%d] : 0x%lx", i, set->pmcs[i]);
+ }
+ }
+}
+
+void __pfm_spe_ctxsw(struct task_struct *prev, struct task_struct *next,
u64 spe_id)
+{
+ struct pfm_context *ctxp, *ctxn;
+ u64 now;
+
+ now = sched_clock();
+
+ if (prev) {
+ ctxp = prev->pfm_context;
+ PFM_INFO("ctxswout spe_id:0x%lx", spe_id);
+ if (ctxp)
+ __pfm_ctxswout_thread(prev, ctxp, now);
+
+ } else if (next) {
+ ctxn = next->pfm_context;
+ PFM_INFO("ctxswin spe_id:0x%lx", spe_id);
+ if (ctxn) {
+ pfm_prepare_ctxswin_thread(ctxn, spe_id);
+ __pfm_ctxswin_thread(next, ctxn, now);
+ }
+
+ } else {
+ PFM_ERR("perv and next are NULL");
+ }
+ __get_cpu_var(pfm_stats).ctxsw_count++;
+ __get_cpu_var(pfm_stats).ctxsw_ns += sched_clock() - now;
+}
+
_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/