diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9e68cd5..c897b8c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -915,6 +915,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. kexec loader will pass this option to capture kernel. See Documentation/kdump/kdump.txt for details. + emulated_files=1 [X86_32] + if CONFIG_CPU_PROC_EMULATED_FILES is set, + start runnung /proc/emulated_files at boot. + Normally, it is not run until expcilitly enabled + by 'echo 1 > /proc/emulated_files', since the + data collection is a very heavy task on CPU. + enable_mtrr_cleanup [X86] The kernel tries to adjust MTRR layout from continuous to discrete, to make X server driver able to add WB diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index a9f8463..7fa5c5d 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -400,12 +400,26 @@ config CPU_EMU_SSE2 config CPU_PROC_EMULATED_OPS bool "/proc/emulated_ops support" depends on X86_32 && CPU_EMU486 + default y ---help--- /proc/emulated_ops will show counts of emulated CMOV, NOPL, FCOMI/FCOMIP, FUCOMI/FUCOMIP and FCMOVcc instructions. If you are not sure, say N. +config CPU_PROC_EMULATED_FILES + bool "/proc/emulated_files support" + depends on CPU_PROC_EMULATED_OPS + default n + ---help--- + /proc/emulated_files will show statistics of what executable uses + emulated CMOV, SSE and SSE2 instructions. + Since this is heavy on CPU, by default data collecting is off; + explicitly enable it by "echo 1 > /proc/emulated_files" or + passing "emulated_files=1" kernel command line option. + + If you are not sure, say N. + config CPU_EMU486_DEBUG bool "Emulation debug" depends on X86_32 && CPU_EMU486 diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index c7c8534..ff1443b 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -45,6 +45,7 @@ CONFIG_X86_GENERIC=y # CONFIG_GEODE_NOPL is not set # CONFIG_CPU_EMU_FUCOMI is not set # CONFIG_CPU_PROC_EMULATED_OPS is not set +# CONFIG_CPU_PROC_EMULATED_FILES is not set CONFIG_HPET_TIMER=y CONFIG_SCHED_SMT=y CONFIG_PREEMPT_VOLUNTARY=y diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 3cc89fc..8160d8d 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -930,9 +930,198 @@ static int __init proc_emulated_ops_init(void) module_init(proc_emulated_ops_init); #endif /* CONFIG_CPU_PROC_EMULATED_OPS */ -#ifdef CONFIG_CPU_EMU_SSE2 +#ifdef CONFIG_CPU_PROC_EMULATED_FILES +/* + * /proc/emulated_files support. + * Dumps list of "cmov-ops sse-ops sse2-ops /path/of/lib-or-exec" since boot. + * Is a heavy process on slow CPUs. + */ +#define EMU_OPS_FILES_MAX 1024 +struct { + char buf[256]; + unsigned long cmov; + unsigned long sse; + unsigned long sse2; +} emulated_files_list[EMU_OPS_FILES_MAX] = { + { {'\0'}, 0,0,0 }, +}; +enum emulated_op_type { + OP_NONE = 0, + OP_CMOV, + OP_SSE, + OP_SSE2, +}; +static int emulated_files_running = 0; +/* cmdline: emulated_files=1 to start /proc/emulated_files on boot */ +core_param(emulated_files, emulated_files_running, int, 0644); + +static void emulated_files_clear(void) +{ + int i; + for (i=0; imm; + struct vm_area_struct *vma; + + /* + * Do not print if we are in atomic + * contexts (in exception stacks, etc.): + */ + if (preempt_count()) + return; + + down_read(&mm->mmap_sem); + vma = find_vma(mm, ip); + if (vma && vma->vm_file) { + struct file *f = vma->vm_file; + char *buf = (char *)__get_free_page(GFP_KERNEL); + if (buf) { + char *p; + int i; + char *ph; + int h; + + p = d_path(&f->f_path, buf, PAGE_SIZE); + if (IS_ERR(p)) + p = "?"; + + /* hash the path */ + for (h=0,ph=p; *ph!='\0'; ph++) + h += (int)*ph; + h &= 127; + i = h * (EMU_OPS_FILES_MAX / 128); + /* linear search in emulated_files_list[] for matching or vacant slot */ + for ( ;immap_sem); +} + +static int emulated_files_proc_show(struct seq_file *m, void *v) +{ + int i; + seq_printf(m, "%10s %10s %10s %s%s\n", "cmov","sse","sse2","filename", + (!emulated_files_running)?" (stopped; write \"1\" to start)":"" + ); + for (i=0;i /proc/emulated_files" + * stop by "echo -1 > /proc/emulated_files" + * clear by "echo 0 > /proc/emulated_files" + */ +static ssize_t emulated_files_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if (count) { + char c; + if (get_user(c, buf)) + return -EFAULT; + + switch(c) { + case '-': + emulated_files_running = 0; /* false */ + break; + case '0': + /*printk(KERN_NOTICE "clear /proc/emulated_files\n");*/ + emulated_files_clear(); + break; + case '1': + emulated_files_running = 1; /* true */ + break; + default: + return count; + } + } + return count; +} + +static const struct file_operations emulated_files_proc_fops = { + .open = emulated_files_proc_open, + .read = seq_read, + .write = emulated_files_proc_write, + .llseek = seq_lseek, + .release = single_release, +}; +static int __init proc_emulated_files_init(void) +{ + emulated_files_clear(); + proc_create("emulated_files", 0644, NULL, &emulated_files_proc_fops); + return 0; +} +module_init(proc_emulated_files_init); +#endif /* CONFIG_CPU_PROC_EMULATED_FILES */ + +#ifdef CONFIG_CPU_PROC_EMULATED_OPS +# ifdef CONFIG_CPU_PROC_EMULATED_FILES +#define EMU_COUNT_SSE(eip) emulated_files_byip(((unsigned long)(eip)), OP_SSE); emulated_ops_counter.sse++ +#define EMU_COUNT_SSE2(eip) emulated_files_byip(((unsigned long)(eip)), OP_SSE2);emulated_ops_counter.sse2++ +# else #define EMU_COUNT_SSE(eip) emulated_ops_counter.sse++ #define EMU_COUNT_SSE2(eip) emulated_ops_counter.sse2++ +# endif #else #define EMU_COUNT_SSE(eip) #define EMU_COUNT_SSE2(eip) @@ -1411,10 +1600,13 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) /* ncond is now true if the cond matches the opcode */ modrm = *(eip + 1); - eip += 2; /* skips all the opcodes */ #ifdef CONFIG_CPU_PROC_EMULATED_OPS emulated_ops_counter.cmov++; #endif +#ifdef CONFIG_CPU_PROC_EMULATED_FILES + emulated_files_byip((unsigned long)eip, OP_CMOV); +#endif + eip += 2; /* skips all the opcodes */ if (!ncond) { /* condition is not valid, skip the instruction and do nothing */