From: Brian Sumner <bls@sgi.com>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] fpswa patch(es)
Date: Thu, 06 Dec 2001 21:44:19 +0000 [thread overview]
Message-ID: <marc-linux-ia64-105590698805632@msgid-missing> (raw)
The following patch is really 3 patches rolled into one.
I've found all 3 useful during application porting and debugging.
1. /proc/fpemu
A proc file that tools can monitor to identify when
applications are running that are requiring lots of
assists. Configured with CONFIG_PROC_FPEMU
% cat /proc/fpemu
CPU0f4859
CPU135141
Total\x1000000
2. Log total number of assists to messages
Configured with CONFIG_PRINT_FPEMU, causes messages like
Dec 6 10:04:41 nospam kernel: assist(1151): 1000000 floating-point assist faults
when a process exits having taken a nonzero number of assist faults
3. signal for successful assist
Allows the process to request a specified signal to be sent
when an assist succeeds. Currently the process receives
SIGFPE when the assist fails (and nothing when it succeeds).
The application requests this with, e.g.
prctl(PR_FPEMU_SIGNAL, SIGUSR1);
Configured with CONFIG_SIGNAL_FPEMU.
The following applies cleanly to 2.4.16 + 011128 diff.
Thanks,
Brian Sumner
---------- patch follows ----------------------------------------------------------
diff -urN linux-2.4.16/arch/ia64/config.in linux-2.4.16-fpemu/arch/ia64/config.in
--- linux-2.4.16/arch/ia64/config.in Tue Nov 27 12:10:18 2001
+++ linux-2.4.16-fpemu/arch/ia64/config.in Wed Nov 28 06:11:03 2001
@@ -96,6 +96,9 @@
bool 'SMP support' CONFIG_SMP
tristate 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT
bool 'Performance monitor support' CONFIG_PERFMON
+bool '/proc/fpemu support' CONFIG_PROC_FPEMU
+bool 'Log FPEMU activity per process' CONFIG_PRINT_FPEMU
+bool 'Generate signal for successful FPEMU invocation' CONFIG_SIGNAL_FPEMU
tristate '/proc/pal support' CONFIG_IA64_PALINFO
tristate '/proc/efi/vars support' CONFIG_EFI_VARS
diff -urN linux-2.4.16/arch/ia64/kernel/process.c linux-2.4.16-fpemu/arch/ia64/kernel/process.c
--- linux-2.4.16/arch/ia64/kernel/process.c Tue Nov 27 12:10:18 2001
+++ linux-2.4.16-fpemu/arch/ia64/kernel/process.c Wed Nov 28 06:11:03 2001
@@ -517,6 +517,11 @@
current->thread.flags &= ~IA64_THREAD_PM_VALID;
}
#endif
+#ifdef CONFIG_PRINT_FPEMU
+ if (current->thread.fpemu_count)
+ printk(KERN_WARNING "%s(%d): %lu floating-point assist faults\n",
+ current->comm, current->pid, current->thread.fpemu_count);
+#endif
}
unsigned long
diff -urN linux-2.4.16/arch/ia64/kernel/traps.c linux-2.4.16-fpemu/arch/ia64/kernel/traps.c
--- linux-2.4.16/arch/ia64/kernel/traps.c Fri Nov 9 16:26:17 2001
+++ linux-2.4.16-fpemu/arch/ia64/kernel/traps.c Wed Nov 28 06:56:56 2001
@@ -33,6 +33,7 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
+#include <linux/proc_fs.h>
#include <asm/hardirq.h>
#include <asm/ia32.h>
@@ -45,6 +46,50 @@
static fpswa_interface_t *fpswa_interface;
+#ifdef CONFIG_PROC_FPEMU
+static unsigned long fpemu_count[NR_CPUS];
+static struct proc_dir_entry *fpemu_dir;
+
+static int
+fpemu_proc_info(char *page)
+{
+ int i;
+ char *p = page;
+ unsigned long total = 0;
+
+ for (i = 0; i < smp_num_cpus; ++i) {
+ total += fpemu_count[i];
+ p += sprintf(p, "CPU%d=%lu\n", i, fpemu_count[i]);
+ }
+
+ p += sprintf(p, "Total=%lu\n", total);
+
+ return p - page;
+}
+
+static int
+fpemu_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = fpemu_proc_info(page);
+
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count) len = count;
+ if (len < 0) len = 0;
+
+ return len;
+}
+
+void __init
+trap_proc_init(void)
+{
+ if (ia64_boot_param->fpswa)
+ fpemu_dir = create_proc_read_entry("fpemu", 0, 0, fpemu_read_entry, NULL);
+}
+
+#endif
+
void __init
trap_init (void)
{
@@ -267,6 +312,7 @@
if (!fpswa_interface)
return -1;
+
memset(&fp_state, 0, sizeof(fp_state_t));
/*
@@ -311,8 +357,10 @@
long exception, bundle[2];
unsigned long fault_ip;
struct siginfo siginfo;
+#if !defined(CONFIG_PROC_FPEMU) && !defined(CONFIG_PRINT_FPEMU) && !defined(CONFIG_SIGNAL_FPEMU)
static int fpu_swa_count = 0;
static unsigned long last_time;
+#endif
fault_ip = regs->cr_iip;
if (!fp_fault && (ia64_psr(regs)->ri = 0))
@@ -320,6 +368,7 @@
if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle)))
return -1;
+#if !defined(CONFIG_PROC_FPEMU) && !defined(CONFIG_PRINT_FPEMU) && !defined(CONFIG_SIGNAL_FPEMU)
if (jiffies - last_time > 5*HZ)
fpu_swa_count = 0;
if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
@@ -327,9 +376,27 @@
printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
}
+#endif
+#ifdef CONFIG_PROC_FPEMU
+ ++fpemu_count[smp_processor_id()];
+#endif
+#ifdef CONFIG_PRINT_FPEMU
+ ++current->thread.fpemu_count;
+#endif
exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr,
®s->cr_ifs, regs);
+#ifdef CONFIG_SIGNAL_FPEMU
+ if (!exception && current->thread.fpemu_sig) {
+ siginfo.si_signo = current->thread.fpemu_sig;
+ siginfo.si_errno = 0;
+ siginfo.si_code = __SI_FAULT;
+ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ siginfo.si_isr = isr;
+ send_sig_info(current->thread.fpemu_sig, &siginfo, current);
+ }
+#endif
+
if (fp_fault) {
if (exception = 0) {
/* emulation was successful */
@@ -523,7 +590,11 @@
case 32: /* fp fault */
case 33: /* fp trap */
result = handle_fpu_swa((vector = 32) ? 1 : 0, regs, isr);
+#if !defined(CONFIG_SIGNAL_FPEMU)
if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
+#else
+ if (result < 0) {
+#endif
siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0;
siginfo.si_code = FPE_FLTINV;
diff -urN linux-2.4.16/include/asm-ia64/processor.h linux-2.4.16-fpemu/include/asm-ia64/processor.h
--- linux-2.4.16/include/asm-ia64/processor.h Tue Nov 27 12:10:19 2001
+++ linux-2.4.16-fpemu/include/asm-ia64/processor.h Wed Nov 28 06:11:03 2001
@@ -345,6 +345,15 @@
(int *) (addr)); \
})
+#ifdef CONFIG_SIGNAL_FPEMU
+#define SET_FPEMU_SIG(task,value) \
+({ \
+ (task)->thread.fpemu_sig = value; \
+ 0; \
+})
+#endif
+
+
struct siginfo;
struct thread_struct {
@@ -378,6 +387,18 @@
#else
# define INIT_THREAD_PM
#endif
+#ifdef CONFIG_PRINT_FPEMU
+ __u64 fpemu_count;
+# define INIT_FPEMU_COUNT 0,
+#else
+# define INIT_FPEMU_COUNT
+#endif
+#ifdef CONFIG_SIGNAL_FPEMU
+ __u64 fpemu_sig;
+# define INIT_FPEMU_SIG 0,
+#else
+# define INIT_FPEMU_SIG
+#endif
__u64 dbr[IA64_NUM_DBG_REGS];
__u64 ibr[IA64_NUM_DBG_REGS];
struct ia64_fpreg fph[96]; /* saved/loaded on demand */
@@ -391,6 +412,8 @@
0, /* siginfo */ \
INIT_THREAD_IA32 \
INIT_THREAD_PM \
+ INIT_FPEMU_COUNT \
+ INIT_FPEMU_SIG \
{0, }, /* dbr */ \
{0, }, /* ibr */ \
{{{{0}}}, } /* fph */ \
diff -urN linux-2.4.16/include/linux/prctl.h linux-2.4.16-fpemu/include/linux/prctl.h
--- linux-2.4.16/include/linux/prctl.h Tue Nov 27 12:10:20 2001
+++ linux-2.4.16-fpemu/include/linux/prctl.h Wed Nov 28 06:19:16 2001
@@ -26,4 +26,6 @@
# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */
# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */
+#define PR_FPEMU_SIGNAL 11 /* generate signal on successful FPEMU invocation */
+
#endif /* _LINUX_PRCTL_H */
diff -urN linux-2.4.16/init/main.c linux-2.4.16-fpemu/init/main.c
--- linux-2.4.16/init/main.c Tue Nov 27 12:10:20 2001
+++ linux-2.4.16-fpemu/init/main.c Wed Nov 28 06:11:03 2001
@@ -109,6 +109,9 @@
#ifdef CONFIG_PERFMON
extern void perfmon_init(void);
#endif
+#ifdef CONFIG_PROC_FPEMU
+extern void trap_proc_init(void);
+#endif
/*
* Boot command-line arguments
@@ -597,6 +600,9 @@
#ifdef CONFIG_PERFMON
perfmon_init();
#endif
+#ifdef CONFIG_PROC_FPEMU
+ trap_proc_init();
+#endif
mempages = num_physpages;
fork_init(mempages);
diff -urN linux-2.4.16/kernel/sys.c linux-2.4.16-fpemu/kernel/sys.c
--- linux-2.4.16/kernel/sys.c Tue Nov 27 12:10:20 2001
+++ linux-2.4.16-fpemu/kernel/sys.c Wed Nov 28 06:11:03 2001
@@ -1272,6 +1272,14 @@
}
current->keep_capabilities = arg2;
break;
+ case PR_FPEMU_SIGNAL:
+#ifdef SET_FPEMU_SIG
+ error = arg2 < 1 || arg2 >= _NSIG
+ ? -EINVAL : SET_FPEMU_SIG(current, arg2);
+#else
+ error = -EINVAL;
+#endif
+ break;
default:
error = -EINVAL;
break;
next reply other threads:[~2001-12-06 21:44 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-12-06 21:44 Brian Sumner [this message]
2001-12-14 22:35 ` [Linux-ia64] fpswa patch(es) David Mosberger
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=marc-linux-ia64-105590698805632@msgid-missing \
--to=bls@sgi.com \
--cc=linux-ia64@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.