linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files
  2006-06-22 22:56 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
@ 2006-06-22 23:00 ` Mike Kravetz
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-06-22 23:00 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Bryan Rosenburg, Christopher Yeoh, Nathan Lynch, Arnd Bergmann

Make statistics available via files in debugfs.

--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

diff -Naupr linux-2.6.17.1/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.1.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.1/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-06-22 23:02:50.000000000 +0000
+++ linux-2.6.17.1.work/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-06-22 23:03:55.000000000 +0000
@@ -217,3 +217,94 @@ long plpar_hcall_9arg_9ret(unsigned long
 	preempt_enable();
 	return rc;
 }
+
+/*
+ * Routines for displaying the statistics in debugfs
+ */
+static void *hc_start(struct seq_file *m, loff_t *pos)
+{
+	if ((int)*pos < MAX_HCALL_OPCODES)
+		return (void *)(unsigned long)(*pos + 1);
+
+	return NULL;
+}
+
+static void *hc_next(struct seq_file *m, void *p, loff_t * pos)
+{
+	++*pos;
+
+	return hc_start(m, pos);
+}
+
+static void hc_stop(struct seq_file *m, void *p)
+{
+}
+
+static int hc_show(struct seq_file *m, void *p)
+{
+	unsigned long h_num = (unsigned long)p;
+	struct hcall_stats *hs = (struct hcall_stats *)m->private;
+
+	if (hs[h_num].num_calls)
+		seq_printf(m, "%lu %lu %lu\n", h_num<<2, hs[h_num].num_calls,
+			   hs[h_num].total_time);
+
+	return 0;
+}
+
+static struct seq_operations hcall_inst_seq_ops = {
+        .start = hc_start,
+        .next  = hc_next,
+        .stop  = hc_stop,
+        .show  = hc_show
+};
+
+static int hcall_inst_seq_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct seq_file *seq;
+
+	rc = seq_open(file, &hcall_inst_seq_ops);
+	seq = file->private_data;
+	seq->private = file->f_dentry->d_inode->u.generic_ip;
+
+	return rc;
+}
+
+static struct file_operations hcall_inst_seq_fops = {
+	.open = hcall_inst_seq_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+#define	HCALL_ROOT_DIR		"hcall_inst"
+#define CPU_NAME_BUF_SIZE	32
+
+static int __init hcall_inst_init(void)
+{
+	struct dentry *hcall_root;
+	struct dentry *hcall_file;
+	char cpu_name_buf[CPU_NAME_BUF_SIZE];
+	int cpu;
+
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		return 0;
+
+	hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
+	if (!hcall_root)
+		return -ENOMEM;
+
+	for_each_cpu(cpu) {
+		snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
+		hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,
+						 hcall_root,
+						 per_cpu(hcall_stats, cpu),
+						 &hcall_inst_seq_fops);
+		if (!hcall_file)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+__initcall(hcall_inst_init);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files
  2006-07-14 23:37 Mike Kravetz
@ 2006-07-14 23:41 ` Mike Kravetz
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-14 23:41 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: Arnd Bergmann, Bryan Rosenburg, linuxppc-dev, Nathan Lynch,
	Christopher Yeoh

Make statistics available via files in debugfs.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

diff -Naupr linux-2.6.17.4/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.4.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.4/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-14 23:32:01.000000000 +0000
+++ linux-2.6.17.4.work/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-14 23:32:54.000000000 +0000
@@ -205,3 +205,94 @@ long plpar_hcall_9arg_9ret(unsigned long
 	update_stats(opcode, t_before);
 	return rc;
 }
+
+/*
+ * Routines for displaying the statistics in debugfs
+ */
+static void *hc_start(struct seq_file *m, loff_t *pos)
+{
+	if ((int)*pos < MAX_HCALL_OPCODES)
+		return (void *)(unsigned long)(*pos + 1);
+
+	return NULL;
+}
+
+static void *hc_next(struct seq_file *m, void *p, loff_t * pos)
+{
+	++*pos;
+
+	return hc_start(m, pos);
+}
+
+static void hc_stop(struct seq_file *m, void *p)
+{
+}
+
+static int hc_show(struct seq_file *m, void *p)
+{
+	unsigned long h_num = (unsigned long)p;
+	struct hcall_stats *hs = (struct hcall_stats *)m->private;
+
+	if (hs[h_num].num_calls)
+		seq_printf(m, "%lu %lu %lu\n", h_num<<2, hs[h_num].num_calls,
+			   hs[h_num].total_time);
+
+	return 0;
+}
+
+static struct seq_operations hcall_inst_seq_ops = {
+        .start = hc_start,
+        .next  = hc_next,
+        .stop  = hc_stop,
+        .show  = hc_show
+};
+
+static int hcall_inst_seq_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct seq_file *seq;
+
+	rc = seq_open(file, &hcall_inst_seq_ops);
+	seq = file->private_data;
+	seq->private = file->f_dentry->d_inode->u.generic_ip;
+
+	return rc;
+}
+
+static struct file_operations hcall_inst_seq_fops = {
+	.open = hcall_inst_seq_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+#define	HCALL_ROOT_DIR		"hcall_inst"
+#define CPU_NAME_BUF_SIZE	32
+
+static int __init hcall_inst_init(void)
+{
+	struct dentry *hcall_root;
+	struct dentry *hcall_file;
+	char cpu_name_buf[CPU_NAME_BUF_SIZE];
+	int cpu;
+
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		return 0;
+
+	hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
+	if (!hcall_root)
+		return -ENOMEM;
+
+	for_each_cpu(cpu) {
+		snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
+		hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,
+						 hcall_root,
+						 per_cpu(hcall_stats, cpu),
+						 &hcall_inst_seq_fops);
+		if (!hcall_file)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+__initcall(hcall_inst_init);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 0/3] powerpc: Instrument Hypervisor Calls
@ 2006-07-18 20:47 Mike Kravetz
  2006-07-18 20:48 ` [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers Mike Kravetz
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 20:47 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

A small update from the last version.  By popular demand, both
wall time (mftb) and cpu cycles(PURR) are collected for each call.
It is interesting to see these two values side by side in the
output files.

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers
  2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
@ 2006-07-18 20:48 ` Mike Kravetz
  2006-07-18 20:49 ` [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers Mike Kravetz
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 20:48 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Move all the Hypervisor call definitions to to a single header file.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

diff -Naupr linux-2.6.17.6/drivers/net/ibmveth.h linux-2.6.17.6.work/drivers/net/ibmveth.h
--- linux-2.6.17.6/drivers/net/ibmveth.h	2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/drivers/net/ibmveth.h	2006-07-18 19:33:47.000000000 +0000
@@ -41,16 +41,6 @@
 #define IbmVethMcastRemoveFilter     0x2UL
 #define IbmVethMcastClearFilterTable 0x3UL
 
-/* hcall numbers */
-#define H_VIO_SIGNAL             0x104
-#define H_REGISTER_LOGICAL_LAN   0x114
-#define H_FREE_LOGICAL_LAN       0x118
-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
-#define H_SEND_LOGICAL_LAN       0x120
-#define H_MULTICAST_CTRL         0x130
-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
-
 /* hcall macros */
 #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
   plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
--- linux-2.6.17.6/include/asm-powerpc/hvcall.h	2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h	2006-07-18 19:33:47.000000000 +0000
@@ -155,9 +155,15 @@
 #define H_VIO_SIGNAL		0x104
 #define H_SEND_CRQ		0x108
 #define H_COPY_RDMA		0x110
+#define H_REGISTER_LOGICAL_LAN	0x114
+#define H_FREE_LOGICAL_LAN	0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN	0x120
+#define H_MULTICAST_CTRL	0x130
 #define H_SET_XDABR		0x134
 #define H_STUFF_TCE		0x138
 #define H_PUT_TCE_INDIRECT	0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
 #define H_VTERM_PARTNER_INFO	0x150
 #define H_REGISTER_VTERM	0x154
 #define H_FREE_VTERM		0x158
@@ -187,11 +193,14 @@
 #define H_GET_HCA_INFO          0x1B8
 #define H_GET_PERF_COUNT        0x1BC
 #define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
 #define H_QUERY_INT_STATE       0x1E4
 #define H_POLL_PENDING		0x1D8
 #define H_JOIN			0x298
 #define H_ENABLE_CRQ		0x2B0
 
+#define MAX_HCALL_OPCODES	(H_ENABLE_CRQ >> 2)
+
 #ifndef __ASSEMBLY__
 
 /* plpar_hcall() -- Generic call interface using above opcodes

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
  2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
  2006-07-18 20:48 ` [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers Mike Kravetz
@ 2006-07-18 20:49 ` Mike Kravetz
  2006-07-18 22:34   ` Olof Johansson
  2006-07-18 20:50 ` [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files Mike Kravetz
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 20:49 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Add wrappers which perform the actual hypervisor call instrumentation.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

diff -Naupr linux-2.6.17.6/arch/powerpc/Kconfig.debug linux-2.6.17.6.work/arch/powerpc/Kconfig.debug
--- linux-2.6.17.6/arch/powerpc/Kconfig.debug	2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/Kconfig.debug	2006-07-18 19:56:20.000000000 +0000
@@ -18,6 +18,20 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
+config HCALL_STATS
+	bool "Hypervisor call instrumentation"
+	depends on PPC_PSERIES && DEBUG_FS
+	help
+	  Adds code to keep track of the number of hypervisor calls made and
+	  the amount of time spent in hypervisor calls: both wall time (based
+	  on time base) and cpu time (based on PURR).  A directory named
+	  hcall_inst is added at the root of the debugfs filesystem.  Within
+	  the hcall_inst directory are files that contain CPU specific call
+	  statistics.
+
+	  This option will add a small amount of overhead to all hypervisor
+	  calls.
+
 config DEBUGGER
 	bool "Enable debugger hooks"
 	depends on DEBUG_KERNEL
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile	2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile	2006-07-18 19:56:20.000000000 +0000
@@ -9,3 +9,4 @@ obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o e
 
 obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
 obj-$(CONFIG_HVCS)		+= hvcserver.o
+obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S	2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S	2006-07-18 19:56:20.000000000 +0000
@@ -11,7 +11,35 @@
 #include <asm/hvcall.h>
 #include <asm/processor.h>
 #include <asm/ppc_asm.h>
-	
+
+/*
+ * If hcall statistics are desired, all routines are wrapped with code
+ * that does the statistic gathering.
+ */
+#ifndef CONFIG_HCALL_STATS
+#define PLPAR_HCALL		plpar_hcall
+#define PLPAR_HCALL_NORETS	plpar_hcall_norets
+#define PLPAR_HCALL_8ARG_2RET	plpar_hcall_8arg_2ret
+#define PLPAR_HCALL_4OUT	plpar_hcall_4out
+#define PLPAR_HCALL_7ARG_7RET	plpar_hcall_7arg_7ret
+#define PLPAR_HCALL_9ARG_9RET	plpar_hcall_9arg_9ret
+#else
+#define PLPAR_HCALL		plpar_hcall_base
+#define PLPAR_HCALL_NORETS	plpar_hcall_norets_base
+#define PLPAR_HCALL_8ARG_2RET	plpar_hcall_8arg_2ret_base
+#define PLPAR_HCALL_4OUT	plpar_hcall_4out_base
+#define PLPAR_HCALL_7ARG_7RET	plpar_hcall_7arg_7ret_base
+#define PLPAR_HCALL_9ARG_9RET	plpar_hcall_9arg_9ret_base
+
+/*
+ * A special 'indirect' call to a C based wrapper if statistics are desired.
+ * See plpar_hcall_norets_C function header for more details.
+ */
+_GLOBAL(plpar_hcall_norets)
+	b	plpar_hcall_norets_C
+
+#endif
+
 #define STK_PARM(i)     (48 + ((i)-3)*8)
 
 	.text
@@ -25,7 +53,7 @@
 			unsigned long *out2,		R9
 			unsigned long *out3);		R10
  */
-_GLOBAL(plpar_hcall)
+_GLOBAL(PLPAR_HCALL)
 	HMT_MEDIUM
 
 	mfcr	r0
@@ -52,7 +80,7 @@ _GLOBAL(plpar_hcall)
 
 
 /* Simple interface with no output values (other than status) */
-_GLOBAL(plpar_hcall_norets)
+_GLOBAL(PLPAR_HCALL_NORETS)
 	HMT_MEDIUM
 
 	mfcr	r0
@@ -76,7 +104,7 @@ _GLOBAL(plpar_hcall_norets)
 			unsigned long arg8,		112(R1)
 			unsigned long *out1);		120(R1)
  */
-_GLOBAL(plpar_hcall_8arg_2ret)
+_GLOBAL(PLPAR_HCALL_8ARG_2RET)
 	HMT_MEDIUM
 
 	mfcr	r0
@@ -102,7 +130,7 @@ _GLOBAL(plpar_hcall_8arg_2ret)
 		 	unsigned long *out3,		R10
 		 	unsigned long *out4);		112(R1)
  */
-_GLOBAL(plpar_hcall_4out)
+_GLOBAL(PLPAR_HCALL_4OUT)
 	HMT_MEDIUM
 
 	mfcr	r0
@@ -144,7 +172,7 @@ _GLOBAL(plpar_hcall_4out)
 			 unsigned long *out6,		102(R1)
 			 unsigned long *out7);		100(R1)
 */
-_GLOBAL(plpar_hcall_7arg_7ret)
+_GLOBAL(PLPAR_HCALL_7ARG_7RET)
 	HMT_MEDIUM
 
 	mfcr	r0
@@ -193,7 +221,7 @@ _GLOBAL(plpar_hcall_7arg_7ret)
 			 unsigned long *out8,		 94(R1)
 		         unsigned long *out9,            92(R1)
 */
-_GLOBAL(plpar_hcall_9arg_9ret)
+_GLOBAL(PLPAR_HCALL_9ARG_9RET)
 	HMT_MEDIUM
 
 	mfcr	r0
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-18 19:57:44.000000000 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2006 Mike Kravetz IBM Corporation
+ *
+ * Hypervisor Call Instrumentation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
+#include <asm/hvcall.h>
+#include <asm/firmware.h>
+
+DEFINE_PER_CPU(struct hcall_stats[MAX_HCALL_OPCODES+1], hcall_stats);
+
+/*
+ * Common update of the per-CPU/per-hcall statistics
+ */
+static inline void update_stats(unsigned long opcode,
+				unsigned long t_tb_before,
+				unsigned long t_cpu_before)
+{
+	unsigned long op_index = opcode >> 2;
+	struct hcall_stats *hs = &__get_cpu_var(hcall_stats[op_index]);
+
+	hs->tb_total += (mftb() - t_tb_before);
+	hs->cpu_total += (mfspr(SPRN_PURR) - t_cpu_before);
+	hs->num_calls++;
+}
+
+/*
+ * plpar_hcall wrapper
+ */
+long plpar_hcall(unsigned long opcode,
+                 unsigned long arg1,
+                 unsigned long arg2,
+                 unsigned long arg3,
+                 unsigned long arg4,
+                 unsigned long *out1,
+                 unsigned long *out2,
+                 unsigned long *out3)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_base(opcode, arg1, arg2, arg3, arg4, out1, out2, out3);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
+
+/*
+ * A C based wrapper for plpar_hcall_norets
+ * The wrapper for plpar_hcall_norets is a special case because the function
+ * takes a variable number of arguments.  It is almost impossible to write a
+ * wrapper for a function that takes a variable number of arguments in C.
+ * Therefore, there is an assembly routine in hvCall.S that simply branches
+ * to this C wrapper.  This 'indirection' takes care of the variable arguments
+ * issue.  This C wrapper has a fixed maximum number of arguments.
+ */
+long plpar_hcall_norets_C(unsigned long opcode,
+				unsigned long arg1,
+				unsigned long arg2,
+				unsigned long arg3,
+				unsigned long arg4,
+				unsigned long arg5,
+				unsigned long arg6)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_norets_base(opcode, arg1, arg2, arg3, arg4, arg5,
+				     arg6);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
+
+/*
+ * plpar_hcall_8arg_2ret wrapper
+ */
+long plpar_hcall_8arg_2ret(unsigned long opcode,
+                           unsigned long arg1,
+                           unsigned long arg2,
+                           unsigned long arg3,
+                           unsigned long arg4,
+                           unsigned long arg5,
+                           unsigned long arg6,
+                           unsigned long arg7,
+                           unsigned long arg8,
+                           unsigned long *out1)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_8arg_2ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+					arg6, arg7, arg8, out1);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
+
+/*
+ * plpar_hcall_4out wrapper
+ */
+long plpar_hcall_4out(unsigned long opcode,
+                      unsigned long arg1,
+                      unsigned long arg2,
+                      unsigned long arg3,
+                      unsigned long arg4,
+                      unsigned long *out1,
+                      unsigned long *out2,
+                      unsigned long *out3,
+                      unsigned long *out4)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_4out_base(opcode, arg1, arg2, arg3, arg4, out1,
+				   out2, out3, out4);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
+
+/*
+ * plpar_hcall_7arg_7ret wrapper
+ */
+long plpar_hcall_7arg_7ret(unsigned long opcode,
+                           unsigned long arg1,
+                           unsigned long arg2,
+                           unsigned long arg3,
+                           unsigned long arg4,
+                           unsigned long arg5,
+                           unsigned long arg6,
+                           unsigned long arg7,
+                           unsigned long *out1,
+                           unsigned long *out2,
+                           unsigned long *out3,
+                           unsigned long *out4,
+                           unsigned long *out5,
+                           unsigned long *out6,
+                           unsigned long *out7)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_7arg_7ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+					arg6, arg7, out1, out2, out3, out4,
+					out5, out6, out7);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
+
+/*
+ * plpar_hcall_9arg_9ret wrapper
+ */
+long plpar_hcall_9arg_9ret(unsigned long opcode,
+                           unsigned long arg1,
+                           unsigned long arg2,
+                           unsigned long arg3,
+                           unsigned long arg4,
+                           unsigned long arg5,
+                           unsigned long arg6,
+                           unsigned long arg7,
+                           unsigned long arg8,
+                           unsigned long arg9,
+                           unsigned long *out1,
+                           unsigned long *out2,
+                           unsigned long *out3,
+                           unsigned long *out4,
+                           unsigned long *out5,
+                           unsigned long *out6,
+                           unsigned long *out7,
+                           unsigned long *out8,
+                           unsigned long *out9)
+{
+	long rc;
+	unsigned long t_tb_before, t_cpu_before;
+
+	t_tb_before = mftb();
+	t_cpu_before = mfspr(SPRN_PURR);
+	rc = plpar_hcall_9arg_9ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+					arg6, arg7, arg8, arg9, out1, out2,
+					out3, out4, out5, out6, out7, out8,
+					out9);
+
+	update_stats(opcode, t_tb_before, t_cpu_before);
+	return rc;
+}
diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
--- linux-2.6.17.6/include/asm-powerpc/hvcall.h	2006-07-18 19:35:00.000000000 +0000
+++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h	2006-07-18 19:56:20.000000000 +0000
@@ -292,6 +292,87 @@ long plpar_hcall_9arg_9ret(unsigned long
 			   unsigned long *out8,
 			   unsigned long *out9);
 
+
+/* For hcall instrumentation.  One structure per-hcall, per-CPU */
+struct hcall_stats {
+	unsigned long	num_calls;	/* number of calls (on this CPU) */
+	unsigned long	tb_total;	/* total wall time (mftb) of calls. */
+	unsigned long	cpu_total;	/* total cpu time (PURR) of calls. */
+};
+
+/* If Hypervisor call instrumentation is enabled, the assembly routine
+ * names are changed from 'plpar_hcall*' to 'plpar_hcall*_base' and
+ * 'plpar_hcall*' routines become instrumented wrappers.  The following
+ * are declarations for the renamed 'plpar_hcall*_base' routines.
+ */
+long plpar_hcall_base (unsigned long opcode,
+		       unsigned long arg1,
+		       unsigned long arg2,
+		       unsigned long arg3,
+		       unsigned long arg4,
+		       unsigned long *out1,
+		       unsigned long *out2,
+		       unsigned long *out3);
+
+long plpar_hcall_norets_base(unsigned long opcode, ...);
+
+long plpar_hcall_8arg_2ret_base(unsigned long opcode,
+				unsigned long arg1,
+				unsigned long arg2,
+				unsigned long arg3,
+				unsigned long arg4,
+				unsigned long arg5,
+				unsigned long arg6,
+				unsigned long arg7,
+				unsigned long arg8,
+				unsigned long *out1);
+
+long plpar_hcall_4out_base(unsigned long opcode,
+			   unsigned long arg1,
+			   unsigned long arg2,
+			   unsigned long arg3,
+			   unsigned long arg4,
+			   unsigned long *out1,
+			   unsigned long *out2,
+			   unsigned long *out3,
+			   unsigned long *out4);
+
+long plpar_hcall_7arg_7ret_base(unsigned long opcode,
+				unsigned long arg1,
+				unsigned long arg2,
+				unsigned long arg3,
+				unsigned long arg4,
+				unsigned long arg5,
+				unsigned long arg6,
+				unsigned long arg7,
+				unsigned long *out1,
+				unsigned long *out2,
+				unsigned long *out3,
+				unsigned long *out4,
+				unsigned long *out5,
+				unsigned long *out6,
+				unsigned long *out7);
+
+long plpar_hcall_9arg_9ret_base(unsigned long opcode,
+				unsigned long arg1,
+				unsigned long arg2,
+				unsigned long arg3,
+				unsigned long arg4,
+				unsigned long arg5,
+				unsigned long arg6,
+				unsigned long arg7,
+				unsigned long arg8,
+				unsigned long arg9,
+				unsigned long *out1,
+				unsigned long *out2,
+				unsigned long *out3,
+				unsigned long *out4,
+				unsigned long *out5,
+				unsigned long *out6,
+				unsigned long *out7,
+				unsigned long *out8,
+				unsigned long *out9);
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files
  2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
  2006-07-18 20:48 ` [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers Mike Kravetz
  2006-07-18 20:49 ` [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers Mike Kravetz
@ 2006-07-18 20:50 ` Mike Kravetz
  2006-07-18 21:00 ` [PATCH 0/3] powerpc: Instrument Hypervisor Calls Paul Mackerras
  2006-07-18 21:29 ` Mike Kravetz
  4 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 20:50 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Make statistics available via files in debugfs.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-18 20:02:21.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-18 20:03:32.000000000 +0000
@@ -214,3 +214,96 @@ long plpar_hcall_9arg_9ret(unsigned long
 	update_stats(opcode, t_tb_before, t_cpu_before);
 	return rc;
 }
+
+/*
+ * Routines for displaying the statistics in debugfs
+ */
+static void *hc_start(struct seq_file *m, loff_t *pos)
+{
+	if ((int)*pos < MAX_HCALL_OPCODES)
+		return (void *)(unsigned long)(*pos + 1);
+
+	return NULL;
+}
+
+static void *hc_next(struct seq_file *m, void *p, loff_t * pos)
+{
+	++*pos;
+
+	return hc_start(m, pos);
+}
+
+static void hc_stop(struct seq_file *m, void *p)
+{
+}
+
+static int hc_show(struct seq_file *m, void *p)
+{
+	unsigned long h_num = (unsigned long)p;
+	struct hcall_stats *hs = (struct hcall_stats *)m->private;
+
+	if (hs[h_num].num_calls)
+		seq_printf(m, "%lu %lu %lu %lu\n", h_num<<2,
+			   hs[h_num].num_calls,
+			   hs[h_num].tb_total,
+			   hs[h_num].cpu_total);
+
+	return 0;
+}
+
+static struct seq_operations hcall_inst_seq_ops = {
+        .start = hc_start,
+        .next  = hc_next,
+        .stop  = hc_stop,
+        .show  = hc_show
+};
+
+static int hcall_inst_seq_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct seq_file *seq;
+
+	rc = seq_open(file, &hcall_inst_seq_ops);
+	seq = file->private_data;
+	seq->private = file->f_dentry->d_inode->u.generic_ip;
+
+	return rc;
+}
+
+static struct file_operations hcall_inst_seq_fops = {
+	.open = hcall_inst_seq_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+#define	HCALL_ROOT_DIR		"hcall_inst"
+#define CPU_NAME_BUF_SIZE	32
+
+static int __init hcall_inst_init(void)
+{
+	struct dentry *hcall_root;
+	struct dentry *hcall_file;
+	char cpu_name_buf[CPU_NAME_BUF_SIZE];
+	int cpu;
+
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		return 0;
+
+	hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
+	if (!hcall_root)
+		return -ENOMEM;
+
+	for_each_cpu(cpu) {
+		snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
+		hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,
+						 hcall_root,
+						 per_cpu(hcall_stats, cpu),
+						 &hcall_inst_seq_fops);
+		if (!hcall_file)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+__initcall(hcall_inst_init);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
  2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
                   ` (2 preceding siblings ...)
  2006-07-18 20:50 ` [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files Mike Kravetz
@ 2006-07-18 21:00 ` Paul Mackerras
  2006-07-19  3:36   ` Mike Kravetz
  2006-07-18 21:29 ` Mike Kravetz
  4 siblings, 1 reply; 15+ messages in thread
From: Paul Mackerras @ 2006-07-18 21:00 UTC (permalink / raw)
  To: Mike Kravetz; +Cc: linuxppc-dev

Mike Kravetz writes:

> A small update from the last version.  By popular demand, both
> wall time (mftb) and cpu cycles(PURR) are collected for each call.
> It is interesting to see these two values side by side in the
> output files.

Did you see the patch from Anton that I posted a week or so ago, which
reduces the number of plpar_hcall_* functions?  I'd rather the
instrumentation stuff was based on that.

My other comment is this: wouldn't it actually turn out simpler if we
read the timebase (and PURR, if we really want to do that too) in the
assembly code that implements plpar_hcall_*?

Paul.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
  2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
                   ` (3 preceding siblings ...)
  2006-07-18 21:00 ` [PATCH 0/3] powerpc: Instrument Hypervisor Calls Paul Mackerras
@ 2006-07-18 21:29 ` Mike Kravetz
  2006-07-18 22:38   ` Olof Johansson
  4 siblings, 1 reply; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 21:29 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

On Tue, Jul 18, 2006 at 01:47:23PM -0700, Mike Kravetz wrote:
> A small update from the last version.  By popular demand, both
> wall time (mftb) and cpu cycles(PURR) are collected for each call.
> It is interesting to see these two values side by side in the
> output files.

Arnd asked on IRC, so I thought others may be interested in a
sample output file.  Remember, there is one file per CPU. All
values are decimal.  First number is hcall # (in decimal), second
is number of calls, third is total time (mftb) and fourth is cpu
time (PURR).  Note that 'total times' are still in cycles and
can be converted to another format in user space.

[elm3b125]/sys/kernel/debug/hcall_inst >cat cpu0
4 140651 21538230 14456409
8 130064 11855094 9459178
24 14259 1496316 986702
32 1809 354584 315399
84 103 27196 17763
88 1046 108106 109322
100 2596 251229 205154
104 1 1040 1061
108 2208 320491 242708
116 2669 1030894 713272
220 2 532 510
224 130662 47508588184 169383891
228 5 2689902 4622
260 3018 261893 230753

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
  2006-07-18 20:49 ` [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers Mike Kravetz
@ 2006-07-18 22:34   ` Olof Johansson
  2006-07-18 23:18     ` Mike Kravetz
  0 siblings, 1 reply; 15+ messages in thread
From: Olof Johansson @ 2006-07-18 22:34 UTC (permalink / raw)
  To: Mike Kravetz; +Cc: linuxppc-dev, Paul Mackerras

On Tue, Jul 18, 2006 at 01:49:46PM -0700, Mike Kravetz wrote:
> Add wrappers which perform the actual hypervisor call instrumentation.
> --
> Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>

NACK.

As I said before, SPRN_PURR doesn't exist on all architecture versions
that supports hypervisor mode. Try booting on a JS20/21 or a POWER4
machine in LPAR mode and you'll see. (Unfortunately I don't have access
to any such hardware myself, so I can't send you oops output to show it).


-Olof

> diff -Naupr linux-2.6.17.6/arch/powerpc/Kconfig.debug linux-2.6.17.6.work/arch/powerpc/Kconfig.debug
> --- linux-2.6.17.6/arch/powerpc/Kconfig.debug	2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/Kconfig.debug	2006-07-18 19:56:20.000000000 +0000
> @@ -18,6 +18,20 @@ config DEBUG_STACK_USAGE
>  
>  	  This option will slow down process creation somewhat.
>  
> +config HCALL_STATS
> +	bool "Hypervisor call instrumentation"
> +	depends on PPC_PSERIES && DEBUG_FS
> +	help
> +	  Adds code to keep track of the number of hypervisor calls made and
> +	  the amount of time spent in hypervisor calls: both wall time (based
> +	  on time base) and cpu time (based on PURR).  A directory named
> +	  hcall_inst is added at the root of the debugfs filesystem.  Within
> +	  the hcall_inst directory are files that contain CPU specific call
> +	  statistics.
> +
> +	  This option will add a small amount of overhead to all hypervisor
> +	  calls.
> +
>  config DEBUGGER
>  	bool "Enable debugger hooks"
>  	depends on DEBUG_KERNEL
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile	2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile	2006-07-18 19:56:20.000000000 +0000
> @@ -9,3 +9,4 @@ obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o e
>  
>  obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
>  obj-$(CONFIG_HVCS)		+= hvcserver.o
> +obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S	2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S	2006-07-18 19:56:20.000000000 +0000
> @@ -11,7 +11,35 @@
>  #include <asm/hvcall.h>
>  #include <asm/processor.h>
>  #include <asm/ppc_asm.h>
> -	
> +
> +/*
> + * If hcall statistics are desired, all routines are wrapped with code
> + * that does the statistic gathering.
> + */
> +#ifndef CONFIG_HCALL_STATS
> +#define PLPAR_HCALL		plpar_hcall
> +#define PLPAR_HCALL_NORETS	plpar_hcall_norets
> +#define PLPAR_HCALL_8ARG_2RET	plpar_hcall_8arg_2ret
> +#define PLPAR_HCALL_4OUT	plpar_hcall_4out
> +#define PLPAR_HCALL_7ARG_7RET	plpar_hcall_7arg_7ret
> +#define PLPAR_HCALL_9ARG_9RET	plpar_hcall_9arg_9ret
> +#else
> +#define PLPAR_HCALL		plpar_hcall_base
> +#define PLPAR_HCALL_NORETS	plpar_hcall_norets_base
> +#define PLPAR_HCALL_8ARG_2RET	plpar_hcall_8arg_2ret_base
> +#define PLPAR_HCALL_4OUT	plpar_hcall_4out_base
> +#define PLPAR_HCALL_7ARG_7RET	plpar_hcall_7arg_7ret_base
> +#define PLPAR_HCALL_9ARG_9RET	plpar_hcall_9arg_9ret_base
> +
> +/*
> + * A special 'indirect' call to a C based wrapper if statistics are desired.
> + * See plpar_hcall_norets_C function header for more details.
> + */
> +_GLOBAL(plpar_hcall_norets)
> +	b	plpar_hcall_norets_C
> +
> +#endif
> +
>  #define STK_PARM(i)     (48 + ((i)-3)*8)
>  
>  	.text
> @@ -25,7 +53,7 @@
>  			unsigned long *out2,		R9
>  			unsigned long *out3);		R10
>   */
> -_GLOBAL(plpar_hcall)
> +_GLOBAL(PLPAR_HCALL)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> @@ -52,7 +80,7 @@ _GLOBAL(plpar_hcall)
>  
>  
>  /* Simple interface with no output values (other than status) */
> -_GLOBAL(plpar_hcall_norets)
> +_GLOBAL(PLPAR_HCALL_NORETS)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> @@ -76,7 +104,7 @@ _GLOBAL(plpar_hcall_norets)
>  			unsigned long arg8,		112(R1)
>  			unsigned long *out1);		120(R1)
>   */
> -_GLOBAL(plpar_hcall_8arg_2ret)
> +_GLOBAL(PLPAR_HCALL_8ARG_2RET)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> @@ -102,7 +130,7 @@ _GLOBAL(plpar_hcall_8arg_2ret)
>  		 	unsigned long *out3,		R10
>  		 	unsigned long *out4);		112(R1)
>   */
> -_GLOBAL(plpar_hcall_4out)
> +_GLOBAL(PLPAR_HCALL_4OUT)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> @@ -144,7 +172,7 @@ _GLOBAL(plpar_hcall_4out)
>  			 unsigned long *out6,		102(R1)
>  			 unsigned long *out7);		100(R1)
>  */
> -_GLOBAL(plpar_hcall_7arg_7ret)
> +_GLOBAL(PLPAR_HCALL_7ARG_7RET)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> @@ -193,7 +221,7 @@ _GLOBAL(plpar_hcall_7arg_7ret)
>  			 unsigned long *out8,		 94(R1)
>  		         unsigned long *out9,            92(R1)
>  */
> -_GLOBAL(plpar_hcall_9arg_9ret)
> +_GLOBAL(PLPAR_HCALL_9ARG_9RET)
>  	HMT_MEDIUM
>  
>  	mfcr	r0
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c	2006-07-18 19:57:44.000000000 +0000
> @@ -0,0 +1,216 @@
> +/*
> + * Copyright (C) 2006 Mike Kravetz IBM Corporation
> + *
> + * Hypervisor Call Instrumentation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/percpu.h>
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
> +#include <linux/cpumask.h>
> +#include <asm/hvcall.h>
> +#include <asm/firmware.h>
> +
> +DEFINE_PER_CPU(struct hcall_stats[MAX_HCALL_OPCODES+1], hcall_stats);
> +
> +/*
> + * Common update of the per-CPU/per-hcall statistics
> + */
> +static inline void update_stats(unsigned long opcode,
> +				unsigned long t_tb_before,
> +				unsigned long t_cpu_before)
> +{
> +	unsigned long op_index = opcode >> 2;
> +	struct hcall_stats *hs = &__get_cpu_var(hcall_stats[op_index]);
> +
> +	hs->tb_total += (mftb() - t_tb_before);
> +	hs->cpu_total += (mfspr(SPRN_PURR) - t_cpu_before);
> +	hs->num_calls++;
> +}
> +
> +/*
> + * plpar_hcall wrapper
> + */
> +long plpar_hcall(unsigned long opcode,
> +                 unsigned long arg1,
> +                 unsigned long arg2,
> +                 unsigned long arg3,
> +                 unsigned long arg4,
> +                 unsigned long *out1,
> +                 unsigned long *out2,
> +                 unsigned long *out3)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_base(opcode, arg1, arg2, arg3, arg4, out1, out2, out3);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> +
> +/*
> + * A C based wrapper for plpar_hcall_norets
> + * The wrapper for plpar_hcall_norets is a special case because the function
> + * takes a variable number of arguments.  It is almost impossible to write a
> + * wrapper for a function that takes a variable number of arguments in C.
> + * Therefore, there is an assembly routine in hvCall.S that simply branches
> + * to this C wrapper.  This 'indirection' takes care of the variable arguments
> + * issue.  This C wrapper has a fixed maximum number of arguments.
> + */
> +long plpar_hcall_norets_C(unsigned long opcode,
> +				unsigned long arg1,
> +				unsigned long arg2,
> +				unsigned long arg3,
> +				unsigned long arg4,
> +				unsigned long arg5,
> +				unsigned long arg6)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_norets_base(opcode, arg1, arg2, arg3, arg4, arg5,
> +				     arg6);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> +
> +/*
> + * plpar_hcall_8arg_2ret wrapper
> + */
> +long plpar_hcall_8arg_2ret(unsigned long opcode,
> +                           unsigned long arg1,
> +                           unsigned long arg2,
> +                           unsigned long arg3,
> +                           unsigned long arg4,
> +                           unsigned long arg5,
> +                           unsigned long arg6,
> +                           unsigned long arg7,
> +                           unsigned long arg8,
> +                           unsigned long *out1)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_8arg_2ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> +					arg6, arg7, arg8, out1);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> +
> +/*
> + * plpar_hcall_4out wrapper
> + */
> +long plpar_hcall_4out(unsigned long opcode,
> +                      unsigned long arg1,
> +                      unsigned long arg2,
> +                      unsigned long arg3,
> +                      unsigned long arg4,
> +                      unsigned long *out1,
> +                      unsigned long *out2,
> +                      unsigned long *out3,
> +                      unsigned long *out4)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_4out_base(opcode, arg1, arg2, arg3, arg4, out1,
> +				   out2, out3, out4);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> +
> +/*
> + * plpar_hcall_7arg_7ret wrapper
> + */
> +long plpar_hcall_7arg_7ret(unsigned long opcode,
> +                           unsigned long arg1,
> +                           unsigned long arg2,
> +                           unsigned long arg3,
> +                           unsigned long arg4,
> +                           unsigned long arg5,
> +                           unsigned long arg6,
> +                           unsigned long arg7,
> +                           unsigned long *out1,
> +                           unsigned long *out2,
> +                           unsigned long *out3,
> +                           unsigned long *out4,
> +                           unsigned long *out5,
> +                           unsigned long *out6,
> +                           unsigned long *out7)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_7arg_7ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> +					arg6, arg7, out1, out2, out3, out4,
> +					out5, out6, out7);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> +
> +/*
> + * plpar_hcall_9arg_9ret wrapper
> + */
> +long plpar_hcall_9arg_9ret(unsigned long opcode,
> +                           unsigned long arg1,
> +                           unsigned long arg2,
> +                           unsigned long arg3,
> +                           unsigned long arg4,
> +                           unsigned long arg5,
> +                           unsigned long arg6,
> +                           unsigned long arg7,
> +                           unsigned long arg8,
> +                           unsigned long arg9,
> +                           unsigned long *out1,
> +                           unsigned long *out2,
> +                           unsigned long *out3,
> +                           unsigned long *out4,
> +                           unsigned long *out5,
> +                           unsigned long *out6,
> +                           unsigned long *out7,
> +                           unsigned long *out8,
> +                           unsigned long *out9)
> +{
> +	long rc;
> +	unsigned long t_tb_before, t_cpu_before;
> +
> +	t_tb_before = mftb();
> +	t_cpu_before = mfspr(SPRN_PURR);
> +	rc = plpar_hcall_9arg_9ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> +					arg6, arg7, arg8, arg9, out1, out2,
> +					out3, out4, out5, out6, out7, out8,
> +					out9);
> +
> +	update_stats(opcode, t_tb_before, t_cpu_before);
> +	return rc;
> +}
> diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
> --- linux-2.6.17.6/include/asm-powerpc/hvcall.h	2006-07-18 19:35:00.000000000 +0000
> +++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h	2006-07-18 19:56:20.000000000 +0000
> @@ -292,6 +292,87 @@ long plpar_hcall_9arg_9ret(unsigned long
>  			   unsigned long *out8,
>  			   unsigned long *out9);
>  
> +
> +/* For hcall instrumentation.  One structure per-hcall, per-CPU */
> +struct hcall_stats {
> +	unsigned long	num_calls;	/* number of calls (on this CPU) */
> +	unsigned long	tb_total;	/* total wall time (mftb) of calls. */
> +	unsigned long	cpu_total;	/* total cpu time (PURR) of calls. */
> +};
> +
> +/* If Hypervisor call instrumentation is enabled, the assembly routine
> + * names are changed from 'plpar_hcall*' to 'plpar_hcall*_base' and
> + * 'plpar_hcall*' routines become instrumented wrappers.  The following
> + * are declarations for the renamed 'plpar_hcall*_base' routines.
> + */
> +long plpar_hcall_base (unsigned long opcode,
> +		       unsigned long arg1,
> +		       unsigned long arg2,
> +		       unsigned long arg3,
> +		       unsigned long arg4,
> +		       unsigned long *out1,
> +		       unsigned long *out2,
> +		       unsigned long *out3);
> +
> +long plpar_hcall_norets_base(unsigned long opcode, ...);
> +
> +long plpar_hcall_8arg_2ret_base(unsigned long opcode,
> +				unsigned long arg1,
> +				unsigned long arg2,
> +				unsigned long arg3,
> +				unsigned long arg4,
> +				unsigned long arg5,
> +				unsigned long arg6,
> +				unsigned long arg7,
> +				unsigned long arg8,
> +				unsigned long *out1);
> +
> +long plpar_hcall_4out_base(unsigned long opcode,
> +			   unsigned long arg1,
> +			   unsigned long arg2,
> +			   unsigned long arg3,
> +			   unsigned long arg4,
> +			   unsigned long *out1,
> +			   unsigned long *out2,
> +			   unsigned long *out3,
> +			   unsigned long *out4);
> +
> +long plpar_hcall_7arg_7ret_base(unsigned long opcode,
> +				unsigned long arg1,
> +				unsigned long arg2,
> +				unsigned long arg3,
> +				unsigned long arg4,
> +				unsigned long arg5,
> +				unsigned long arg6,
> +				unsigned long arg7,
> +				unsigned long *out1,
> +				unsigned long *out2,
> +				unsigned long *out3,
> +				unsigned long *out4,
> +				unsigned long *out5,
> +				unsigned long *out6,
> +				unsigned long *out7);
> +
> +long plpar_hcall_9arg_9ret_base(unsigned long opcode,
> +				unsigned long arg1,
> +				unsigned long arg2,
> +				unsigned long arg3,
> +				unsigned long arg4,
> +				unsigned long arg5,
> +				unsigned long arg6,
> +				unsigned long arg7,
> +				unsigned long arg8,
> +				unsigned long arg9,
> +				unsigned long *out1,
> +				unsigned long *out2,
> +				unsigned long *out3,
> +				unsigned long *out4,
> +				unsigned long *out5,
> +				unsigned long *out6,
> +				unsigned long *out7,
> +				unsigned long *out8,
> +				unsigned long *out9);
> +
>  #endif /* __ASSEMBLY__ */
>  #endif /* __KERNEL__ */
>  #endif /* _ASM_POWERPC_HVCALL_H */
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
  2006-07-18 21:29 ` Mike Kravetz
@ 2006-07-18 22:38   ` Olof Johansson
  0 siblings, 0 replies; 15+ messages in thread
From: Olof Johansson @ 2006-07-18 22:38 UTC (permalink / raw)
  To: Mike Kravetz; +Cc: linuxppc-dev, Paul Mackerras

On Tue, Jul 18, 2006 at 02:29:13PM -0700, Mike Kravetz wrote:

> 88 1046 108106 109322
[...]
> 104 1 1040 1061

Heh. Shouldn't PURR/TB be <= 1 at all times? :-) I bet this is because
they're not sampled at exactly the same time, etc.

Maybe recoding it to assembly so you can do mftb and mfspr right after
each other, and do the arithmetics/stores later could help. Inline asm
might be sufficient.


-Olof

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
  2006-07-18 22:34   ` Olof Johansson
@ 2006-07-18 23:18     ` Mike Kravetz
  2006-07-19  3:33       ` Olof Johansson
  0 siblings, 1 reply; 15+ messages in thread
From: Mike Kravetz @ 2006-07-18 23:18 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, Paul Mackerras

On Tue, Jul 18, 2006 at 05:34:25PM -0500, Olof Johansson wrote:
> As I said before, SPRN_PURR doesn't exist on all architecture versions
> that supports hypervisor mode.

Thanks!

I assume checking must be done at run time via something like,
if (cpu_has_feature(CPU_FTR_PURR))

Also assume that it would make sense to do this determination at
initialization/boot time and put the result in the statistic data
structure.  In this way we would know it is in the same cache line
we are updating with other stats.  Or, should cur_cpu_spec->cpu_features
be 'sufficiently hot' to make this a non-issue?

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
  2006-07-18 23:18     ` Mike Kravetz
@ 2006-07-19  3:33       ` Olof Johansson
  2006-07-19  3:50         ` Mike Kravetz
  0 siblings, 1 reply; 15+ messages in thread
From: Olof Johansson @ 2006-07-19  3:33 UTC (permalink / raw)
  To: Mike Kravetz; +Cc: Olof Johansson, linuxppc-dev, Paul Mackerras

On Tue, Jul 18, 2006 at 04:18:15PM -0700, Mike Kravetz wrote:

> I assume checking must be done at run time via something like,
> if (cpu_has_feature(CPU_FTR_PURR))

If you do it in the hcall asm instead (like Paulus suggested), then it's
better to use BEGIN_FTR_SECTION/END_FTR_SECTION() around it, that way
the PURR reads just get nopped out instead of adding tests and branches.

> Also assume that it would make sense to do this determination at
> initialization/boot time and put the result in the statistic data
> structure.  In this way we would know it is in the same cache line
> we are updating with other stats.  Or, should cur_cpu_spec->cpu_features
> be 'sufficiently hot' to make this a non-issue?

If you use the FTR_SECTION stuff then it'll be taken care of
automatically at boot time. Doing that from C is messy, I don't think
anyone has had reason to do it before.


-Olof

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
  2006-07-18 21:00 ` [PATCH 0/3] powerpc: Instrument Hypervisor Calls Paul Mackerras
@ 2006-07-19  3:36   ` Mike Kravetz
  2006-07-19 22:11     ` Mike Kravetz
  0 siblings, 1 reply; 15+ messages in thread
From: Mike Kravetz @ 2006-07-19  3:36 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

On Wed, Jul 19, 2006 at 07:00:22AM +1000, Paul Mackerras wrote:
> Mike Kravetz writes:
> > A small update from the last version.  By popular demand, both
> > wall time (mftb) and cpu cycles(PURR) are collected for each call.
> > It is interesting to see these two values side by side in the
> > output files.
> 
> Did you see the patch from Anton that I posted a week or so ago, which
> reduces the number of plpar_hcall_* functions?  I'd rather the
> instrumentation stuff was based on that.

Agreed.  I missed the patch from last week, but saw the one from Anton
that was posted today.  Future instrumentation patches will assume this
change.

> My other comment is this: wouldn't it actually turn out simpler if we
> read the timebase (and PURR, if we really want to do that too) in the
> assembly code that implements plpar_hcall_*?

I'll give that a try.  My assembly skills are a bit rusty, so it may
take a little longer to produce something.

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
  2006-07-19  3:33       ` Olof Johansson
@ 2006-07-19  3:50         ` Mike Kravetz
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-19  3:50 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, Paul Mackerras

On Tue, Jul 18, 2006 at 10:33:00PM -0500, Olof Johansson wrote:
> If you use the FTR_SECTION stuff then it'll be taken care of
> automatically at boot time. Doing that from C is messy, I don't think
> anyone has had reason to do it before.

Ok, sounds like a good reason for assembly.  I'll dust off the books. :)

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
  2006-07-19  3:36   ` Mike Kravetz
@ 2006-07-19 22:11     ` Mike Kravetz
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Kravetz @ 2006-07-19 22:11 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

On Tue, Jul 18, 2006 at 08:36:18PM -0700, Mike Kravetz wrote:
> > My other comment is this: wouldn't it actually turn out simpler if we
> > read the timebase (and PURR, if we really want to do that too) in the
> > assembly code that implements plpar_hcall_*?
> 
> I'll give that a try.  My assembly skills are a bit rusty, so it may
> take a little longer to produce something.

Getting the timebase and PURR in assembly is easy enough.  So, I thought
about updating the per-cpu statistics while in there.  But, I couldn't
find any other assembly code that does this.  Sure there is asm code that
updated fields in the PACA, but none that messes with paca.data_offset
(that I could find).

Should the statistic updates also be done in the assembly routines?  Or,
how about a call out to a C routine for this?

-- 
Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2006-07-19 22:10 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-18 20:47 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
2006-07-18 20:48 ` [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers Mike Kravetz
2006-07-18 20:49 ` [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers Mike Kravetz
2006-07-18 22:34   ` Olof Johansson
2006-07-18 23:18     ` Mike Kravetz
2006-07-19  3:33       ` Olof Johansson
2006-07-19  3:50         ` Mike Kravetz
2006-07-18 20:50 ` [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files Mike Kravetz
2006-07-18 21:00 ` [PATCH 0/3] powerpc: Instrument Hypervisor Calls Paul Mackerras
2006-07-19  3:36   ` Mike Kravetz
2006-07-19 22:11     ` Mike Kravetz
2006-07-18 21:29 ` Mike Kravetz
2006-07-18 22:38   ` Olof Johansson
  -- strict thread matches above, loose matches on Subject: below --
2006-07-14 23:37 Mike Kravetz
2006-07-14 23:41 ` [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files Mike Kravetz
2006-06-22 22:56 [PATCH 0/3] powerpc: Instrument Hypervisor Calls Mike Kravetz
2006-06-22 23:00 ` [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files Mike Kravetz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).