diff options
author | Anton Blanchard <anton@samba.org> | 2009-10-26 14:50:29 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2009-10-28 01:13:04 -0400 |
commit | c8cd093a6e9f96ea6b871576fd4e46d7c818bb89 (patch) | |
tree | 2bad2c3a2cc68a35fb93d986a49bf543efcd0156 /arch/powerpc/platforms/pseries/hvCall_inst.c | |
parent | 6795b85c6a4f690e61e7be31aa150d945c723fb5 (diff) |
powerpc: tracing: Add hypervisor call tracepoints
Add hcall_entry and hcall_exit tracepoints. This replaces the inline
assembly HCALL_STATS code and converts it to use the new tracepoints.
To keep the disabled case as quick as possible, we embed a status word
in the TOC so we can get at it with a single load. By doing so we
keep the overhead at a minimum. Time taken for a null hcall:
No tracepoint code: 135.79 cycles
Disabled tracepoints: 137.95 cycles
For reference, before this patch enabling HCALL_STATS resulted in a null
hcall of 201.44 cycles!
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries/hvCall_inst.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/hvCall_inst.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 3631a4f277eb..e44e1035f133 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/hvcall.h> | 26 | #include <asm/hvcall.h> |
27 | #include <asm/firmware.h> | 27 | #include <asm/firmware.h> |
28 | #include <asm/cputable.h> | 28 | #include <asm/cputable.h> |
29 | #include <asm/trace.h> | ||
29 | 30 | ||
30 | DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats); | 31 | DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats); |
31 | 32 | ||
@@ -100,6 +101,34 @@ static const struct file_operations hcall_inst_seq_fops = { | |||
100 | #define HCALL_ROOT_DIR "hcall_inst" | 101 | #define HCALL_ROOT_DIR "hcall_inst" |
101 | #define CPU_NAME_BUF_SIZE 32 | 102 | #define CPU_NAME_BUF_SIZE 32 |
102 | 103 | ||
104 | |||
105 | static void probe_hcall_entry(unsigned long opcode) | ||
106 | { | ||
107 | struct hcall_stats *h; | ||
108 | |||
109 | if (opcode > MAX_HCALL_OPCODE) | ||
110 | return; | ||
111 | |||
112 | h = &get_cpu_var(hcall_stats)[opcode / 4]; | ||
113 | h->tb_start = mftb(); | ||
114 | h->purr_start = mfspr(SPRN_PURR); | ||
115 | } | ||
116 | |||
117 | static void probe_hcall_exit(unsigned long opcode, unsigned long retval) | ||
118 | { | ||
119 | struct hcall_stats *h; | ||
120 | |||
121 | if (opcode > MAX_HCALL_OPCODE) | ||
122 | return; | ||
123 | |||
124 | h = &__get_cpu_var(hcall_stats)[opcode / 4]; | ||
125 | h->num_calls++; | ||
126 | h->tb_total = mftb() - h->tb_start; | ||
127 | h->purr_total = mfspr(SPRN_PURR) - h->purr_start; | ||
128 | |||
129 | put_cpu_var(hcall_stats); | ||
130 | } | ||
131 | |||
103 | static int __init hcall_inst_init(void) | 132 | static int __init hcall_inst_init(void) |
104 | { | 133 | { |
105 | struct dentry *hcall_root; | 134 | struct dentry *hcall_root; |
@@ -110,6 +139,14 @@ static int __init hcall_inst_init(void) | |||
110 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | 139 | if (!firmware_has_feature(FW_FEATURE_LPAR)) |
111 | return 0; | 140 | return 0; |
112 | 141 | ||
142 | if (register_trace_hcall_entry(probe_hcall_entry)) | ||
143 | return -EINVAL; | ||
144 | |||
145 | if (register_trace_hcall_exit(probe_hcall_exit)) { | ||
146 | unregister_trace_hcall_entry(probe_hcall_entry); | ||
147 | return -EINVAL; | ||
148 | } | ||
149 | |||
113 | hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL); | 150 | hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL); |
114 | if (!hcall_root) | 151 | if (!hcall_root) |
115 | return -ENOMEM; | 152 | return -ENOMEM; |