Immediate Values
Subsystems (4)
cover Immediate Values
Hi Andrew,
Here are the updated immediate values, following recent discussions.
It depends on the text edit lock patches.
It applies to 2.6.23-rc4-mm1, in the following order:
immediate-values-architecture-independent-code.patch immediate-values-kconfig-embedded.patch immediate-values-move-kprobes-i386-restore-interrupt-to-kdebug-h.patch immediate-values-i386-optimization.patch immediate-values-powerpc-optimization.patch immediate-values-documentation.patch profiling-use-immediate-values.patch
Mathieu
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 1/7 Immediate Values - Architecture Independent Code
Immediate values are used as read mostly variables that are rarely updated. They use code patching to modify the values inscribed in the instruction stream. It provides a way to save precious cache lines that would otherwise have to be used by these variables.
There is a generic _immediate_read() version, which uses standard global variables, and optimized per architecture immediate_read() implementations, which use a load immediate to remove a data cache hit. When the immediate values functionnality is disabled in the kernel, it falls back to global variables.
It adds a new rodata section "__immediate" to place the pointers to the enable value. Immediate values activation functions sits in kernel/immediate.c.
Immediate values refer to the memory address of a previously declared integer. This integer holds the information about the state of the immediate values associated, and must be accessed through the API found in linux/immediate.h.
At module load time, each immediate value is checked to see if it must be enabled. It would be the case if the variable they refer to is exported from another module and already enabled.
In the early stages of start_kernel(), the immediate values are updated to reflect the state of the variable they refer to.
* Why should this be merged *
It improves performances on heavy memory I/O workloads.
An interesting result shows the potential this infrastructure has by showing the slowdown a simple system call such as getppid() suffers when it is used under heavy user-space cache trashing:
Random walk L1 and L2 trashing surrounding a getppid() call:
(note: in this test, do_syscal_trace was taken at each system call, see Documentation/immediate.txt in these patches for details)
- No memory pressure : getppid() takes 1573 cycles
- With memory pressure : getppid() takes 15589 cycles
We therefore have a slowdown of 10 times just to get the kernel variables from memory. Another test on the same architecture (Intel P4) measured the memory latency to be 559 cycles. Therefore, each cache line removed from the hot path would improve the syscall time of 3.5% in these conditions.
Changelog:
- section __immediate is already SHF_ALLOC
- Because of the wonders of ELF, section 0 has sh_addr and sh_size 0. So the if (immediateindex) is unnecessary here.
- Remove module_mutex usage: depend on functions implemented in module.c for that.
- Does not update tainted module's immediate values.
- remove immediate_*_t types, add DECLARE_IMMEDIATE() and DEFINE_IMMEDIATE().
- immediate_read(&var) becomes immediate_read(var) because of this.
- Adding a new EXPORT_IMMEDIATE_SYMBOL(_GPL).
- remove immediate_if(). Should use if (unlikely(immediate_read(var))) instead.
- Wait until we have gcc support before we add the immediate_if macro, since its form may have to change.
- Document immediate_set_early(). This design is chosen over immediate_init() because:
- We can mark the function __init so it is freed after boot.
- Module code patching can also be done by the "normal" function. This is preferred, even if it can be slightly slower, because update performance does not matter.
- immediate_init() could confuse users because we can actually "initialize" an immediate value to a certain value, which will be used as initial value. e.g.:
static DEFINE_IMMEDIATE(int, var) = 10;
--- include/asm-generic/vmlinux.lds.h | 7 ++ include/linux/immediate.h | 133 ++++++++++++++++++++++++++++++++++++++ include/linux/module.h | 17 ++++ init/main.c | 2 kernel/Makefile | 1 kernel/immediate.c | 92 ++++++++++++++++++++++++++ kernel/module.c | 49 ++++++++++++++ 7 files changed, 301 insertions(+)
include/linux/immediate.h new file +133 -0
@@ -0,0 +1,133 @@ +#ifndef _LINUX_IMMEDIATE_H +#define _LINUX_IMMEDIATE_H + +/* +* Immediate values, can be updated at runtime and save cache lines. +* +* (C) Copyright 2007 Mathieu Desnoyers <[email protected]> +* +* This file is released under the GPLv2. +* See the file COPYING for more details. +*/ + +#ifdef CONFIG_IMMEDIATE + +#include <asm/immediate.h> + +/** +* immediate_set - set immediate variable (with locking) +* @name: immediate value name +* @i: required value +* +* Sets the value of @name, taking the module_mutex if required by +* the architecture. +*/ +#define immediate_set (name, i) \ + do { \ + name##__immediate = (i); \ + core_immediate_update(); \ + module_immediate_update(); \ + } while (0) + + +/** +* _immediate_set - set immediate variable (without locking) +* @name: immediate value name +* @i: required value +* +* Sets the value of @name. Must be called with module_mutex held. +*/ +#define _immediate_set (name, i) \ + do { \ + name##__immediate = (i); \ + core_immediate_update(); \ + _module_immediate_update(); \ + } while (0) + +/** +* immediate_set_early - set immediate variable at early boot +* @name: immediate value name +* @i: required value +* +* Sets the value of @name. Should be used for updates at early boot, when only +* one CPU is active and interrupts are disabled. +*/ +#define immediate_set_early (name, i) \ + do { \ + name##__immediate = (i); \ + immediate_update_early(); \ + } while (0) + +/* +* Internal update functions. +*/ +extern void core_immediate_update (void ); +extern void immediate_update_range (const struct __immediate *begin, +const struct __immediate *end); +extern void immediate_update_early (void ); + +#else + +/* +* Generic immediate values: a simple, standard, memory load. +*/ + +/** +* immediate_read - read immediate variable +* @name: immediate value name +* +* Reads the value of @name. +*/ +#define immediate_read (name) _immediate_read(name) + +/** +* immediate_set - set immediate variable (with locking) +* @name: immediate value name +* @i: required value +* +* Sets the value of @name, taking the module_mutex if required by +* the architecture. +*/ +#define immediate_set (name, i) (name##__immediate = (i)) + +/** +* _immediate_set - set immediate variable (without locking) +* @name: immediate value name +* @i: required value +* +* Sets the value of @name. Must be called with module_mutex held. +*/ +#define _immediate_set (name, i) immediate_set(name, i) + +/** +* immediate_set_early - set immediate variable at early boot +* @name: immediate value name +* @i: required value +* +* Sets the value of @name. Should be used for early boot updates. +*/ +#define immediate_set_early (name, i) immediate_set(name, i) + +/* +* Internal update functions. +*/ +static inline void immediate_update_early (void ) +{ } +#endif + +#define DECLARE_IMMEDIATE (type, name) extern __typeof__(type) name##__immediate +#define DEFINE_IMMEDIATE (type, name) __typeof__(type) name##__immediate + +#define EXPORT_IMMEDIATE_SYMBOL (name) EXPORT_SYMBOL(name##__immediate) +#define EXPORT_IMMEDIATE_SYMBOL_GPL (name) EXPORT_SYMBOL_GPL(name##__immediate) + +/** +* _immediate_read - Read immediate value with standard memory load. +* @name: immediate value name +* +* Force a data read of the immediate value instead of the immediate value +* based mechanism. Useful for __init and __exit section data read. +*/ +#define _immediate_read (name) (name##__immediate) + +#endif
include/asm-generic/vmlinux.lds.h +7 -0
@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \/* Kernel symbol table: strings */ \ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ *(__ksymtab_strings) \
include/linux/module.h +17 -0
@@ -15,6 +15,7 @@#include <linux/stringify.h> #include <linux/kobject.h> #include <linux/moduleparam.h> +#include <linux/immediate.h> #include <asm/local.h> #include <asm/module.h>
@@ -370,6 +371,11 @@ struct module/* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; + +#ifdef CONFIG_IMMEDIATE +const struct __immediate *immediate; +unsigned int num_immediate; +#endif };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}
@@ -473,6 +479,9 @@ int unregister_module_notifier(struct noextern void print_modules (void ); +extern void _module_immediate_update (void ); +extern void module_immediate_update (void ); +#else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL (sym)#define EXPORT_SYMBOL_GPL (sym)
@@ -572,6 +581,14 @@ static inline void print_modules(void) { } +static inline void _module_immediate_update (void ) +{ +} + +static inline void module_immediate_update (void ) +{ +} +#endif /* CONFIG_MODULES */ struct device_driver ;
kernel/module.c +49 -0
82 lines not on this page · raw message
kernel/immediate.c new file +92 -0
92 lines not on this page · raw message
init/main.c +2 -0
@@ -56,6 +56,7 @@#include <linux/pid_namespace.h> #include <linux/device.h> #include <linux/kthread.h> +#include <linux/immediate.h> #include <asm/io.h> #include <asm/bugs.h>
@@ -525,6 +526,7 @@ asmlinkage void __init start_kernel(voidunwind_init ();lockdep_init ();container_init_early (); +immediate_update_early ();local_irq_disable ();early_boot_irqs_off ();
kernel/Makefile +1 -0
@@ -61,6 +61,7 @@ obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o +obj-$(CONFIG_IMMEDIATE) += immediate.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================
include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \
Why do you need an output section for that? IOW: will this work too?
.data : ... {
...
VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \
...
}
Quoted 21 lines
Index:
linux-2.6-lttng/kernel/module.c
===================================================================kernel/module.c +2
-0@@ -33,6 +33,7 @@#include <linux/cpu.h> #include <linux/moduleparam.h> #include <linux/errno.h> +#include <linux/immediate.h> #include <linux/err.h> #include <linux/vermagic.h> #include <linux/notifier.h> @@ -1717,6 +1718,7 @@ static struct module *load_module(void _unsigned int unusedcrcindex;unsigned int unusedgplindex;unsigned int unusedgplcrcindex; +unsigned int immediateindex;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */
kernel/module.c static struct module *load_module(void _ · line 1818
Quoted 4 lines
kernel/module.c +1
-0@@ -1813,6 +1815,7 @@ static struct module *load_module(void _#ifdef ARCH_UNWIND_SECTION_NAME unwindex =find_sec (hdr, sechdrs, secstrings,ARCH_UNWIND_SECTION_NAME );#endif + immediateindex =find_sec (hdr, sechdrs, secstrings,"__immediate" );
Do you need to frame immediateindex by #ifdef CONFIG_IMMEDIATE / #endif? --
vda
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}
This last one could cause alignment problems. We either have to use the proper ALIGN() before the section, or let AT(ADDR(__immediate) - LOAD_OFFSET) take care of it. I prefer the latter.
Quoted 21 lines
Quoted 21 lines
Index:
linux-2.6-lttng/kernel/module.c
===================================================================kernel/module.c +2
-0@@ -33,6 +33,7 @@#include <linux/cpu.h> #include <linux/moduleparam.h> #include <linux/errno.h> +#include <linux/immediate.h> #include <linux/err.h> #include <linux/vermagic.h> #include <linux/notifier.h> @@ -1717,6 +1718,7 @@ static struct module *load_module(void _unsigned int unusedcrcindex;unsigned int unusedgplindex;unsigned int unusedgplcrcindex; +unsigned int immediateindex;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */
Quoted 8 lines
kernel/module.c static struct module *load_module(void _ · line 1818
Quoted 5 lines
kernel/module.c +1
-0@@ -1813,6 +1815,7 @@ static struct module *load_module(void _#ifdef ARCH_UNWIND_SECTION_NAME unwindex =find_sec (hdr, sechdrs, secstrings,ARCH_UNWIND_SECTION_NAME );#endif + immediateindex =find_sec (hdr, sechdrs, secstrings,"__immediate" );Do you need to frame immediateindex by #ifdef
CONFIG_IMMEDIATE/ #endif?
I could, but I have been told to leave the immediateindex there even though immediate values are configured out. I guess visual hideousness is the main argument there.
Mathieu
Quoted 2 lines
--
vda
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}
Quoted 3 lines
This last one could cause alignment problems. We either have to use the proper
ALIGN()before the section, or letAT(ADDR(__immediate) - LOAD_OFFSET)take care of it. I prefer the latter.
This adds yet another output section in vmlinux, and there is
no tools which need that. We already have 30+ sections there while we need ~20.
I am trying to fix the mess. Please don't add to it.
Re alignment: (1) do you really realy REALLY need it? Last I checked, i386 was handling unaligned accesses just fine; and
(2) this works:
. = ALIGN(4)
VMLINUX_SYMBOL(__start___immediate) = .; \
*(__immediate) \
VMLINUX_SYMBOL(__stop___immediate) = .; \
--
vda
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 47 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}Quoted 3 lines
This last one could cause alignment problems. We either have to use the proper
ALIGN()before the section, or letAT(ADDR(__immediate) - LOAD_OFFSET)take care of it. I prefer the latter.This adds yet another output section in vmlinux, and there is
no tools which need that. We already have 30+ sections there while we need ~20.I am trying to fix the mess. Please don't add to it.
Re alignment: (1) do you really realy REALLY need it? Last I checked, i386 was handling unaligned accesses just fine; and
(2) this works:. = ALIGN(4)
Review
Quoted 3 lines
(quoted diff) +0
-0VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \
Alignment: I need the __start___immediate and __stop___immediate values to be at the same alignment as the *(__immediate) content, or else we end up thinking that padding is data.
. = ALIGN(4) works fine as long as the structure within the section is not bigger or equal to 32 bytes: gcc has the habit to align 32 bytes structure on 32 bytes multiples. The safest way I found to do it is to declare the section as I do: it will cause no breakage if anybody append data to the structure.
Mathieu
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 52 lines · Mathieu Desnoyers
Quoted 47 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}Quoted 3 lines
This last one could cause alignment problems. We either have to use the proper
ALIGN()before the section, or letAT(ADDR(__immediate) - LOAD_OFFSET)take care of it. I prefer the latter.This adds yet another output section in vmlinux, and there is
no tools which need that. We already have 30+ sections there while we need ~20.I am trying to fix the mess. Please don't add to it.
Re alignment: (1) do you really realy REALLY need it? Last I checked, i386 was handling unaligned accesses just fine; and
(2) this works:. = ALIGN(4)Review
Quoted 3 lines
(quoted diff) +0
-0VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \
Quoted 7 lines
Alignment: I need the
__start___immediateand__stop___immediatevalues to be at the same alignment as the *(__immediate) content, or else we end up thinking that padding is data.. = ALIGN(4) works fine as long as the structure within the section is not bigger or equal to 32 bytes: gcc has the habit to align 32 bytes structure on 32 bytes multiples. The safest way I found to do it is to
Yes, I'm painfully aware of that. gcc is too damn happy to align stuff.
Quoted 2 lines
declare the section as I do: it will cause no breakage if anybody append data to the structure.
You can actively fight gcc's sadistic alignment tendencies instead:
struct __immediate {
long var; /* Identifier variable of the immediate value */
long immediate; /*
* Pointer to the memory location that holds
* the immediate value within the load immediate
* instruction.
*/
long size; /* Type size. */
} __attribute__ ((aligned(sizeof(long)))); <================= HERE
Kernel is already using this technique a lot. Try
grep -r '^\} *__attribute__ *.*aligned' .
--
vda
Re: [patch 1/7] Immediate Values - Architecture Independent Code
In reply to Mathieu DesnoyersQuoted 56 lines · Mathieu Desnoyers
Quoted 47 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}Quoted 3 lines
This last one could cause alignment problems. We either have to use the proper
ALIGN()before the section, or letAT(ADDR(__immediate) - LOAD_OFFSET)take care of it. I prefer the latter.This adds yet another output section in vmlinux, and there is
no tools which need that. We already have 30+ sections there while we need ~20.I am trying to fix the mess. Please don't add to it.
Re alignment: (1) do you really realy REALLY need it? Last I checked, i386 was handling unaligned accesses just fine; and
(2) this works:. = ALIGN(4)Review
Quoted 3 lines
(quoted diff) +0
-0VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \Alignment: I need the
__start___immediateand__stop___immediatevalues to be at the same alignment as the *(__immediate) content, or else we end up thinking that padding is data.
Quoted 5 lines
. = ALIGN(4) works fine as long as the structure within the section is not bigger or equal to 32 bytes: gcc has the habit to align 32 bytes structure on 32 bytes multiples. The safest way I found to do it is to declare the section as I do: it will cause no breakage if anybody append data to the structure.
If your structure will be padded by gcc, then this:
+#define immediate_read(name) \
+ ({ \
+ __typeof__(name##__immediate) value; \
+ switch (sizeof(value)) { \
+ case 1: \
+ asm ( ".section __immediate, \"a\", @progbits;\n\t" \
+ ".long %1, (0f)+1, 1;\n\t" \
+ ".previous;\n\t" \
+ "0:\n\t" \
+ "mov %2,%0;\n\t" \
+ : "=r" (value) \
+ : "m" (name##__immediate), \
+ "i" (0)); \
+ break; \will produce wrongly-sized "struct __immediate" (truncated one), since gcc has no idea that you are building struct __immediate there, and here:
+void immediate_update_range(const struct __immediate *begin,
+ const struct __immediate *end)
+{
+ const struct __immediate *iter;
+ int ret;
+
+ for (iter = begin; iter < end; iter++) {
+ mutex_lock(&immediate_mutex); + kernel_text_lock(); + ret = arch_immediate_update(iter); + kernel_text_unlock(); + if (ret) + printk(KERN_WARNING "Invalid immediate value. " + "Variable at %p, " + "instruction at %p, size %lu\n", + (void*)iter->immediate, + (void*)iter->var, iter->size);
+ mutex_unlock(&immediate_mutex);
+ }
+}
iter++ will go off rails.
--
vda
Re: [patch 1/7] Immediate Values - Architecture Independent Code
Quoted 105 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 56 lines · Mathieu Desnoyers
Quoted 47 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 5 lines · Mathieu Desnoyers
Index:
linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h line 131
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0@@ -122,6 +122,13 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ +/* Immediate values: pointers */ \ + __immediate : AT(ADDR(__immediate) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___immediate) = .; \ + *(__immediate ) \ + VMLINUX_SYMBOL(__stop___immediate) = .; \ + } \ + \Why do you need an output section for that? IOW: will this work too?
Quoted 9 lines
.data : ... {
...VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \...
}Quoted 3 lines
This last one could cause alignment problems. We either have to use the proper
ALIGN()before the section, or letAT(ADDR(__immediate) - LOAD_OFFSET)take care of it. I prefer the latter.This adds yet another output section in vmlinux, and there is
no tools which need that. We already have 30+ sections there while we need ~20.I am trying to fix the mess. Please don't add to it.
Re alignment: (1) do you really realy REALLY need it? Last I checked, i386 was handling unaligned accesses just fine; and
(2) this works:. = ALIGN(4)Review
Quoted 3 lines
(quoted diff) +0
-0VMLINUX_SYMBOL(__start___immediate) = .; \ *(__immediate) \ VMLINUX_SYMBOL(__stop___immediate) = .; \Alignment: I need the
__start___immediateand__stop___immediatevalues to be at the same alignment as the *(__immediate) content, or else we end up thinking that padding is data.Quoted 5 lines
. = ALIGN(4) works fine as long as the structure within the section is not bigger or equal to 32 bytes: gcc has the habit to align 32 bytes structure on 32 bytes multiples. The safest way I found to do it is to declare the section as I do: it will cause no breakage if anybody append data to the structure.
If your structure will be padded by gcc, then this:
(quoted diff) +14
-0+#define immediate_read(name) \ + ({ \ + __typeof__(name##__immediate) value; \ + switch (sizeof(value)) { \ + case 1: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+1, 1;\n\t" \ + ".previous;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \will produce wrongly-sized "struct
__immediate" (truncated one), since gcc has no idea that you are building struct__immediatethere, and here:kernel/immediate.c new file +20
-0+void immediate_update_range (const struct __immediate *begin, +const struct __immediate *end) +{ +const struct __immediate *iter; +int ret; + +for (iter = begin; iter < end; iter++) { +mutex_lock (&immediate_mutex); +kernel_text_lock (); + ret =arch_immediate_update (iter); +kernel_text_unlock (); +if (ret) +printk (KERN_WARNING "Invalid immediate value. " +"Variable at %p, " +"instruction at %p, size %lu\n" , + (void *)iter->immediate, + (void *)iter->var, iter->size); +mutex_unlock (&immediate_mutex); + } +}
Quoted 1 line
iter++ will go off rails.
You are right. It's ok here since we are actually smaller than 32 bytes, but I should force the structure alignment so that if the structure grows, the assembly declaration follows. I'll go for the gcc attribute and then we can remove the section declaration.
Mathieu
Quoted 2 lines
--
vda
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 2/7 Immediate Values - Kconfig menu in EMBEDDED
In reply to Mathieu DesnoyersImmediate values provide a way to use dynamic code patching to update variables sitting within the instruction stream. It saves caches lines normally used by static read mostly variables. Enable it by default, but let users disable it through the EMBEDDED menu with the "Disable immediate values" submenu entry.
Note: Since I think that I really should let embedded systems developers using RO memory the option to disable the immediate values, I choose to leave this menu option there, in the EMBEDDED menu. Also, the "CONFIG_IMMEDIATE" makes sense because we want to compile out all the immediate code when we decide not to use optimized immediate values at all (it removes otherwise unused code).
--- init/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
init/Kconfig +21 -0
@@ -407,6 +407,17 @@ config CC_OPTIMIZE_FOR_SIZE config SYSCTL bool +config IMMEDIATE + default y if !DISABLE_IMMEDIATE + depends on X86_32 || PPC || PPC64 + bool + help + Immediate values are used as read mostly variables that are rarely + updated. They use code patching to modify the values inscribed in the + instruction stream. It provides a way to save precious cache lines + that would otherwise have to be used by these variables. Can be + disabled through the EMBEDDED menu. + menuconfig EMBEDDED bool "Configure standard kernel features (for small systems)" help
@@ -645,6 +656,16 @@ config PROC_KPAGEMAP information on page-level memory usage. Disabling this interface will reduce the size of the kernel by around 600 bytes. +config DISABLE_IMMEDIATE + default y if EMBEDDED + bool "Disable immediate values" if EMBEDDED + depends on X86_32 || PPC || PPC64 + help + Disable code patching based immediate values for embedded systems. It + consumes slightly more memory and requires to modify the instruction + stream each time a variable is updated. Should really be disabled for + embedded systems with read-only text. + endmenu # General setup config RT_MUTEXES
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 2/7] Immediate Values - Kconfig menu in EMBEDDED
Quoted 8 lines · On Mon, 17 Sep 2007 14:42:26 -0400 Mathieu Desnoyers wrote:
init/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)Index: linux-2.6-lttng/init/Kconfig
===================================================================
init/Kconfig config CC_OPTIMIZE_FOR_SIZE · line 415
Quoted 9 lines
init/Kconfig +6
-0@@ -407,6 +407,17 @@ config CC_OPTIMIZE_FOR_SIZE config SYSCTL bool +config IMMEDIATE + default y if !DISABLE_IMMEDIATE + depends on X86_32 || PPC || PPC64 + bool + help + Immediate values are used as read mostly variables that are rarely
read-mostly
init/Kconfig config CC_OPTIMIZE_FOR_SIZE · line 417
Quoted 2 lines
init/Kconfig +2
-0+ updated. They use code patching to modify the values inscribed in the + instruction stream. It provides a way to save precious cache lines
They .... (then) It ...
so choose one of the other. I think I prefer "They".
init/Kconfig config CC_OPTIMIZE_FOR_SIZE · line 423
Quoted 6 lines
init/Kconfig +3
-0+ that would otherwise have to be used by these variables. Can be + disabled through the EMBEDDED menu. + menuconfig EMBEDDED bool "Configure standard kernel features (for small systems)" help
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
PATCH 3/7 Immediate Values - Move Kprobes i386 restore_interrupt to kdebug.h
In reply to Mathieu DesnoyersSince the breakpoint handler is useful both to kprobes and immediate values, it makes sense to make the required restore_interrupt() available through asm-i386/kdebug.h.
--- include/asm-i386/kdebug.h | 12 ++++++++++++ include/asm-i386/kprobes.h | 9 --------- 2 files changed, 12 insertions(+), 9 deletions(-)
include/asm-i386/kdebug.h +12 -0
@@ -6,6 +6,9 @@* from x86_64 architecture. */ +#include <asm/ptrace.h> +#include <asm/system.h> +struct pt_regs ;/* Grossly misnamed. */
@@ -25,4 +28,13 @@ enum die_val { DIE_PAGE_FAULT_NO_CONTEXT, }; +/* trap3/1 are intr gates for kprobes. So, restore the status of IF, +* if necessary, before executing the original int3/1 (trap) handler. +*/ +static inline void restore_interrupts (struct pt_regs *regs) +{ +if (regs->eflags &IF_MASK ) +local_irq_enable (); +} +#endif
include/asm-i386/kprobes.h +0 -9
@@ -79,15 +79,6 @@ struct kprobe_ctlblk {struct prev_kprobe prev_kprobe; }; -/* trap3/1 are intr gates for kprobes. So, restore the status of IF, -* if necessary, before executing the original int3/1 (trap) handler. -*/ -static inline void restore_interrupts (struct pt_regs *regs) -{ -if (regs->eflags &IF_MASK ) -local_irq_enable (); -} -extern int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data);extern int kprobe_fault_handler (struct pt_regs *regs,int trapnr);
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 4/7 Immediate Values - i386 Optimization
In reply to Mathieu Desnoyersi386 optimization of the immediate values which uses a movl with code patching to set/unset the value used to populate the register used as variable source.
Changelog:
- Use text_poke_early with cr0 WP save/restore to patch the bypass. We are doing non atomic writes to a code region only touched by us (nobody can execute it since we are protected by the immediate_mutex).
- Put immediate_set and _immediate_set in the architecture independent header.
--- arch/i386/kernel/Makefile | 1 arch/i386/kernel/immediate.c | 307 +++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/traps.c | 8 - include/asm-i386/immediate.h | 82 +++++++++++ 4 files changed, 394 insertions(+), 4 deletions(-)
include/asm-i386/immediate.h new file +82 -0
@@ -0,0 +1,82 @@ +#ifndef _ASM_I386_IMMEDIATE_H +#define _ASM_I386_IMMEDIATE_H + +/* +* Immediate values. i386 architecture optimizations. +* +* (C) Copyright 2006 Mathieu Desnoyers <[email protected]> +* +* This file is released under the GPLv2. +* See the file COPYING for more details. +*/ + +struct __immediate { +long var;/* Pointer to the identifier variable of the +* immediate value +*/ +long immediate;/* +* Pointer to the memory location of the +* immediate value within the instruction. +*/ +long size;/* Type size. */ +}; + +/** +* immediate_read - read immediate variable +* @name: immediate value name +* +* Reads the value of @var. +* Optimized version of the immediate. +* Do not use in __init and __exit functions. Use _immediate_read() instead. +* Makes sure the 2 and 4 bytes update will be atomic by aligning the immediate +* value. 2 bytes (short) uses a 66H prefix. If size is bigger than 4 bytes, +* fall back on a memory read. +*/ +#define immediate_read (name) \ + ({ \ + __typeof__(name##__immediate) value; \ + switch (sizeof(value)) { \ + case 1: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+1, 1;\n\t" \ + ".previous;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + case 2: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+2, 2;\n\t" \ + ".previous;\n\t" \ + "1:\n\t" \ + ".align 2;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + case 4: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+1, 4;\n\t" \ + ".previous;\n\t" \ + "1:\n\t" \ + ".org (1b)+(3-((1b)%%4)), 0x90;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + default:value = name##__immediate; \ + break; \ + }; \ + value; \ + }) + +extern int arch_immediate_update (const struct __immediate *immediate); +extern void arch_immediate_update_early (const struct __immediate *immediate); + +#endif /* _ASM_I386_IMMEDIATE_H */
arch/i386/kernel/Makefile +1 -0
@@ -37,6 +37,7 @@ obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_EFI) += efi.o efi_stub.o +obj-$(CONFIG_IMMEDIATE) += immediate.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_VM86) += vm86.o
arch/i386/kernel/immediate.c new file +307 -0
307 lines not on this page · raw message
arch/i386/kernel/traps.c +4 -4
@@ -601,7 +601,7 @@ fastcall void do_##name(struct pt_regs * } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) -#ifndef CONFIG_KPROBES +#if !defined(CONFIG_KPROBES ) && !defined(CONFIG_IMMEDIATE ) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)#endif DO_VM86_ERROR (4 ,SIGSEGV ,"overflow" , overflow)
@@ -843,14 +843,14 @@ void restart_nmi(void)acpi_nmi_enable (); } -#ifdef CONFIG_KPROBES +#if defined(CONFIG_KPROBES ) || defined(CONFIG_IMMEDIATE ) fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) {if (notify_die (DIE_INT3 ,"int3" , regs, error_code,3 ,SIGTRAP ) ==NOTIFY_STOP )return ; -/* This is an interrupt gate, because kprobes wants interrupts -disabled. Normal trap handlers don't. */ +/* This is an interrupt gate, because kprobes and immediate values wants +* interrupts disabled. Normal trap handlers don't. */ restore_interrupts (regs);do_trap (3 ,SIGTRAP ,"int3" ,1 , regs, error_code,NULL ); }
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 4/7] Immediate Values - i386 Optimization
Quoted 44 lines · Mathieu Desnoyers
i386 optimization of the immediate values which uses a movl with code patching to set/unset the value used to populate the register used as variable source.
Changelog:
- Usetext_poke_earlywith cr0 WP save/restore to patch the bypass. We are doing non atomic writes to a code region only touched by us (nobody can execute it since we are protected by theimmediate_mutex).
- Putimmediate_setand_immediate_setin the architecture independent header.Signed-off-by Mathieu Desnoyers <[email protected]>CC Andi Kleen <[email protected]>CC "H. Peter Anvin" <[email protected]>CC Chuck Ebbert <[email protected]>CC Christoph Hellwig <[email protected]>--- arch/i386/kernel/Makefile | 1 arch/i386/kernel/immediate.c | 307 +++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/traps.c | 8 - include/asm-i386/immediate.h | 82 +++++++++++ 4 files changed, 394 insertions(+), 4 deletions(-)Index:
linux-2.6-lttng/include/asm-i386/immediate.h
===================================================================include/asm-i386/immediate.h new file +18
-0@@ -0,0 +1,82 @@ +#ifndef _ASM_I386_IMMEDIATE_H +#define _ASM_I386_IMMEDIATE_H + +/* + * Immediate values. i386 architecture optimizations. + * + * (C) Copyright 2006 Mathieu Desnoyers <[email protected]> + * + * This file is released under the GPLv2. + * See the file COPYING for more details. + */ + +struct __immediate { + long var; /* Pointer to the identifier variable of the + * immediate value + */ + long immediate; /* + * Pointer to the memory location of the
include/asm-i386/immediate.h line 28
Quoted 10 lines
include/asm-i386/immediate.h new file +10
-0+* immediate value within the instruction. +*/ +long size;/* Type size. */ +}; + +/** +* immediate_read - read immediate variable +* @name: immediate value name +* +* Reads the value of @var.
s/var/name/ ?
Quoted 419 lines
include/asm-i386/immediate.h new file +54
-0+* Optimized version of the immediate. +* Do not use in __init and __exit functions. Use _immediate_read() instead. +* Makes sure the 2 and 4 bytes update will be atomic by aligning the immediate +* value. 2 bytes (short) uses a 66H prefix. If size is bigger than 4 bytes, +* fall back on a memory read. +*/ +#define immediate_read (name) \ + ({ \ + __typeof__(name##__immediate) value; \ + switch (sizeof(value)) { \ + case 1: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+1, 1;\n\t" \ + ".previous;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + case 2: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+2, 2;\n\t" \ + ".previous;\n\t" \ + "1:\n\t" \ + ".align 2;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + case 4: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + ".long %1, (0f)+1, 4;\n\t" \ + ".previous;\n\t" \ + "1:\n\t" \ + ".org (1b)+(3-((1b)%%4)), 0x90;\n\t" \ + "0:\n\t" \ + "mov %2,%0;\n\t" \ + : "=r" (value) \ + : "m" (name##__immediate), \ + "i" (0)); \ + break; \ + default:value = name##__immediate; \ + break; \ + }; \ + value; \ + }) + +extern int arch_immediate_update (const struct __immediate *immediate); +extern void arch_immediate_update_early (const struct __immediate *immediate); + +#endif /* _ASM_I386_IMMEDIATE_H */ Index: linux-2.6-lttng/arch/i386/kernel/Makefile
===================================================================arch/i386/kernel/Makefile +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_EFI) += efi.o efi_stub.o +obj-$(CONFIG_IMMEDIATE) += immediate.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_VM86) += vm86.oIndex:
linux-2.6-lttng/arch/i386/kernel/immediate.c
===================================================================arch/i386/kernel/immediate.c new file +307
-0@@ -0,0 +1,307 @@ +/* +* Immediate Value - i386 architecture specific code. +* +* Rationale +* +* Required because of : +* - Erratum 49 fix for Intel PIII. +* - Still present on newer processors : Intel Core 2 Duo Processor for Intel +* Centrino Duo Processor Technology Specification Update, AH33. +* Unsynchronized Cross-Modifying Code Operations Can Cause Unexpected +* Instruction Execution Results. +* +* Permits immediate value modification by XMC with correct serialization. +* +* Reentrant for NMI and trap handler instrumentation. Permits XMC to a +* location that has preemption enabled because it involves no temporary or +* reused data structure. +* +* Quoting Richard J Moore, source of the information motivating this +* implementation which differs from the one proposed by Intel which is not +* suitable for kernel context (does not support NMI and would require disabling +* interrupts on every CPU for a long period) : +* +* "There is another issue to consider when looking into using probes other +* then int3: +* +* Intel erratum 54 - Unsynchronized Cross-modifying code - refers to the +* practice of modifying code on one processor where another has prefetched +* the unmodified version of the code. Intel states that unpredictable general +* protection faults may result if a synchronizing instruction (iret, int, +* int3, cpuid, etc ) is not executed on the second processor before it +* executes the pre-fetched out-of-date copy of the instruction. +* +* When we became aware of this I had a long discussion with Intel's +* microarchitecture guys. It turns out that the reason for this erratum +* (which incidentally Intel does not intend to fix) is because the trace +* cache - the stream of micorops resulting from instruction interpretation - +* cannot guaranteed to be valid. Reading between the lines I assume this +* issue arises because of optimization done in the trace cache, where it is +* no longer possible to identify the original instruction boundaries. If the +* CPU discoverers that the trace cache has been invalidated because of +* unsynchronized cross-modification then instruction execution will be +* aborted with a GPF. Further discussion with Intel revealed that replacing +* the first opcode byte with an int3 would not be subject to this erratum. +* +* So, is cmpxchg reliable? One has to guarantee more than mere atomicity." +* +* Overall design +* +* The algorithm proposed by Intel applies not so well in kernel context: it +* would imply disabling interrupts and looping on every CPUs while modifying +* the code and would not support instrumentation of code called from interrupt +* sources that cannot be disabled. +* +* Therefore, we use a different algorithm to respect Intel's erratum (see the +* quoted discussion above). We make sure that no CPU sees an out-of-date copy +* of a pre-fetched instruction by 1 - using a breakpoint, which skips the +* instruction that is going to be modified, 2 - issuing an IPI to every CPU to +* execute a sync_core(), to make sure that even when the breakpoint is removed, +* no cpu could possibly still have the out-of-date copy of the instruction, +* modify the now unused 2nd byte of the instruction, and then put back the +* original 1st byte of the instruction. +* +* It has exactly the same intent as the algorithm proposed by Intel, but +* it has less side-effects, scales better and supports NMI, SMI and MCE. +* +* Mathieu Desnoyers <[email protected]> +*/ + +#include <linux/notifier.h> +#include <linux/preempt.h> +#include <linux/smp.h> +#include <linux/notifier.h> +#include <linux/module.h> +#include <linux/immediate.h> +#include <linux/kdebug.h> +#include <linux/rcupdate.h> +#include <linux/kprobes.h> + +#include <asm/cacheflush.h> + +#define BREAKPOINT_INSTRUCTION 0xcc +#define BREAKPOINT_INS_LEN 1 +#define NR_NOPS 8 + +static long target_after_int3;/* EIP of the target after the int3 */ +static long bypass_eip;/* EIP of the bypass. */ +static long bypass_after_int3;/* EIP after the end-of-bypass int3 */ +static long after_immediate;/* +* EIP where to resume after the +* single-stepping. +*/ + +/* +* Size of the movl instruction (without the immediate value) in bytes. +* The 2 bytes load immediate has a 66H prefix, which makes the opcode 2 bytes +* wide. +*/ +static inline size_t _immediate_get_insn_size (long size) +{ +switch (size) { +case 1 :return 1 ; +case 2 :return 2 ; +case 4 :return 1 ; +default :BUG (); + }; +} + +/* +* Internal bypass used during value update. The bypass is skipped by the +* function in which it is inserted. +* No need to be aligned because we exclude readers from the site during +* update. +* Layout is: +* nop nop nop nop nop nop nop nop int3 +* The nops are the target replaced by the instruction to single-step. +*/ +static inline void _immediate_bypass (long *bypassaddr,long *breaknextaddr) +{ + asmvolatile ("jmp 2f;\n\t" +"0:\n\t" +".space 8, 0x90;\n\t" +"1:\n\t" +"int3;\n\t" +"2:\n\t" +"movl $(0b),%0;\n\t" +"movl $((1b)+1),%1;\n\t" + :"=r" (*bypassaddr), +"=r" (*breaknextaddr) : ); +} + +static void immediate_synchronize_core (void *info) +{ +sync_core ();/* use cpuid to stop speculative execution */ +} + +/* +* The eip value points right after the breakpoint instruction, in the second +* byte of the movl. +* Disable preemption in the bypass to make sure no thread will be preempted in +* it. We can then use synchronize_sched() to make sure every bypass users have +* ended. +*/ +static int immediate_notifier (struct notifier_block *nb, +unsigned long val,void *data) +{ +enum die_val die_val = (enum die_val ) val; +struct die_args *args = data; + +if (!args->regs ||user_mode_vm (args->regs)) +return NOTIFY_DONE ; + +if (die_val ==DIE_INT3 ) { +if (args->regs->eip == target_after_int3) { +preempt_disable (); + args->regs->eip = bypass_eip; +return NOTIFY_STOP ; + }else if (args->regs->eip == bypass_after_int3) { + args->regs->eip = after_immediate; +preempt_enable (); +return NOTIFY_STOP ; + } + } +return NOTIFY_DONE ; +} + +static struct notifier_block immediate_notify = { + .notifier_call = immediate_notifier, + .priority =0x7fffffff ,/* we need to be notified first */ +}; + + +/** +* arch_immediate_update - update one immediate value +* @immediate: pointer of type const struct __immediate to update +* +* Update one immediate value. Must be called with immediate_mutex held. +*/ +__kprobes int arch_immediate_update (const struct __immediate *immediate) +{ +int ret; +size_t insn_size =_immediate_get_insn_size (immediate->size); +long insn = immediate->immediate - insn_size; +long len; +unsigned long cr0; + +#ifdef CONFIG_KPROBES +/* +* Fail if a kprobe has been set on this instruction. +* (TODO: we could eventually do better and modify all the (possibly +* nested) kprobes for this site if kprobes had an API for this. +*/ +if (unlikely (*(unsigned char *)insn ==BREAKPOINT_INSTRUCTION )) { +printk (KERN_WARNING "Immediate value in conflict with kprobe. " +"Variable at %p, " +"instruction at %p, size %lu\n" , + (void *)immediate->immediate, + (void *)immediate->var, immediate->size); +return -EBUSY ; + } +#endif + +/* +* If the variable and the instruction have the same value, there is +* nothing to do. +*/ +switch (immediate->size) { +case 1 :if (*(uint8_t *)immediate->immediate + == *(uint8_t *)immediate->var) +return 0 ; +break ; +case 2 :if (*(uint16_t *)immediate->immediate + == *(uint16_t *)immediate->var) +return 0 ; +break ; +case 4 :if (*(uint32_t *)immediate->immediate + == *(uint32_t *)immediate->var) +return 0 ; +break ; +default :return -EINVAL ; + } + +_immediate_bypass (&bypass_eip, &bypass_after_int3); + + after_immediate = immediate->immediate + immediate->size; + +/* +* Using the _early variants because nobody is executing the +* bypass code while we patch it. It is protected by the +* immediate_mutex. Since we modify the instructions non atomically (for +* nops), we have to use the _early variant. +* We must however deal with the WP flag in cr0 by ourself. +*/ +kernel_wp_save (cr0); +text_poke_early ((void *)bypass_eip, (void *)insn, + insn_size + immediate->size); +/* +* Fill the rest with nops. +*/ + len =NR_NOPS - immediate->size - insn_size; +add_nops ((void *)(bypass_eip + insn_size + immediate->size), len); +kernel_wp_restore (cr0); + + target_after_int3 = insn +BREAKPOINT_INS_LEN ; +/* register_die_notifier has memory barriers */ +register_die_notifier (&immediate_notify); +/* The breakpoint will single-step the bypass */ +text_poke ((void *)insn, + INIT_ARRAY(unsigned char, BREAKPOINT_INSTRUCTION, 1), 1); +wmb (); +/* +* Execute serializing instruction on each CPU. +* Acts as a memory barrier. +*/ + ret =on_each_cpu (immediate_synchronize_core,NULL ,1 ,1 ); +BUG_ON (ret !=0 ); + +text_poke ((void *)(insn + insn_size), (void *)immediate->var, + immediate->size); +wmb (); +text_poke ((void *)insn, (unsigned char *)bypass_eip,1 ); +/* +* Wait for all int3 handlers to end +* (interrupts are disabled in int3). +* This CPU is clearly not in a int3 handler, +* because int3 handler is not preemptible and +* there cannot be any more int3 handler called +* for this site, because we placed the original +* instruction back. +* synchronize_sched has memory barriers. +*/ +synchronize_sched (); +unregister_die_notifier (&immediate_notify); +/* unregister_die_notifier has memory barriers */ +return 0 ; +} + +/** +* arch_immediate_update_early - update one immediate value at boot time +* @immediate: pointer of type const struct __immediate to update +* +* Update one immediate value at boot time. +*/ +void __init arch_immediate_update_early (const struct __immediate *immediate) +{ +/* +* If the variable and the instruction have the same value, there is +* nothing to do. +*/ +switch (immediate->size) { +case 1 :if (*(uint8_t *)immediate->immediate + == *(uint8_t *)immediate->var) +return ; +break ; +case 2 :if (*(uint16_t *)immediate->immediate + == *(uint16_t *)immediate->var) +return ; +break ; +case 4 :if (*(uint32_t *)immediate->immediate + == *(uint32_t *)immediate->var) +return ; +break ; +default :return ; + } +memcpy ((void *)immediate->immediate, (void *)immediate->var, + immediate->size); +}Index:
linux-2.6-lttng/arch/i386/kernel/traps.c
===================================================================arch/i386/kernel/traps.c +4
-4@@ -601,7 +601,7 @@ fastcall void do_##name(struct pt_regs * } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) -#ifndef CONFIG_KPROBES +#if !defined(CONFIG_KPROBES ) && !defined(CONFIG_IMMEDIATE ) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)#endif DO_VM86_ERROR (4 ,SIGSEGV ,"overflow" , overflow)@@ -843,14 +843,14 @@ void restart_nmi(void)acpi_nmi_enable (); } -#ifdef CONFIG_KPROBES +#if defined(CONFIG_KPROBES ) || defined(CONFIG_IMMEDIATE ) fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) {if (notify_die (DIE_INT3 ,"int3" , regs, error_code,3 ,SIGTRAP ) ==NOTIFY_STOP )return ; -/* This is an interrupt gate, because kprobes wants interrupts -disabled. Normal trap handlers don't. */ +/* This is an interrupt gate, because kprobes and immediate values wants +* interrupts disabled. Normal trap handlers don't. */ restore_interrupts (regs);do_trap (3 ,SIGTRAP ,"int3" ,1 , regs, error_code,NULL ); }Signature · 9 lines
-- Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Signature · 2 lines
Regards/Gruß,
Boris.PATCH 5/7 Immediate Values - Powerpc Optimization
In reply to Mathieu DesnoyersPowerPC optimization of the immediate values which uses a li instruction, patched with an immediate value.
Changelog:
- Put immediate_set and _immediate_set in the architecture independent header.
--- arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/immediate.c | 103 ++++++++++++++++++++++++++++++++++++++++ include/asm-powerpc/immediate.h | 73 ++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+)
include/asm-powerpc/immediate.h new file +73 -0
@@ -0,0 +1,73 @@ +#ifndef _ASM_POWERPC_IMMEDIATE_H +#define _ASM_POWERPC_IMMEDIATE_H + +/* +* Immediate values. PowerPC architecture optimizations. +* +* (C) Copyright 2006 Mathieu Desnoyers <[email protected]> +* +* This file is released under the GPLv2. +* See the file COPYING for more details. +*/ + +#include <asm/asm-compat.h> + +struct __immediate { +long var;/* Identifier variable of the immediate value */ +long immediate;/* +* Pointer to the memory location that holds +* the immediate value within the load immediate +* instruction. +*/ +long size;/* Type size. */ +}; + +/** +* immediate_read - read immediate variable +* @name: immediate value name +* +* Reads the value of @name. +* Optimized version of the immediate. +* Do not use in __init and __exit functions. Use _immediate_read() instead. +* Makes sure the 2 bytes update will be atomic by aligning the immediate +* value. Use a normal memory read for the 4 bytes immediate because there is no +* way to atomically update it without using a seqlock read side, which would +* cost more in term of total i-cache and d-cache space than a simple memory +* read. +*/ +#define immediate_read (name) \ + ({ \ + __typeof__(name##__immediate) value; \ + switch (sizeof(value)) { \ + case 1: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + PPC_LONG "%1, ((0f)+3), 1;\n\t" \ + ".previous;\n\t" \ + "0:\n\t" \ + "li %0,%2;\n\t" \ + : "=r" (value) \ + : "i" (&name##__immediate), \ + "i" (0)); \ + break; \ + case 2: \ + asm ( ".section __immediate, \"a\", @progbits;\n\t" \ + PPC_LONG "%1, ((0f)+2), 2;\n\t" \ + ".previous;\n\t" \ + ".align 2\n\t" \ + "0:\n\t" \ + "li %0,%2;\n\t" \ + : "=r" (value) \ + : "i" (&name##__immediate), \ + "i" (0)); \ + break; \ + default: \ + value = name##__immediate; \ + break; \ + }; \ + value; \ + }) + +extern int arch_immediate_update (const struct __immediate *immediate); +extern void arch_immediate_update_early (const struct __immediate *immediate); + +#endif /* _ASM_POWERPC_IMMEDIATE_H */
arch/powerpc/kernel/Makefile +1 -0
@@ -97,3 +97,4 @@ obj-$(CONFIG_PPC64) += $(obj64-y) extra-$(CONFIG_PPC_FPU) += fpu.o extra-$(CONFIG_PPC64) += entry_64.o +obj-$(CONFIG_IMMEDIATE) += immediate.o
arch/powerpc/kernel/immediate.c new file +103 -0
103 lines not on this page · raw message
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 6/7 Immediate Values - Documentation
In reply to Mathieu Desnoyers--- Documentation/immediate.txt | 228 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+)
Documentation/immediate.txt new file +228 -0
@@ -0,0 +1,228 @@ + Using the Immediate Values + + Mathieu Desnoyers + + +This document introduces Immediate Values and their use. + +* Purpose of immediate values + +An immediate value is used to compile into the kernel variables that sit within +the instruction stream. They are meant to be rarely updated but read often. +Using immediate values for these variables will save cache lines. + +This infrastructure is specialized in supporting dynamic patching of the values +in the instruction stream when multiple CPUs are running without disturbing the +normal system behavior. + +Compiling code meant to be rarely enabled at runtime can be done using +immediate_if() as condition surrounding the code. + +* Usage + +In order to use the "immediate" macros, you should include linux/immediate.h. + +#include <linux/immediate.h> + +DEFINE_IMMEDIATE(char, this_immediate); +EXPORT_SYMBOL(this_immediate); + + +And use, in the body of a function: + +Use immediate_set(&this_immediate) to set the immediate value. + +Use immediate_read(&this_immediate) to read the immediate value. + +The immediate mechanism supports inserting multiple instances of the same +immediate. Immediate values can be put in inline functions, inlined static +functions, and unrolled loops. + +If you have to read the immediate values from a function declared as __init or +__exit, you should explicitly use _immediate_read(), which will fall back on a +global variable read. Failing to do so will leave a reference to the __init +section after it is freed (it would generate a modpost warning). + +The prefered idiom to dynamically enable compiled-in code is to use +immediate_if (&this_immediate), which may eventually use gcc improvements to +provide a jump instruction patching based condition instead of a immediate value +feeding a conditional jump. You should use _immediate_if () instead of +immediate_if () in functions marked __init or __exit. + +immediate_set_early() should be used only at early kernel boot time, before SMP +is activated. It provides no locking, does not take care of clearing the +write-protection bits when touching executable pages and does not take care or +SMP errata on the i386 and x86_64 architectures. By not doing so, it can update +the immediate values very early at kernel boot time and require the minimalistic +infrastructure available at that point. + +You can choose to set an initial static value to the immediate by using, for +instance: + +DEFINE_IMMEDIATE(long, myptr) = 10; + + +* Optimization for a given architecture + +One can implement optimized immediate values for a given architecture by +replacing asm-$ARCH/immediate.h. + +* Performance improvement + +* Memory hit for a data-based branch + +Here are the results on a 3GHz Pentium 4: + +number of tests: 100 +number of branches per test: 100000 +memory hit cycles per iteration (mean): 636.611 +L1 cache hit cycles per iteration (mean): 89.6413 +instruction stream based test, cycles per iteration (mean): 85.3438 +Just getting the pointer from a modulo on a pseudo-random value, doing + nothing with it, cycles per iteration (mean): 77.5044 + +So: +Base case: 77.50 cycles +instruction stream based test: +7.8394 cycles +L1 cache hit based test: +12.1369 cycles +Memory load based test: +559.1066 cycles + +So let's say we have a ping flood coming at +(14014 packets transmitted, 14014 received, 0% packet loss, time 1826ms) +7674 packets per second. If we put 2 markers for irq entry/exit, it +brings us to 15348 markers sites executed per second. + +(15348 exec/s) * (559 cycles/exec) / (3G cycles/s) = 0.0029 +We therefore have a 0.29% slowdown just on this case. + +Compared to this, the instruction stream based test will cause a +slowdown of: + +(15348 exec/s) * (7.84 cycles/exec) / (3G cycles/s) = 0.00004 +For a 0.004% slowdown. + +If we plan to use this for memory allocation, spinlock, and all sort of +very high event rate tracing, we can assume it will execute 10 to 100 +times more sites per second, which brings us to 0.4% slowdown with the +instruction stream based test compared to 29% slowdown with the memory +load based test on a system with high memory pressure. + + + +* Markers impact under heavy memory load + +Running a kernel with my LTTng instrumentation set, in a test that +generates memory pressure (from userspace) by trashing L1 and L2 caches +between calls to getppid() (note: syscall_trace is active and calls +a marker upon syscall entry and syscall exit; markers are disarmed). +This test is done in user-space, so there are some delays due to IRQs +coming and to the scheduler. (UP 2.6.22-rc6-mm1 kernel, task with -20 +nice level) + +My first set of results: Linear cache trashing, turned out not to be +very interesting, because it seems like the linearity of the memset on a +full array is somehow detected and it does not "really" trash the +caches. + +Now the most interesting result: Random walk L1 and L2 trashing +surrounding a getppid() call. + +- Markers compiled out (but syscall_trace execution forced) +number of tests: 10000 +No memory pressure +Reading timestamps takes 108.033 cycles +getppid: 1681.4 cycles +With memory pressure +Reading timestamps takes 102.938 cycles +getppid: 15691.6 cycles + + +- With the immediate values based markers: +number of tests: 10000 +No memory pressure +Reading timestamps takes 108.006 cycles +getppid: 1681.84 cycles +With memory pressure +Reading timestamps takes 100.291 cycles +getppid: 11793 cycles + + +- With global variables based markers: +number of tests: 10000 +No memory pressure +Reading timestamps takes 107.999 cycles +getppid: 1669.06 cycles +With memory pressure +Reading timestamps takes 102.839 cycles +getppid: 12535 cycles + +The result is quite interesting in that the kernel is slower without +markers than with markers. I explain it by the fact that the data +accessed is not laid out in the same manner in the cache lines when the +markers are compiled in or out. It seems that it aligns the function's +data better to compile-in the markers in this case. + +But since the interesting comparison is between the immediate values and +global variables based markers, and because they share the same memory +layout, except for the movl being replaced by a movz, we see that the +global variable based markers (2 markers) adds 742 cycles to each system +call (syscall entry and exit are traced and memory locations for both +global variables lie on the same cache line). + + +- Test redone with less iterations, but with error estimates + +10 runs of 100 iterations each: Tests done on a 3GHz P4. Here I run getppid with +syscall trace inactive, comparing the case with memory pressure and withou +memory pressure. (sorry, my system is not setup to execute syscall_trace this +time, but it will make the point anyway). + +No memory pressure +Reading timestamps: 150.92 cycles, std dev. 1.01 cycles +getppid: 1462.09 cycles, std dev. 18.87 cycles + +With memory pressure +Reading timestamps: 578.22 cycles, std dev. 269.51 cycles +getppid: 17113.33 cycles, std dev. 1655.92 cycles + + +Now for memory read timing: (10 runs, branches per test: 100000) +Memory read based branch: + 644.09 cycles, std dev. 11.39 cycles +L1 cache hit based branch: + 88.16 cycles, std dev. 1.35 cycles + + +So, now that we have the raw results, let's calculate: + +Memory read: +644.09±11.39 - 88.16±1.35 = 555.93±11.46 cycles + +Getppid without memory pressure: +1462.09±18.87 - 150.92±1.01 = 1311.17±18.90 cycles + +Getppid with memory pressure: +17113.33±1655.92 - 578.22±269.51 = 16535.11±1677.71 cycles + +Therefore, if we add 2 markers not based on immediate values to the getppid +code, which would add 2 memory reads, we would add +2 * 555.93±12.74 = 1111.86±25.48 cycles + +Therefore, + +1111.86±25.48 / 16535.11±1677.71 = 0.0672 + relative error: sqrt(((25.48/1111.86)^2)+((1677.71/16535.11)^2)) + = 0.1040 + absolute error: 0.1040 * 0.0672 = 0.0070 + +Therefore: 0.0672±0.0070 * 100% = 6.72±0.70 % + +We can therefore affirm that adding 2 markers to getppid, on a system with high +memory pressure, would have a performance hit of at least 6.0% on the system +call time, all within the uncertainty limits of these tests. The same applies to +other kernel code paths. The smaller those code paths are, the highest the +impact ratio will be. + +Therefore, not only is it interesting to use the immediate values to dynamically +activate dormant code such as the markers, but I think it should also be +considered as a replacement for many of the "read mostly" static variables.
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
Re: [patch 6/7] Immediate Values - Documentation
Quoted 19 lines · On Mon, 17 Sep 2007 14:42:30 -0400 Mathieu Desnoyers wrote:
Signed-off-by Mathieu Desnoyers <[email protected]>--- Documentation/immediate.txt | 228 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+)Index:
linux-2.6-lttng/Documentation/immediate.txt
===================================================================Documentation/immediate.txt new file +9
-0@@ -0,0 +1,228 @@ + Using the Immediate Values + + Mathieu Desnoyers + + +This document introduces Immediate Values and their use. + +* Purpose of immediate values +
[snip]
Documentation/immediate.txt line 46
Quoted 7 lines
Documentation/immediate.txt new file +7
-0+ +If you have to read the immediate values from a function declared as __init or +__exit, you should explicitly use _immediate_read(), which will fall back on a +global variable read. Failing to do so will leave a reference to the __init +section after it is freed (it would generate a modpost warning). + +The prefered idiom to dynamically enable compiled-in code is to use
preferred
Documentation/immediate.txt line 48
Quoted 2 lines
Documentation/immediate.txt new file +2
-0+immediate_if (&this_immediate), which may eventually use gcc improvements to +provide a jump instruction patching based condition instead of a immediate value
an
Documentation/immediate.txt line 54
Quoted 6 lines
Documentation/immediate.txt new file +6
-0+feeding a conditional jump. You should use _immediate_if () instead of +immediate_if () in functions marked __init or __exit. + +immediate_set_early() should be used only at early kernel boot time, before SMP +is activated. It provides no locking, does not take care of clearing the +write-protection bits when touching executable pages and does not take care or
does not take care of ??
Documentation/immediate.txt line 56
Quoted 2 lines
Documentation/immediate.txt new file +2
-0+SMP errata on the i386 and x86_64 architectures. By not doing so, it can update +the immediate values very early at kernel boot time and require the minimalistic
require only the
Quoted 8 lines
Documentation/immediate.txt new file +8
-0+infrastructure available at that point. + +You can choose to set an initial static value to the immediate by using, for +instance: + +DEFINE_IMMEDIATE(long, myptr) = 10; + +
[snip]
Documentation/immediate.txt line 104
Quoted 5 lines
Documentation/immediate.txt new file +5
-0+ +(15348 exec/s) * (7.84 cycles/exec) / (3G cycles/s) = 0.00004 +For a 0.004% slowdown. + +If we plan to use this for memory allocation, spinlock, and all sort of
all sorts of
Quoted 6 lines
Documentation/immediate.txt new file +6
-0+very high event rate tracing, we can assume it will execute 10 to 100 +times more sites per second, which brings us to 0.4% slowdown with the +instruction stream based test compared to 29% slowdown with the memory +load based test on a system with high memory pressure. + +
[snip]
Documentation/immediate.txt line 176
Quoted 6 lines
Documentation/immediate.txt new file +6
-0+ + +- Test redone with less iterations, but with error estimates + +10 runs of 100 iterations each: Tests done on a 3GHz P4. Here I run getppid with +syscall trace inactive, comparing the case with memory pressure and withou
last word: without
Quoted 3 lines
Documentation/immediate.txt new file +3
-0+memory pressure. (sorry, my system is not setup to execute syscall_trace this +time, but it will make the point anyway). +
[snip]
Documentation/immediate.txt line 228
Quoted 5 lines
Documentation/immediate.txt new file +5
-0+ + +Therefore, not only is it interesting to use the immediate values to dynamically +activate dormant code such as the markers, but I think it should also be +considered as a replacement for many of the "read mostly" static variables.
"read-mostly"
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
Re: [patch 6/7] Immediate Values - Documentation
Quoted 7 lines · * Randy Dunlap ([email protected]) wrote:
Quoted 5 lines · On Mon, 17 Sep 2007 14:42:30 -0400 Mathieu Desnoyers wrote:
Signed-off-by Mathieu Desnoyers <[email protected]>--- Documentation/immediate.txt | 228 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+)
Quoted 14 lines
Quoted 5 lines
Index:
linux-2.6-lttng/Documentation/immediate.txt
===================================================================Documentation/immediate.txt line 9
Quoted 9 lines
Documentation/immediate.txt new file +9
-0@@ -0,0 +1,228 @@ + Using the Immediate Values + + Mathieu Desnoyers + + +This document introduces Immediate Values and their use. + +* Purpose of immediate values +
Updated, thanks. I also noted that I did not refresh this patch when sending it.. a repost is needed (removed the immediate_if, which is now gone, and changed all immediate_read(&this_immediate) for immediate_read(this_immediate).
Mathieu
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 7/7 Scheduler Profiling - Use Immediate Values
In reply to Mathieu DesnoyersUse immediate values with lower d-cache hit in optimized version as a condition for scheduler profiling call.
--- drivers/kvm/svm.c | 4 +--- drivers/kvm/vmx.c | 3 +-- include/linux/profile.h | 5 +++-- kernel/profile.c | 22 +++++++++++----------- 4 files changed, 16 insertions(+), 18 deletions(-)
kernel/profile.c +11 -11
@@ -42,8 +42,8 @@ static int (*timer_hook)(struct pt_regsstatic atomic_t *prof_buffer;static unsigned long prof_len, prof_shift; -int prof_on__read_mostly ; -EXPORT_SYMBOL_GPL (prof_on); +DEFINE_IMMEDIATE (char, prof_on)__read_mostly ; +EXPORT_IMMEDIATE_SYMBOL_GPL (prof_on);static cpumask_t prof_cpu_mask =CPU_MASK_ALL ;#ifdef CONFIG_SMP
@@ -60,7 +60,7 @@ static int __init profile_setup(char * sint par;if (!strncmp (str, sleepstr,strlen (sleepstr))) { - prof_on =SLEEP_PROFILING ; +immediate_set_early (prof_on,SLEEP_PROFILING );if (str[strlen (sleepstr)] ==',' ) str +=strlen (sleepstr) +1 ;if (get_option (&str, &par))
@@ -69,7 +69,7 @@ static int __init profile_setup(char * s"kernel sleep profiling enabled (shift: %ld)\n" , prof_shift); }else if (!strncmp (str, schedstr,strlen (schedstr))) { - prof_on =SCHED_PROFILING ; +immediate_set_early (prof_on,SCHED_PROFILING );if (str[strlen (schedstr)] ==',' ) str +=strlen (schedstr) +1 ;if (get_option (&str, &par))
@@ -78,7 +78,7 @@ static int __init profile_setup(char * s"kernel schedule profiling enabled (shift: %ld)\n" , prof_shift); }else if (!strncmp (str, kvmstr,strlen (kvmstr))) { - prof_on =KVM_PROFILING ; +immediate_set_early (prof_on,KVM_PROFILING );if (str[strlen (kvmstr)] ==',' ) str +=strlen (kvmstr) +1 ;if (get_option (&str, &par))
@@ -88,7 +88,7 @@ static int __init profile_setup(char * s prof_shift); }else if (get_option (&str, &par)) { prof_shift = par; - prof_on =CPU_PROFILING ; +immediate_set_early (prof_on,CPU_PROFILING );printk (KERN_INFO "kernel profiling enabled (shift: %ld)\n" , prof_shift); }
@@ -99,7 +99,7 @@ __setup("profile=", profile_setup);void __init profile_init (void ) { -if (!prof_on) +if (!_immediate_read (prof_on))return ;/* only text is profiled */
@@ -288,7 +288,7 @@ void profile_hits(int type, void *__pc,int i, j, cpu;struct profile_hit *hits; -if (prof_on != type || !prof_buffer) +if (!prof_buffer)return ; pc =min ((pc - (unsigned long )_stext) >> prof_shift, prof_len -1 ); i = primary = (pc & (NR_PROFILE_GRP -1 )) <<PROFILE_GRPSHIFT ;
@@ -398,7 +398,7 @@ void profile_hits(int type, void *__pc, {unsigned long pc; -if (prof_on != type || !prof_buffer) +if (!prof_buffer)return ; pc = ((unsigned long )__pc - (unsigned long )_stext) >> prof_shift;atomic_add (nr_hits, &prof_buffer[min (pc, prof_len -1 )]);
@@ -555,7 +555,7 @@ static int __init create_hash_tables(voi }return 0 ; out_cleanup: - prof_on =0 ; +immediate_set_early (prof_on,0 );smp_mb ();on_each_cpu (profile_nop,NULL ,0 ,1 );for_each_online_cpu (cpu) {
@@ -582,7 +582,7 @@ static int __init create_proc_profile(vo {struct proc_dir_entry *entry; -if (!prof_on) +if (!_immediate_read (prof_on))return 0 ;if (create_hash_tables ())return -1 ;
include/linux/profile.h +3 -2
@@ -7,10 +7,11 @@#include <linux/init.h> #include <linux/cpumask.h> #include <linux/cache.h> +#include <linux/immediate.h> #include <asm/errno.h> -extern int prof_on__read_mostly ; +DECLARE_IMMEDIATE (char, prof_on)__read_mostly ;#define CPU_PROFILING 1#define SCHED_PROFILING 2
@@ -38,7 +39,7 @@ static inline void profile_hit(int type,/* * Speedup for the common (no profiling enabled) case: */ -if (unlikely (prof_on == type)) +if (unlikely (immediate_read (prof_on) == type))profile_hits (type, ip,1 ); }
drivers/kvm/svm.c +1 -3
@@ -1570,9 +1570,7 @@ again:/* * Profile KVM exit RIPs: */ -if (unlikely (prof_on ==KVM_PROFILING )) -profile_hit (KVM_PROFILING , - (void *)(unsigned long )svm->vmcb->save.rip); +profile_hit (KVM_PROFILING , (void *)(unsigned long )svm->vmcb->save.rip);stgi ();
drivers/kvm/vmx.c +1 -2
@@ -2234,8 +2234,7 @@ again:/* * Profile KVM exit RIPs: */ -if (unlikely (prof_on ==KVM_PROFILING )) -profile_hit (KVM_PROFILING , (void *)vmcs_readl (GUEST_RIP )); +profile_hit (KVM_PROFILING , (void *)vmcs_readl (GUEST_RIP )); r =kvm_handle_exit (kvm_run, vcpu);if (r >0 ) {
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68