* [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64
@ 2003-04-10 13:13 Eric Piel
2003-04-11 1:24 ` Stephane Eranian
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Eric Piel @ 2003-04-10 13:13 UTC (permalink / raw)
To: linux-ia64
[-- Attachment #1: Type: text/plain, Size: 1562 bytes --]
Hello,
Since kernel 2.5.60 the perfmon doesn't send SIGPROF to the designated
task. The problem can be solved by replacing perfmon.c by an older
version (eg: from a kernel 2.5.59). Upgrading to perfmon 1.4 doesn't
solve this bug.
My testcase is the program "realfeel4" from peter Chubb available on the
perfmon website (and attached to this e-mail).
On a kernel 2.5.6{0,4} :
# ./realfeel4
897.533 MHz
secondsPerTick=1.11417e-09
ticksPerSecond=897532585.408894
sample_period = 6282728
smallest = 18446744073709551615, largest = 0, nsamples = 0, sigma = 0,
sigmasqr = 0
While we should expect something like on a kernel 2.5.59:
# ./realfeel4
897.527 MHz
secondsPerTick=1.11417e-09
ticksPerSecond=897526816.648964
sample_period = 6282687
smallest = 4859, largest = 8216, nsamples = 1426, sigma = 7948200,
sigmasqr = 44510579922
Mean 5573.77, stddev 382.946
nsamples = 0 means it didn't receive any signal: that's bad :-)
It seems the reason of the bug is the new, indirect, way to deliver the
signals. Now perfmon relies on do_notify_resume_user() to call
pfm_ovfl_block_reset(). I think the bugs stands somewhere there because
do_notify_resume_user() isn't called so often (when I tested it, only
once the timer of realfeel4 was over). Unfortunatly I didn't understand
all the mechanism of the signals and in addition ia64_leave_kernel() is
coded in assembly, that doesn't help ;-).
I would be very greetful if someone could have a look at it or, at
least, could give me some clues about how the kernel decides when to
call do_notify_resume_user().
Eric
[-- Attachment #2: realfeel4.c --]
[-- Type: text/plain, Size: 8358 bytes --]
/*
* realfeel4.c -- produce histogram of interrupt to user-space latency.
*
* Based on notify-self.c from the pfmon2.0 package and realfeel.c from
* Mark Hahn http://brain.mkmaster.ca/~hahn/realfeel.c
*
* Portions Copyright (C) 2001-2002 Hewlett-Packard Co
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Released under GPL.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sched.h>
#include <string.h>
#include <perfmon/pfmlib.h>
typedef unsigned long stamp_t;
static inline stamp_t time_stamp(void)
{
stamp_t result;
__asm__ __volatile__("mov %0=ar.itc;;" : "=r"(result) :: "memory");
return result;
}
static pid_t me;
long sample_period;
#define NUM_PMDS PMU_MAX_PMDS
static pfarg_reg_t pd[NUM_PMDS];
static pfmlib_param_t evt;
static stamp_t smallest = ULONG_MAX;
static stamp_t largest;
static unsigned long nsamples;
static unsigned long sigma;
static unsigned long sigmasqr;
static void fatal_error(char *fmt,...) __attribute__((noreturn));
static void
fatal_error(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
int set_realtime_priority(void)
{
struct sched_param schp;
/*
* set the process to realtime privs
*/
memset(&schp, 0, sizeof(schp));
schp.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
perror("sched_setscheduler");
exit(1);
}
return 0;
}
double second() {
struct timeval tv;
gettimeofday(&tv,0);
return tv.tv_sec + 1e-6 * tv.tv_usec;
}
typedef unsigned long long u64;
void selectsleep(unsigned us) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = us;
select(0,0,0,0,&tv);
}
double secondsPerTick, ticksPerSecond;
void calibrate()
{
double sumx = 0;
double sumy = 0;
double sumxx = 0;
double sumxy = 0;
double slope;
// least squares linear regression of ticks onto real time
// as returned by gettimeofday.
const unsigned n = 30;
unsigned i;
for (i=0; i<n; i++) {
double breal,real,ticks;
stamp_t bticks;
breal = second();
bticks = time_stamp();
selectsleep((unsigned)(10000 + drand48() * 200000));
ticks = time_stamp() - bticks;
real = second() - breal;
sumx += real;
sumxx += real * real;
sumxy += real * ticks;
sumy += ticks;
}
slope = ((sumxy - (sumx*sumy) / n) /
(sumxx - (sumx*sumx) / n));
ticksPerSecond = slope;
secondsPerTick = 1.0 / slope;
printf("%3.3f MHz\n",ticksPerSecond*1e-6);
}
sig_atomic_t alarmed;
static void alrm(int signo)
{
alarmed = 1;
}
static void delay(unsigned seconds)
{
sigset_t mask;
sigemptyset(&mask);
signal(SIGALRM, alrm);
signal(SIGINT, alrm);
alarmed = 0;
alarm(seconds);
while (alarmed==0 && sigsuspend(&mask))
;
}
static void
process(stamp_t now)
{
static stamp_t last;
if (last) {
stamp_t diff = now - last;
if (now < last)
diff = ~(stamp_t)0 - last + now + 1;
nsamples++;
diff -= sample_period;
sigma += diff;
sigmasqr += diff * diff;
if (diff < smallest)
smallest = diff;
if (diff > largest)
largest = diff;
}
last = now;
/*
* And resume monitoring
*/
if (perfmonctl(me, PFM_RESTART,NULL, 0) == -1) {
perror("PFM_RESTART");
exit(1);
}
}
static void
overflow_handler(int n, struct pfm_siginfo *info, struct sigcontext *sc)
{
unsigned long mask = info->sy_pfm_ovfl[0];
stamp_t now = time_stamp();
/*
* Check to see if we received a spurious SIGPROF, i.e., one not
* generated by the perfmon subsystem.
*/
if (info->sy_code != PROF_OVFL) {
printf("Received spurious SIGPROF si_code=%d\n", info->sy_code);
return;
}
/*
* Each bit set in the overflow mask represents an overflowed counter.
*
* Here we check that the overflow was caused by our first counter.
*/
if ((mask & (1UL<< evt.pfp_pc[0].reg_num)) == 0) {
printf("Something is wrong, unexpected mask 0x%lx\n", mask);
exit(1);
}
process(now);
}
int
main(int argc, char **argv)
{
int ret;
pfarg_context_t ctx[1];
pfmlib_options_t pfmlib_options;
struct sigaction act;
me = getpid();
if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) {
perror("mlockall");
exit(1);
}
set_realtime_priority();
calibrate();
printf("secondsPerTick=%g\n", secondsPerTick);
printf("ticksPerSecond=%f\n", ticksPerSecond);
/*
* Initialize pfm library (required before we can use it)
*/
if (pfm_initialize() != PFMLIB_SUCCESS) {
printf("Can't initialize library\n");
exit(1);
}
/*
* Install the overflow handler (SIGPROF)
*/
memset(&act, 0, sizeof(act));
act.sa_handler = (sig_t)overflow_handler;
act.sa_flags = SA_NOMASK;
sigaction(SIGPROF, &act, 0);
/*
* pass options to library (optional)
*/
memset(&pfmlib_options, 0, sizeof(pfmlib_options));
pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
pfm_set_options(&pfmlib_options);
memset(pd, 0, sizeof(pd));
memset(ctx, 0, sizeof(ctx));
/*
* prepare parameters to library. we don't use any Itanium
* specific features here. so the pfp_model is NULL.
*/
memset(&evt, 0, sizeof(evt));
if (pfm_find_event("cpu_cycles", &evt.pfp_events[0].event) != PFMLIB_SUCCESS) {
fatal_error("Cannot find cpu_cycles event\n");
}
/*
* set the default privilege mode for all counters:
* PFM_PLM3 : user level
* PFM_PLM0 : kernel level
*/
evt.pfp_dfl_plm = PFM_PLM0|PFM_PLM3;
evt.pfp_flags = PFMLIB_PFP_SYSTEMWIDE;
/*
* how many counters we use
*/
evt.pfp_event_count = 1;
/*
* use the library to find the monitors to use
*/
if ((ret = pfm_dispatch_events(&evt)) != PFMLIB_SUCCESS) {
fatal_error("Cannot configure events: %s\n", pfm_strerror(ret));
}
/*
* For this example, we want to be notified on counter overflows.
*/
ctx[0].ctx_flags = PFM_FL_SYSTEM_WIDE;
ctx[0].ctx_notify_pid = me;
ctx[0].ctx_cpu_mask = 1;
/*
* now create the context for self monitoring/across system
*/
if (perfmonctl(me, PFM_CREATE_CONTEXT, ctx, 1) == -1 ) {
if (errno == ENOSYS) {
fatal_error("Your kernel does not have performance monitoring support!\n");
}
fatal_error("Can't create PFM context %s\n", strerror(errno));
}
/*
* Must be done before any PMD/PMD calls (unfreeze PMU). Initialize
* PMC/PMD to safe values. psr.up is cleared.
*/
if (perfmonctl(me, PFM_ENABLE, NULL, 0) == -1) {
fatal_error( "child: perfmonctl error PFM_ENABLE errno %d\n",errno);
}
/*
* We want to get notified when the counter used for our first
* event overflows
*/
evt.pfp_pc[0].reg_flags |= PFM_REGFL_OVFL_NOTIFY;
pd[0].reg_num = evt.pfp_pc[0].reg_num;
/*
* we arm the first counter, such that it will overflow
* after sample_period events have been observed -- around 7ms
*/
sample_period = 7 * ticksPerSecond / 1000;
printf("sample_period = %lu\n", sample_period);
pd[0].reg_value = (~0UL) - sample_period;
pd[0].reg_short_reset = (~0UL) - sample_period;
pd[0].reg_long_reset = (~0UL) - sample_period;
/*
* Now program the registers
*
* We don't use the save variable to indicate the number of elements passed to
* the kernel because, as we said earlier, pc may contain more elements than
* the number of events we specified, i.e., contains more than counting monitors.
*/
if (perfmonctl(me, PFM_WRITE_PMCS, evt.pfp_pc, evt.pfp_pc_count) == -1) {
fatal_error("child: perfmonctl error PFM_WRITE_PMCS errno %d: %s\n",errno, strerror(errno));
}
if (perfmonctl(me, PFM_WRITE_PMDS, pd, evt.pfp_event_count) == -1) {
fatal_error( "child: perfmonctl error PFM_WRITE_PMDS errno %d: %s\n",errno, strerror(errno));
}
/*
* Let's roll now
*/
perfmonctl(me, PFM_START, 0, 0);
delay(10);
perfmonctl(me, PFM_STOP, 0, 0);
/*
* let's stop this now
*/
if (perfmonctl(me, PFM_DESTROY_CONTEXT, NULL, 0) == -1) {
fatal_error( "child: perfmonctl error PFM_DESTROY errno %d\n",errno);
}
printf("smallest = %lu, largest = %lu, nsamples = %lu, sigma = %lu, sigmasqr = %lu\n",
smallest, largest, nsamples, sigma, sigmasqr);
if (nsamples) {
printf("Mean %g, stddev %g\n",
(double)sigma/(double)nsamples,
sqrt(((double)sigmasqr - (double)(sigma * sigma)/(double)nsamples)/(double)nsamples));
}
return 0;
}
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 2003-04-10 13:13 [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 Eric Piel @ 2003-04-11 1:24 ` Stephane Eranian 2003-04-11 14:33 ` Eric Piel 2003-04-16 21:50 ` Stephane Eranian 2 siblings, 0 replies; 4+ messages in thread From: Stephane Eranian @ 2003-04-11 1:24 UTC (permalink / raw) To: linux-ia64 [-- Attachment #1: Type: text/plain, Size: 367 bytes --] Eric, Yes, I realized that a while back and never got around to fixing it. Please try the (mostly untested) attached patch against 2.5.67 but it should apply to older versions as well. Let me know how it goes, especially on SMP. PS: there is a dedicated mailing-list for perfmon. Visit http://www.hpl.hp.com/research/linux/perfmon for details. -- -Stephane [-- Attachment #2: perfmon-2.5-030410.diff --] [-- Type: text/plain, Size: 1407 bytes --] diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet bk-official-extra/arch/ia64/kernel/perfmon.c bk-base/arch/ia64/kernel/perfmon.c --- bk-official-extra/arch/ia64/kernel/perfmon.c Thu Apr 10 14:01:35 2003 +++ bk-base/arch/ia64/kernel/perfmon.c Thu Apr 10 12:24:05 2003 @@ -1883,7 +1883,10 @@ DBprintk(("unblocking %d \n", task->pid)); up(sem); } else { + struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); task->thread.pfm_ovfl_block_reset = 1; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + set_bit(TIF_NOTIFY_RESUME, &info->flags); } #if 0 /* @@ -2733,6 +2736,7 @@ * again */ th->pfm_ovfl_block_reset = 0; + clear_thread_flag(TIF_NOTIFY_RESUME); /* * do some sanity checks first @@ -2907,8 +2911,9 @@ static unsigned long pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { - unsigned long mask; struct thread_struct *t; + struct thread_info *info; + unsigned long mask; unsigned long old_val; unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; int i; @@ -3053,6 +3058,8 @@ t->pfm_ovfl_block_reset = 1; /* will cause blocking */ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG; } + info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); + set_bit(TIF_NOTIFY_RESUME, &info->flags); /* * keep the PMU frozen until either pfm_restart() or ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 2003-04-10 13:13 [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 Eric Piel 2003-04-11 1:24 ` Stephane Eranian @ 2003-04-11 14:33 ` Eric Piel 2003-04-16 21:50 ` Stephane Eranian 2 siblings, 0 replies; 4+ messages in thread From: Eric Piel @ 2003-04-11 14:33 UTC (permalink / raw) To: linux-ia64 Stephane Eranian wrote: > Yes, I realized that a while back and never got around to fixing it. > > Please try the (mostly untested) attached patch against 2.5.67 but it > should apply to older versions as well. Thank you for the patch, testing on a 2.5.64 kernel (I don't have 2.5.67 yet :-) ) with and without preempt. Hardware : tiger (4x Itanium2) > Let me know how it goes, especially on SMP. For now I would say it doesn't work :-( I get the same results from realfeel4 than before. However it works better (in a point of view) than before because now pfm_ovfl_block_reset() is called and sends a SIGPROF. But this is done only at the very end of realfeel4, according to the logs I think it's when sending the SIGALRM. Eric > PS: there is a dedicated mailing-list for perfmon. Sorry, I hadn't noticed, I'm now cross-posting. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 2003-04-10 13:13 [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 Eric Piel 2003-04-11 1:24 ` Stephane Eranian 2003-04-11 14:33 ` Eric Piel @ 2003-04-16 21:50 ` Stephane Eranian 2 siblings, 0 replies; 4+ messages in thread From: Stephane Eranian @ 2003-04-16 21:50 UTC (permalink / raw) To: linux-ia64 [-- Attachment #1: Type: text/plain, Size: 623 bytes --] Eric, On Fri, Apr 11, 2003 at 04:33:33PM +0200, Eric Piel wrote: > > Let me know how it goes, especially on SMP. > For now I would say it doesn't work :-( I get the same results from > realfeel4 than before. Yes, it does not work. I found the source of the problem and it is pretty subtle especially in system-wide mode. The deferred notification does not work with kernel only threads which is likely what you have running in system-wide mode with a mostly idle system. The attached patch against 2.5.67 corrects the problem. Note that this patch also includes other updates. Let me know how it goes. -- -Stephane [-- Attachment #2: perfmon-2.5-030416 --] [-- Type: text/plain, Size: 12191 bytes --] diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet bk-official-extra/arch/ia64/kernel/perfmon.c bk-base/arch/ia64/kernel/perfmon.c --- bk-official-extra/arch/ia64/kernel/perfmon.c Thu Apr 10 14:01:35 2003 +++ bk-base/arch/ia64/kernel/perfmon.c Tue Apr 15 15:58:21 2003 @@ -225,8 +225,9 @@ unsigned int protected:1; /* allow access to creator of context only */ unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ unsigned int excl_idle:1; /* exclude idle task in system wide session */ + unsigned int unsecure:1; /* sp = 0 for non self-monitored task */ unsigned int trap_reason:2; /* reason for going into pfm_block_ovfl_reset() */ - unsigned int reserved:21; + unsigned int reserved:20; } pfm_context_flags_t; #define PFM_TRAP_REASON_NONE 0x0 /* default value */ @@ -279,6 +280,7 @@ #define ctx_fl_using_dbreg ctx_flags.using_dbreg #define ctx_fl_excl_idle ctx_flags.excl_idle #define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_unsecure ctx_flags.unsecure /* * global information about all sessions @@ -1077,10 +1079,15 @@ * and it must be a valid CPU */ cpu = ffz(~pfx->ctx_cpu_mask); +#ifdef CONFIG_SMP if (cpu_online(cpu) == 0) { +#else + if (cpu != 0) { +#endif DBprintk(("CPU%d is not online\n", cpu)); return -EINVAL; } + /* * check for pre-existing pinning, if conflicting reject */ @@ -1226,6 +1233,7 @@ ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; ctx->ctx_fl_frozen = 0; ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; @@ -1252,9 +1260,11 @@ DBprintk(("context=%p, pid=%d notify_task=%p\n", (void *)ctx, task->pid, ctx->ctx_notify_task)); - DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d\n", + DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d unsecure=%d\n", (void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, - ctx->ctx_fl_block, ctx->ctx_fl_system, ctx->ctx_fl_excl_idle)); + ctx->ctx_fl_block, ctx->ctx_fl_system, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_unsecure)); /* * when no notification is required, we can make this visible at the last moment @@ -1883,7 +1893,10 @@ DBprintk(("unblocking %d \n", task->pid)); up(sem); } else { + struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); task->thread.pfm_ovfl_block_reset = 1; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + set_bit(TIF_NOTIFY_RESUME, &info->flags); } #if 0 /* @@ -2052,7 +2065,7 @@ /* * reinforce secure monitoring: cannot toggle psr.up */ - ia64_psr(regs)->sp = 1; + if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1; return 0; } @@ -2733,12 +2746,13 @@ * again */ th->pfm_ovfl_block_reset = 0; + clear_thread_flag(TIF_NOTIFY_RESUME); /* * do some sanity checks first */ if (!ctx) { - printk(KERN_DEBUG "perfmon: [%d] has no PFM context\n", current->pid); + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); return; } /* @@ -2901,14 +2915,17 @@ /* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code + * Arguments: + * mode: 0=coming from PMU interrupt, 1=coming from ctxsw + * * Return: * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ static unsigned long -pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +pfm_overflow_handler(int mode, struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { - unsigned long mask; struct thread_struct *t; + unsigned long mask; unsigned long old_val; unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; int i; @@ -2999,10 +3016,10 @@ /* * check for sampling buffer * - * if present, record sample. We propagate notification ONLY when buffer - * becomes full. + * if present, record sample only when a 64-bit counter has overflowed. + * We propagate notification ONLY when buffer becomes full. */ - if(CTX_HAS_SMPL(ctx)) { + if(CTX_HAS_SMPL(ctx) && ovfl_pmds) { ret = pfm_record_sample(task, ctx, ovfl_pmds, regs); if (ret == 1) { /* @@ -3047,12 +3064,55 @@ * ctx_notify_task could already be NULL, checked in pfm_notify_user() */ if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_notify_task != task) { - t->pfm_ovfl_block_reset = 1; /* will cause blocking */ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCKSIG; } else { - t->pfm_ovfl_block_reset = 1; /* will cause blocking */ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG; } + /* + * we cannot block in system wide mode and we do not go + * through the PMU ctxsw code. Therefore we can generate + * the notification here. In system wide mode, the current + * task maybe different from the task controlling the session + * on this CPU, therefore owner can be different from current. + * + * In per-process mode, this function gets called from + * the interrupt handler or pfm_load_regs(). The mode argument + * tells where we are coming from. When coming from the interrupt + * handler, it is safe to notify (send signal) right here because + * we do not hold any runqueue locks needed by send_sig_info(). + * + * However when coming from ctxsw, we cannot send the signal here. + * It must be deferred until we are sure we do not hold any runqueue + * related locks. The current task maybe different from the owner + * only in UP mode. The deferral is implemented using the + * TIF_NOTIFY_RESUME mechanism. In this case, the pending work + * is checked when the task is about to leave the kernel (see + * entry.S). As of this version of perfmon, a kernel only + * task cannot be monitored in per-process mode. Therefore, + * when this function gets called from pfm_load_regs(), we know + * we have a user level task which will eventually either exit + * or leave the kernel, and thereby go through the checkpoint + * for TIF_*. + */ + if (ctx->ctx_fl_system || mode == 0) { + pfm_notify_user(ctx); + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + } else { + struct thread_info *info; + + /* + * given that TIF_NOTIFY_RESUME is not specific to + * perfmon, we need to have a second level check to + * verify the source of the notification. + */ + task->thread.pfm_ovfl_block_reset = 1; + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + info = ((struct thread_info *) ((char *) task + IA64_TASK_SIZE)); + set_bit(TIF_NOTIFY_RESUME, &info->flags); + } /* * keep the PMU frozen until either pfm_restart() or @@ -3060,7 +3120,10 @@ */ ctx->ctx_fl_frozen = 1; - DBprintk_ovfl(("return pmc0=0x%x must_block=%ld reason=%d\n", + DBprintk_ovfl(("current [%d] owner [%d] mode=%d return pmc0=0x%x must_block=%ld reason=%d\n", + current->pid, + PMU_OWNER() ? PMU_OWNER()->pid : -1, + mode, ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset, ctx->ctx_fl_trap_reason)); @@ -3115,7 +3178,7 @@ /* * assume PMC[0].fr = 1 at this point */ - pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs); + pmc0 = pfm_overflow_handler(0, task, ctx, pmc0, regs); /* * we can only update pmc0 when the overflow * is for the current context. In UP the current @@ -3455,7 +3518,7 @@ * Side effect on ctx_fl_frozen is possible. */ if (t->pmc[0] & ~0x1) { - t->pmc[0] = pfm_overflow_handler(task, ctx, t->pmc[0], NULL); + t->pmc[0] = pfm_overflow_handler(1, task, ctx, t->pmc[0], NULL); } /* @@ -3755,11 +3818,15 @@ preempt_disable(); /* - * make sure child cannot mess up the monitoring session + * for secure sessions, make sure child cannot mess up + * the monitoring session. */ - ia64_psr(regs)->sp = 1; - DBprintk(("enabling psr.sp for [%d]\n", task->pid)); - + if (ctx->ctx_fl_unsecure == 0) { + ia64_psr(regs)->sp = 1; + DBprintk(("enabling psr.sp for [%d]\n", task->pid)); + } else { + DBprintk(("psr.sp=%d [%d]\n", ia64_psr(regs)->sp, task->pid)); + } /* * if there was a virtual mapping for the sampling buffer diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet bk-official-extra/arch/ia64/kernel/perfmon_mckinley.h bk-base/arch/ia64/kernel/perfmon_mckinley.h --- bk-official-extra/arch/ia64/kernel/perfmon_mckinley.h Thu Apr 10 14:01:35 2003 +++ bk-base/arch/ia64/kernel/perfmon_mckinley.h Thu Apr 10 13:46:37 2003 @@ -25,8 +25,8 @@ /* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -143,10 +143,7 @@ case 8: val8 = *val; val13 = th->pmc[13]; val14 = th->pmc[14]; - *val |= 1UL << 2; /* bit 2 must always be 1 */ check_case1 = 1; - break; - case 9: *val |= 1UL << 2; /* bit 2 must always be 1 */ break; case 13: val8 = th->pmc[8]; val13 = *val; diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet bk-official-extra/include/asm-ia64/perfmon.h bk-base/include/asm-ia64/perfmon.h --- bk-official-extra/include/asm-ia64/perfmon.h Thu Apr 10 14:02:30 2003 +++ bk-base/include/asm-ia64/perfmon.h Tue Apr 15 15:59:04 2003 @@ -41,6 +41,7 @@ #define PFM_FL_NOTIFY_BLOCK 0x04 /* block task on user level notifications */ #define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ #define PFM_FL_EXCL_IDLE 0x20 /* exclude idle task from system wide session */ +#define PFM_FL_UNSECURE 0x40 /* allow unsecure monitoring for non self-monitoring task */ /* * PMC flags @@ -125,7 +126,7 @@ * Define the version numbers for both perfmon as a whole and the sampling buffer format. */ #define PFM_VERSION_MAJ 1U -#define PFM_VERSION_MIN 3U +#define PFM_VERSION_MIN 4U #define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) #define PFM_SMPL_VERSION_MAJ 1U diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet bk-official-extra/include/asm-ia64/processor.h bk-base/include/asm-ia64/processor.h --- bk-official-extra/include/asm-ia64/processor.h Thu Apr 10 14:02:30 2003 +++ bk-base/include/asm-ia64/processor.h Tue Apr 15 16:06:17 2003 @@ -291,7 +291,7 @@ #define start_thread(regs,new_ip,new_sp) do { \ set_fs(USER_DS); \ - regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP)) \ + regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL)) \ & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS)); \ regs->cr_iip = new_ip; \ regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2003-04-16 21:50 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-04-10 13:13 [Linux-ia64] [BUG] perfmon doesn't send SIGPROF in kernel 2.5.64 Eric Piel 2003-04-11 1:24 ` Stephane Eranian 2003-04-11 14:33 ` Eric Piel 2003-04-16 21:50 ` Stephane Eranian
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox