Skip to content

Commit

Permalink
[IA64] - Reduce overhead of FP exception logging messages
Browse files Browse the repository at this point in the history
Improve the scalability of the fpswa code that rate-limits
logging of messages.

There are 2 distinctly different problems in this code.

1) If prctl is used to disable logging, last_time is never
   updated. The result is that fpu_swa_count is zeroed out on
   EVERY fp fault. This causes a very very hot cache line.
   The fix reduces the wallclock time of a 1024p FP exception test
   from 28734 sec to 19 sec!!!

2) On VERY large systems, excessive messages are logged because
   multiple cpus can each reset or increment fpu_swa_count at
   about the same time. The result is that hundreds of messages
   are logged each second. The fixes reduces the logging rate
   to ~1 per second.

Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
  • Loading branch information
Jack Steiner authored and Tony Luck committed Dec 12, 2006
1 parent 8b9c106 commit 1cf24bd
Showing 1 changed file with 40 additions and 10 deletions.
50 changes: 40 additions & 10 deletions arch/ia64/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,15 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
return ret.status;
}

struct fpu_swa_msg {
unsigned long count;
unsigned long time;
};
static DEFINE_PER_CPU(struct fpu_swa_msg, cpulast);
DECLARE_PER_CPU(struct fpu_swa_msg, cpulast);
static struct fpu_swa_msg last __cacheline_aligned;


/*
* Handle floating-point assist faults and traps.
*/
Expand All @@ -316,23 +325,44 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
long exception, bundle[2];
unsigned long fault_ip;
struct siginfo siginfo;
static int fpu_swa_count = 0;
static unsigned long last_time;

fault_ip = regs->cr_iip;
if (!fp_fault && (ia64_psr(regs)->ri == 0))
fault_ip -= 16;
if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle)))
return -1;

if (jiffies - last_time > 5*HZ)
fpu_swa_count = 0;
if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
last_time = jiffies;
++fpu_swa_count;
printk(KERN_WARNING
"%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
unsigned long count, current_jiffies = jiffies;
struct fpu_swa_msg *cp = &__get_cpu_var(cpulast);

if (unlikely(current_jiffies > cp->time))
cp->count = 0;
if (unlikely(cp->count < 5)) {
cp->count++;
cp->time = current_jiffies + 5 * HZ;

/* minimize races by grabbing a copy of count BEFORE checking last.time. */
count = last.count;
barrier();

/*
* Lower 4 bits are used as a count. Upper bits are a sequence
* number that is updated when count is reset. The cmpxchg will
* fail is seqno has changed. This minimizes mutiple cpus
* reseting the count.
*/
if (current_jiffies > last.time)
(void) cmpxchg_acq(&last.count, count, 16 + (count & ~15));

/* used fetchadd to atomically update the count */
if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) {
last.time = current_jiffies + 5 * HZ;
printk(KERN_WARNING
"%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
}
}
}

exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
Expand Down

0 comments on commit 1cf24bd

Please sign in to comment.