forked from Minki/linux
s390/ftrace: hotpatch support for function tracing
Make use of gcc's hotpatch support to generate better code for ftrace function tracing. The generated code now contains only a six byte nop in each function prologue instead of a 24 byte code block which will be runtime patched to support function tracing. With the new code generation the runtime overhead for supporting function tracing is close to zero, while the original code did show a significant performance impact. Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
61f552141c
commit
e6d60b368b
@ -117,7 +117,6 @@ config S390
|
||||
select HAVE_BPF_JIT if 64BIT && PACK_STACK
|
||||
select HAVE_CMPXCHG_DOUBLE
|
||||
select HAVE_CMPXCHG_LOCAL
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_DYNAMIC_FTRACE if 64BIT
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
|
||||
|
@ -87,6 +87,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
|
||||
cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# make use of hotpatch feature if the compiler supports it
|
||||
cc_hotpatch := -mhotpatch=0,3
|
||||
ifeq ($(call cc-option-yn,$(cc_hotpatch)),y)
|
||||
CC_FLAGS_FTRACE := $(cc_hotpatch)
|
||||
KBUILD_AFLAGS += -DCC_USING_HOTPATCH
|
||||
KBUILD_CFLAGS += -DCC_USING_HOTPATCH
|
||||
endif
|
||||
endif
|
||||
|
||||
KBUILD_CFLAGS += -mbackchain -msoft-float $(cflags-y)
|
||||
KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare
|
||||
KBUILD_AFLAGS += $(aflags-y)
|
||||
|
@ -3,8 +3,12 @@
|
||||
|
||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||
|
||||
#ifdef CC_USING_HOTPATCH
|
||||
#define MCOUNT_INSN_SIZE 6
|
||||
#else
|
||||
#define MCOUNT_INSN_SIZE 24
|
||||
#define MCOUNT_RETURN_FIXUP 18
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@ -37,17 +41,28 @@ struct ftrace_insn {
|
||||
static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#ifdef CC_USING_HOTPATCH
|
||||
/* brcl 0,0 */
|
||||
insn->opc = 0xc004;
|
||||
insn->disp = 0;
|
||||
#else
|
||||
/* jg .+24 */
|
||||
insn->opc = 0xc0f4;
|
||||
insn->disp = MCOUNT_INSN_SIZE / 2;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is_ftrace_nop(struct ftrace_insn *insn)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#ifdef CC_USING_HOTPATCH
|
||||
if (insn->disp == 0)
|
||||
return 1;
|
||||
#else
|
||||
if (insn->disp == MCOUNT_INSN_SIZE / 2)
|
||||
return 1;
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# Don't trace early setup code and tracing code
|
||||
CFLAGS_REMOVE_early.o = -pg
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
|
||||
endif
|
||||
|
||||
#
|
||||
|
@ -46,6 +46,13 @@
|
||||
* lg %r14,8(%r15) # offset 18
|
||||
* The jg instruction branches to offset 24 to skip as many instructions
|
||||
* as possible.
|
||||
* In case we use gcc's hotpatch feature the original and also the disabled
|
||||
* function prologue contains only a single six byte instruction and looks
|
||||
* like this:
|
||||
* > brcl 0,0 # offset 0
|
||||
* To enable ftrace the code gets patched like above and afterwards looks
|
||||
* like this:
|
||||
* > brasl %r0,ftrace_caller # offset 0
|
||||
*/
|
||||
|
||||
unsigned long ftrace_plt;
|
||||
@ -64,9 +71,15 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
|
||||
if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
|
||||
return -EFAULT;
|
||||
if (addr == MCOUNT_ADDR) {
|
||||
/* Initial code replacement; we expect to see stg r14,8(r15) */
|
||||
/* Initial code replacement */
|
||||
#ifdef CC_USING_HOTPATCH
|
||||
/* We expect to see brcl 0,0 */
|
||||
ftrace_generate_nop_insn(&orig);
|
||||
#else
|
||||
/* We expect to see stg r14,8(r15) */
|
||||
orig.opc = 0xe3e0;
|
||||
orig.disp = 0xf0080024;
|
||||
#endif
|
||||
ftrace_generate_nop_insn(&new);
|
||||
} else if (old.opc == BREAKPOINT_INSTRUCTION) {
|
||||
/*
|
||||
|
@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p)
|
||||
/*
|
||||
* If kprobes patches the instruction that is morphed by
|
||||
* ftrace make sure that kprobes always sees the branch
|
||||
* "jg .+24" that skips the mcount block
|
||||
* "jg .+24" that skips the mcount block or the "brcl 0,0"
|
||||
* in case of hotpatch.
|
||||
*/
|
||||
ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
|
||||
p->ainsn.is_ftrace_insn = 1;
|
||||
|
@ -27,7 +27,9 @@ ENTRY(ftrace_caller)
|
||||
.globl ftrace_regs_caller
|
||||
.set ftrace_regs_caller,ftrace_caller
|
||||
lgr %r1,%r15
|
||||
#ifndef CC_USING_HOTPATCH
|
||||
aghi %r0,MCOUNT_RETURN_FIXUP
|
||||
#endif
|
||||
aghi %r15,-STACK_FRAME_SIZE
|
||||
stg %r1,__SF_BACKCHAIN(%r15)
|
||||
stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
|
||||
|
@ -242,8 +242,13 @@ if ($arch eq "x86_64") {
|
||||
$cc .= " -m32";
|
||||
|
||||
} elsif ($arch eq "s390" && $bits == 64) {
|
||||
$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
|
||||
$mcount_adjust = -14;
|
||||
if ($cc =~ /-DCC_USING_HOTPATCH/) {
|
||||
$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
|
||||
$mcount_adjust = 0;
|
||||
} else {
|
||||
$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
|
||||
$mcount_adjust = -14;
|
||||
}
|
||||
$alignment = 8;
|
||||
$type = ".quad";
|
||||
$ld .= " -m elf64_s390";
|
||||
|
Loading…
Reference in New Issue
Block a user