aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/hvCall_inst.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2009-10-26 14:50:29 -0400
committerPaul Mackerras <paulus@samba.org>2009-10-28 01:13:04 -0400
commitc8cd093a6e9f96ea6b871576fd4e46d7c818bb89 (patch)
tree2bad2c3a2cc68a35fb93d986a49bf543efcd0156 /arch/powerpc/platforms/pseries/hvCall_inst.c
parent6795b85c6a4f690e61e7be31aa150d945c723fb5 (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.c37
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
30DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats); 31DEFINE_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
105static 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
117static 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
103static int __init hcall_inst_init(void) 132static 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;