aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorWu Zhangjin <wuzhangjin@gmail.com>2010-05-14 07:08:32 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-07-05 12:17:29 -0400
commite424054000878d7eb11e44289242886d6e219d22 (patch)
treefdae97a03c8e8b3c4ff232e627e20da88d0477c2 /arch/mips
parent4d6829f92a02d96e1bec2ffe6ee674ef3b49722b (diff)
MIPS: Tracing: Reduce the overhead of dynamic Function Tracer
With the help of uasm this patch encodes the instructions of the dynamic function tracer in ftrace_dyn_arch_init() when initializing it. As a result we can remove the dynamic encoding of instructions in ftrace_make_nop()/call(), ftrace_enable_ftrace_graph_caller() and remove the macro jump_insn_encode() and at last this reduce the overhead of dynamic Function Tracer. This also is cleaner. Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> Cc: linux-mips <linux-mips@linux-mips.org> Cc: David Daney <david.s.daney@gmail.com> Patchwork: http://patchwork.linux-mips.org/patch/1230/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/ftrace.c93
1 files changed, 49 insertions, 44 deletions
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index b1b8fec2432f..c4042cad836e 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -2,7 +2,7 @@
2 * Code for replacing ftrace calls with jumps. 2 * Code for replacing ftrace calls with jumps.
3 * 3 *
4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> 4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
5 * Copyright (C) 2009 DSLab, Lanzhou University, China 5 * Copyright (C) 2009, 2010 DSLab, Lanzhou University, China
6 * Author: Wu Zhangjin <wuzhangjin@gmail.com> 6 * Author: Wu Zhangjin <wuzhangjin@gmail.com>
7 * 7 *
8 * Thanks goes to Steven Rostedt for writing the original x86 version. 8 * Thanks goes to Steven Rostedt for writing the original x86 version.
@@ -12,21 +12,46 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/ftrace.h> 13#include <linux/ftrace.h>
14 14
15#include <asm/cacheflush.h>
16#include <asm/asm.h> 15#include <asm/asm.h>
17#include <asm/asm-offsets.h> 16#include <asm/asm-offsets.h>
17#include <asm/cacheflush.h>
18#include <asm/uasm.h>
18 19
19#ifdef CONFIG_DYNAMIC_FTRACE 20#ifdef CONFIG_DYNAMIC_FTRACE
20 21
21#define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ 22#define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */
22#define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ 23#define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */
23#define jump_insn_encode(op_code, addr) \
24 ((unsigned int)((op_code) | (((addr) >> 2) & ADDR_MASK)))
25 24
26#define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */ 25#define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */
27#define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */ 26#define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */
28#define INSN_NOP 0x00000000 /* nop */ 27#define INSN_NOP 0x00000000 /* nop */
29#define INSN_JAL(addr) jump_insn_encode(JAL, addr) 28#define INSN_JAL(addr) \
29 ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK)))
30
31static unsigned int insn_jal_ftrace_caller __read_mostly;
32static unsigned int insn_lui_v1_hi16_mcount __read_mostly;
33static unsigned int insn_j_ftrace_graph_caller __maybe_unused __read_mostly;
34
35static inline void ftrace_dyn_arch_init_insns(void)
36{
37 u32 *buf;
38 unsigned int v1;
39
40 /* lui v1, hi16_mcount */
41 v1 = 3;
42 buf = (u32 *)&insn_lui_v1_hi16_mcount;
43 UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR);
44
45 /* jal (ftrace_caller + 8), jump over the first two instruction */
46 buf = (u32 *)&insn_jal_ftrace_caller;
47 uasm_i_jal(&buf, (FTRACE_ADDR + 8));
48
49#ifdef CONFIG_FUNCTION_GRAPH_TRACER
50 /* j ftrace_graph_caller */
51 buf = (u32 *)&insn_j_ftrace_graph_caller;
52 uasm_i_j(&buf, (unsigned long)ftrace_graph_caller);
53#endif
54}
30 55
31static int ftrace_modify_code(unsigned long ip, unsigned int new_code) 56static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
32{ 57{
@@ -43,30 +68,20 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
43 return 0; 68 return 0;
44} 69}
45 70
46static int lui_v1;
47static int jal_mcount;
48
49int ftrace_make_nop(struct module *mod, 71int ftrace_make_nop(struct module *mod,
50 struct dyn_ftrace *rec, unsigned long addr) 72 struct dyn_ftrace *rec, unsigned long addr)
51{ 73{
52 unsigned int new; 74 unsigned int new;
53 int faulted;
54 unsigned long ip = rec->ip; 75 unsigned long ip = rec->ip;
55 76
56 /* We have compiled module with -mlong-calls, but compiled the kernel 77 /*
57 * without it, we need to cope with them respectively. */ 78 * We have compiled module with -mlong-calls, but compiled the kernel
79 * without it, we need to cope with them respectively.
80 */
58 if (ip & 0x40000000) { 81 if (ip & 0x40000000) {
59 /* record it for ftrace_make_call */
60 if (lui_v1 == 0) {
61 /* lui_v1 = *(unsigned int *)ip; */
62 safe_load_code(lui_v1, ip, faulted);
63
64 if (unlikely(faulted))
65 return -EFAULT;
66 }
67
68#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) 82#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
69 /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) 83 /*
84 * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005)
70 * addiu v1, v1, low_16bit_of_mcount 85 * addiu v1, v1, low_16bit_of_mcount
71 * move at, ra 86 * move at, ra
72 * move $12, ra_address 87 * move $12, ra_address
@@ -76,7 +91,8 @@ int ftrace_make_nop(struct module *mod,
76 */ 91 */
77 new = INSN_B_1F_5; 92 new = INSN_B_1F_5;
78#else 93#else
79 /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) 94 /*
95 * lui v1, hi_16bit_of_mcount --> b 1f (0x10000004)
80 * addiu v1, v1, low_16bit_of_mcount 96 * addiu v1, v1, low_16bit_of_mcount
81 * move at, ra 97 * move at, ra
82 * jalr v1 98 * jalr v1
@@ -86,36 +102,22 @@ int ftrace_make_nop(struct module *mod,
86 new = INSN_B_1F_4; 102 new = INSN_B_1F_4;
87#endif 103#endif
88 } else { 104 } else {
89 /* record/calculate it for ftrace_make_call */ 105 /*
90 if (jal_mcount == 0) { 106 * move at, ra
91 /* We can record it directly like this: 107 * jal _mcount --> nop
92 * jal_mcount = *(unsigned int *)ip;
93 * Herein, jump over the first two nop instructions */
94 jal_mcount = INSN_JAL(MCOUNT_ADDR + 8);
95 }
96
97 /* move at, ra
98 * jalr v1 --> nop
99 */ 108 */
100 new = INSN_NOP; 109 new = INSN_NOP;
101 } 110 }
102 return ftrace_modify_code(ip, new); 111 return ftrace_modify_code(ip, new);
103} 112}
104 113
105static int modified; /* initialized as 0 by default */
106
107int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 114int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
108{ 115{
109 unsigned int new; 116 unsigned int new;
110 unsigned long ip = rec->ip; 117 unsigned long ip = rec->ip;
111 118
112 /* We just need to remove the "b ftrace_stub" at the fist time! */
113 if (modified == 0) {
114 modified = 1;
115 ftrace_modify_code(addr, INSN_NOP);
116 }
117 /* ip, module: 0xc0000000, kernel: 0x80000000 */ 119 /* ip, module: 0xc0000000, kernel: 0x80000000 */
118 new = (ip & 0x40000000) ? lui_v1 : jal_mcount; 120 new = (ip & 0x40000000) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller;
119 121
120 return ftrace_modify_code(ip, new); 122 return ftrace_modify_code(ip, new);
121} 123}
@@ -133,6 +135,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
133 135
134int __init ftrace_dyn_arch_init(void *data) 136int __init ftrace_dyn_arch_init(void *data)
135{ 137{
138 /* Encode the instructions when booting */
139 ftrace_dyn_arch_init_insns();
140
141 /* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */
142 ftrace_modify_code(MCOUNT_ADDR, INSN_NOP);
143
136 /* The return code is retured via data */ 144 /* The return code is retured via data */
137 *(unsigned long *)data = 0; 145 *(unsigned long *)data = 0;
138 146
@@ -145,15 +153,12 @@ int __init ftrace_dyn_arch_init(void *data)
145#ifdef CONFIG_DYNAMIC_FTRACE 153#ifdef CONFIG_DYNAMIC_FTRACE
146 154
147extern void ftrace_graph_call(void); 155extern void ftrace_graph_call(void);
148#define JMP 0x08000000 /* jump to target directly */
149#define CALL_FTRACE_GRAPH_CALLER \
150 jump_insn_encode(JMP, (unsigned long)(&ftrace_graph_caller))
151#define FTRACE_GRAPH_CALL_IP ((unsigned long)(&ftrace_graph_call)) 156#define FTRACE_GRAPH_CALL_IP ((unsigned long)(&ftrace_graph_call))
152 157
153int ftrace_enable_ftrace_graph_caller(void) 158int ftrace_enable_ftrace_graph_caller(void)
154{ 159{
155 return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, 160 return ftrace_modify_code(FTRACE_GRAPH_CALL_IP,
156 CALL_FTRACE_GRAPH_CALLER); 161 insn_j_ftrace_graph_caller);
157} 162}
158 163
159int ftrace_disable_ftrace_graph_caller(void) 164int ftrace_disable_ftrace_graph_caller(void)