Skip to content

Commit

Permalink
[IA64] perfmon & PAL_HALT again
Browse files Browse the repository at this point in the history
The pmu_active test is based on the values of PSR.up. THIS IS THE PROBLEM as
it does not take into account the lazy restore logic which is as follow (simplified):

context switch out:
	save PMDs
	clear psr.up
	release ownership

context switch in:
	if (ctx->last_cpu == smp_processor_id() && ctx->cpu_activation == cpu_activation) {
		set psr.up
		return
	}
	restore PMD
	restore PMC
	ctx->last_cpu   = smp_processor_id();
	ctx->activation = ++cpu_activation;
	set psr.up

The key here is that on context switch out, we clear psr.up and on context switch in
we check if nobody else used the PMU on that processor since last time we came. In
that case, we assume the PMD/PMC are ours and we simply reactivate.

The Caliper problem is that between the moment we context switch out and the moment we
come back, nobody effectively used the PMU BUT the processor went idle. Normally this
would have no incidence but PAL_HALT does alter the PMU registers.  In default_idle(),
the test on psr.up is not strong enough to cover this case and we go into PAL which
trashed the PMU resgisters. When we come back we falsely assume that this is our state
yet it is corrupted. Very nasty indeed.

To avoid the problem it is necessary to forbid going to PAL_HALT as soon as perfmon
installs some valid state in the PMU registers. This happens with an application
attaches a context to a thread or CPU. It is not enough to check the psr/dcr bits.
Hence I propose the attached patch. It adds a callback in process.c to modify the
condition to enter PAL on idle. Basically, now it is conditional to pal_halt=1 AND
perfmon saying it is okay.

Signed-off-by: Tony Luck <tony.luck@intel.com>
  • Loading branch information
Stephane Eranian authored and Tony Luck committed May 3, 2005
1 parent 012914d commit 8df5a50
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
13 changes: 13 additions & 0 deletions arch/ia64/kernel/perfmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,8 @@ pfm_unregister_buffer_fmt(pfm_uuid_t uuid)
}
EXPORT_SYMBOL(pfm_unregister_buffer_fmt);

extern void update_pal_halt_status(int);

static int
pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
{
Expand Down Expand Up @@ -1311,6 +1313,11 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
is_syswide,
cpu));

/*
* disable default_idle() to go to PAL_HALT
*/
update_pal_halt_status(0);

UNLOCK_PFS(flags);

return 0;
Expand Down Expand Up @@ -1366,6 +1373,12 @@ pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu)
is_syswide,
cpu));

/*
* if possible, enable default_idle() to go into PAL_HALT
*/
if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0)
update_pal_halt_status(1);

UNLOCK_PFS(flags);

return 0;
Expand Down
14 changes: 11 additions & 3 deletions arch/ia64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,24 +173,32 @@ do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall
ia64_do_signal(oldset, scr, in_syscall);
}

static int pal_halt = 1;
static int pal_halt = 1;
static int can_do_pal_halt = 1;

static int __init nohalt_setup(char * str)
{
pal_halt = 0;
return 1;
}
__setup("nohalt", nohalt_setup);

int
update_pal_halt_status(int status)
{
can_do_pal_halt = pal_halt && status;
}

/*
* We use this if we don't have any better idle routine..
*/
void
default_idle (void)
{
unsigned long pmu_active = ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_PP | IA64_PSR_UP);
int can_do_pal;

while (!need_resched())
if (pal_halt && !pmu_active)
if (can_do_pal_halt)
safe_halt();
else
cpu_relax();
Expand Down

0 comments on commit 8df5a50

Please sign in to comment.