Skip to content

Commit

Permalink
static keys: Introduce 'struct static_key', static_key_true()/false()…
Browse files Browse the repository at this point in the history
… and static_key_slow_[inc|dec]()

So here's a boot tested patch on top of Jason's series that does
all the cleanups I talked about and turns jump labels into a
more intuitive to use facility. It should also address the
various misconceptions and confusions that surround jump labels.

Typical usage scenarios:

        #include <linux/static_key.h>

        struct static_key key = STATIC_KEY_INIT_TRUE;

        if (static_key_false(&key))
                do unlikely code
        else
                do likely code

Or:

        if (static_key_true(&key))
                do likely code
        else
                do unlikely code

The static key is modified via:

        static_key_slow_inc(&key);
        ...
        static_key_slow_dec(&key);

The 'slow' prefix makes it abundantly clear that this is an
expensive operation.

I've updated all in-kernel code to use this everywhere. Note
that I (intentionally) have not pushed through the rename
blindly through to the lowest levels: the actual jump-label
patching arch facility should be named like that, so we want to
decouple jump labels from the static-key facility a bit.

On non-jump-label enabled architectures static keys default to
likely()/unlikely() branches.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Jason Baron <jbaron@redhat.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: a.p.zijlstra@chello.nl
Cc: mathieu.desnoyers@efficios.com
Cc: davem@davemloft.net
Cc: ddaney.cavm@gmail.com
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20120222085809.GA26397@elte.hu
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Ingo Molnar committed Feb 24, 2012
1 parent 1cfa60d commit c5905af
Show file tree
Hide file tree
Showing 31 changed files with 298 additions and 205 deletions.
29 changes: 20 additions & 9 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,29 @@ config KPROBES
If in doubt, say "N".

config JUMP_LABEL
bool "Optimize trace point call sites"
bool "Optimize very unlikely/likely branches"
depends on HAVE_ARCH_JUMP_LABEL
help
This option enables a transparent branch optimization that
makes certain almost-always-true or almost-always-false branch
conditions even cheaper to execute within the kernel.

Certain performance-sensitive kernel code, such as trace points,
scheduler functionality, networking code and KVM have such
branches and include support for this optimization technique.

If it is detected that the compiler has support for "asm goto",
the kernel will compile trace point locations with just a
nop instruction. When trace points are enabled, the nop will
be converted to a jump to the trace function. This technique
lowers overhead and stress on the branch prediction of the
processor.

On i386, options added to the compiler flags may increase
the size of the kernel slightly.
the kernel will compile such branches with just a nop
instruction. When the condition flag is toggled to true, the
nop will be converted to a jump instruction to execute the
conditional block of instructions.

This technique lowers overhead and stress on the branch prediction
of the processor and generally makes the kernel faster. The update
of the condition is slower, but those are always very rare.

( On 32-bit x86, the necessary options added to the compiler
flags may increase the size of the kernel slightly. )

config OPTPROBES
def_bool y
Expand Down
6 changes: 3 additions & 3 deletions arch/ia64/include/asm/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,9 @@ paravirt_init_missing_ticks_accounting(int cpu)
pv_time_ops.init_missing_ticks_accounting(cpu);
}

struct jump_label_key;
extern struct jump_label_key paravirt_steal_enabled;
extern struct jump_label_key paravirt_steal_rq_enabled;
struct static_key;
extern struct static_key paravirt_steal_enabled;
extern struct static_key paravirt_steal_rq_enabled;

static inline int
paravirt_do_steal_accounting(unsigned long *new_itm)
Expand Down
4 changes: 2 additions & 2 deletions arch/ia64/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ struct pv_irq_ops pv_irq_ops = {
* pv_time_ops
* time operations
*/
struct jump_label_key paravirt_steal_enabled;
struct jump_label_key paravirt_steal_rq_enabled;
struct static_key paravirt_steal_enabled;
struct static_key paravirt_steal_rq_enabled;

static int
ia64_native_do_steal_accounting(unsigned long *new_itm)
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#define WORD_INSN ".word"
#endif

static __always_inline bool arch_static_branch(struct jump_label_key *key)
static __always_inline bool arch_static_branch(struct static_key *key)
{
asm goto("1:\tnop\n\t"
"nop\n\t"
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
#define JUMP_LABEL_NOP_SIZE 4

static __always_inline bool arch_static_branch(struct jump_label_key *key)
static __always_inline bool arch_static_branch(struct static_key *key)
{
asm goto("1:\n\t"
"nop\n\t"
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define ASM_ALIGN ".balign 4"
#endif

static __always_inline bool arch_static_branch(struct jump_label_key *key)
static __always_inline bool arch_static_branch(struct static_key *key)
{
asm goto("0: brcl 0,0\n"
".pushsection __jump_table, \"aw\"\n"
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#define JUMP_LABEL_NOP_SIZE 4

static __always_inline bool arch_static_branch(struct jump_label_key *key)
static __always_inline bool arch_static_branch(struct static_key *key)
{
asm goto("1:\n\t"
"nop\n\t"
Expand Down
6 changes: 3 additions & 3 deletions arch/x86/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@

#define JUMP_LABEL_NOP_SIZE 5

#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
#define STATIC_KEY_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"

static __always_inline bool arch_static_branch(struct jump_label_key *key)
static __always_inline bool arch_static_branch(struct static_key *key)
{
asm goto("1:"
JUMP_LABEL_INITIAL_NOP
STATIC_KEY_INITIAL_NOP
".pushsection __jump_table, \"aw\" \n\t"
_ASM_ALIGN "\n\t"
_ASM_PTR "1b, %l[l_yes], %c0 \n\t"
Expand Down
6 changes: 3 additions & 3 deletions arch/x86/include/asm/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@ static inline unsigned long long paravirt_sched_clock(void)
return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock);
}

struct jump_label_key;
extern struct jump_label_key paravirt_steal_enabled;
extern struct jump_label_key paravirt_steal_rq_enabled;
struct static_key;
extern struct static_key paravirt_steal_enabled;
extern struct static_key paravirt_steal_rq_enabled;

static inline u64 paravirt_steal_clock(int cpu)
{
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,9 @@ void __init kvm_guest_init(void)
static __init int activate_jump_labels(void)
{
if (has_steal_clock) {
jump_label_inc(&paravirt_steal_enabled);
static_key_slow_inc(&paravirt_steal_enabled);
if (steal_acc)
jump_label_inc(&paravirt_steal_rq_enabled);
static_key_slow_inc(&paravirt_steal_rq_enabled);
}

return 0;
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ static void native_flush_tlb_single(unsigned long addr)
__native_flush_tlb_single(addr);
}

struct jump_label_key paravirt_steal_enabled;
struct jump_label_key paravirt_steal_rq_enabled;
struct static_key paravirt_steal_enabled;
struct static_key paravirt_steal_rq_enabled;

static u64 native_steal_clock(int cpu)
{
Expand Down
8 changes: 4 additions & 4 deletions arch/x86/kvm/mmu_audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
}

static bool mmu_audit;
static struct jump_label_key mmu_audit_key;
static struct static_key mmu_audit_key;

static void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point)
{
Expand All @@ -250,7 +250,7 @@ static void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point)

static inline void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point)
{
if (static_branch((&mmu_audit_key)))
if (static_key_false((&mmu_audit_key)))
__kvm_mmu_audit(vcpu, point);
}

Expand All @@ -259,7 +259,7 @@ static void mmu_audit_enable(void)
if (mmu_audit)
return;

jump_label_inc(&mmu_audit_key);
static_key_slow_inc(&mmu_audit_key);
mmu_audit = true;
}

Expand All @@ -268,7 +268,7 @@ static void mmu_audit_disable(void)
if (!mmu_audit)
return;

jump_label_dec(&mmu_audit_key);
static_key_slow_dec(&mmu_audit_key);
mmu_audit = false;
}

Expand Down
Loading

0 comments on commit c5905af

Please sign in to comment.