linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 0/2] measure SMI cost (kernel)
@ 2017-03-27 15:47 kan.liang
  2017-03-27 15:47 ` [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions kan.liang
  2017-03-27 15:47 ` [PATCH V2 2/2] perf/x86: add sysfs entry to freeze counter on SMI kan.liang
  0 siblings, 2 replies; 5+ messages in thread
From: kan.liang @ 2017-03-27 15:47 UTC (permalink / raw)
  To: peterz, tglx, mingo, linux-kernel; +Cc: acme, eranian, jolsa, ak, Kan Liang

From: Kan Liang <Kan.liang@intel.com>

Currently, there is no way to measure the time cost in System management
mode (SMM) by perf.

Intel perfmon supports FREEZE_WHILE_SMM bit in IA32_DEBUGCTL. Once it sets,
the PMU core counters will freeze on SMI handler. But it will not have an
effect on free running counters. E.g. APERF counter.
The cost of SMI can be measured by (aperf - cycles).

A new sysfs entry /sys/device/cpu/freeze_on_smi is introduced to set
FREEZE_WHILE_SMM bit in IA32_DEBUGCTL.

A new --smi-cost mode in perf stat is implemented to measure the SMI cost
by calculating cycles and aperf results. In practice, the percentages of
SMI cycles should be more useful than absolute value. So the output will be
the percentage of SMI cycles and SMI#.
If user wants to get the actual cycles, they can apply --no-metric-only.

Here is an example output.

 Performance counter stats for 'sudo echo ':

SMI cycles%          SMI#
    0.1%              1

       0.010858678 seconds time elapsed

Changes since V1:
 - Only include kernel patch
 - New functions to set msr bit on cpu and cpus.
   Using the new functions to replace rdmsrl_on_cpu and wrmsrl_on_cpu.
   That avoids the extra IPIs and atomic issue.
 - Support hotplug

Kan Liang (2):
  x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions
  perf/x86: add sysfs entry to freeze counter on SMI

 arch/x86/events/core.c           | 10 ++++++
 arch/x86/events/intel/core.c     | 48 +++++++++++++++++++++++++
 arch/x86/events/perf_event.h     |  3 ++
 arch/x86/include/asm/msr-index.h |  2 ++
 arch/x86/include/asm/msr.h       | 29 +++++++++++++++
 arch/x86/lib/msr-smp.c           | 76 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 168 insertions(+)

-- 
2.7.4

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

* [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions
  2017-03-27 15:47 [PATCH V2 0/2] measure SMI cost (kernel) kan.liang
@ 2017-03-27 15:47 ` kan.liang
  2017-03-27 16:57   ` Borislav Petkov
  2017-03-27 15:47 ` [PATCH V2 2/2] perf/x86: add sysfs entry to freeze counter on SMI kan.liang
  1 sibling, 1 reply; 5+ messages in thread
From: kan.liang @ 2017-03-27 15:47 UTC (permalink / raw)
  To: peterz, tglx, mingo, linux-kernel; +Cc: acme, eranian, jolsa, ak, Kan Liang

From: Kan Liang <Kan.liang@intel.com>

Having msr_set/clear_bit on many cpus or given CPU can avoid extra
unnecessory IPIs and simplify MSR content manipulation, when it only
needs to flip a bit.
There is already msr_set/clear_bit, but missing the _on_cpu and _on_cpus
version.

Signed-off-by: Kan Liang <Kan.liang@intel.com>
---
 arch/x86/include/asm/msr.h | 29 ++++++++++++++++++
 arch/x86/lib/msr-smp.c     | 76 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 898dba2..9bc999b 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -20,6 +20,11 @@ struct msr {
 	};
 };
 
+struct msr_bit_info {
+	u32 msr_no;
+	u8 bit;
+};
+
 struct msr_info {
 	u32 msr_no;
 	struct msr reg;
@@ -314,6 +319,10 @@ int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
+int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit);
+int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit);
+void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit);
+void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit);
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
@@ -327,6 +336,26 @@ int wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q);
 int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
 int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
 #else  /*  CONFIG_SMP  */
+static inline int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit)
+{
+	return msr_set_bit(msr, bit);
+}
+
+static inline int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit)
+{
+	return msr_clear_bit(msr, bit);
+}
+
+static inline void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit)
+{
+	msr_set_bit(msr, bit);
+}
+
+static inline void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit)
+{
+	msr_clear_bit(msr, bit);
+}
+
 static inline int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
 {
 	rdmsr(msr_no, *l, *h);
diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c
index ce68b6a..100b3cb 100644
--- a/arch/x86/lib/msr-smp.c
+++ b/arch/x86/lib/msr-smp.c
@@ -3,6 +3,82 @@
 #include <linux/smp.h>
 #include <asm/msr.h>
 
+static void __msr_set_bit_on_cpu(void *info)
+{
+	struct msr_bit_info *bit_info = info;
+
+	msr_set_bit(bit_info->msr_no, bit_info->bit);
+}
+
+static void __msr_clear_bit_on_cpu(void *info)
+{
+	struct msr_bit_info *bit_info = info;
+
+	msr_clear_bit(bit_info->msr_no, bit_info->bit);
+}
+
+int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit)
+{
+	struct msr_bit_info info;
+	int err;
+
+	info.msr_no = msr;
+	info.bit = bit;
+
+	err = smp_call_function_single(cpu, __msr_set_bit_on_cpu, &info, 1);
+
+	return err;
+}
+EXPORT_SYMBOL(msr_set_bit_on_cpu);
+
+int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit)
+{
+	struct msr_bit_info info;
+	int err;
+
+	info.msr_no = msr;
+	info.bit = bit;
+
+	err = smp_call_function_single(cpu, __msr_clear_bit_on_cpu, &info, 1);
+
+	return err;
+}
+EXPORT_SYMBOL(msr_clear_bit_on_cpu);
+
+void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit)
+{
+	struct msr_bit_info info;
+	int this_cpu;
+
+	info.msr_no = msr;
+	info.bit = bit;
+
+	this_cpu = get_cpu();
+	if (cpumask_test_cpu(this_cpu, mask))
+		__msr_set_bit_on_cpu(&info);
+
+	smp_call_function_many(mask, __msr_set_bit_on_cpu, &info, 1);
+	put_cpu();
+}
+EXPORT_SYMBOL(msr_set_bit_on_cpus);
+
+void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit)
+{
+	struct msr_bit_info info;
+	int this_cpu;
+
+	info.msr_no = msr;
+	info.bit = bit;
+
+	this_cpu = get_cpu();
+	if (cpumask_test_cpu(this_cpu, mask))
+		__msr_clear_bit_on_cpu(&info);
+
+	smp_call_function_many(mask, __msr_clear_bit_on_cpu, &info, 1);
+	put_cpu();
+}
+EXPORT_SYMBOL(msr_clear_bit_on_cpus);
+
 static void __rdmsr_on_cpu(void *info)
 {
 	struct msr_info *rv = info;
-- 
2.7.4

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

* [PATCH V2 2/2] perf/x86: add sysfs entry to freeze counter on SMI
  2017-03-27 15:47 [PATCH V2 0/2] measure SMI cost (kernel) kan.liang
  2017-03-27 15:47 ` [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions kan.liang
@ 2017-03-27 15:47 ` kan.liang
  1 sibling, 0 replies; 5+ messages in thread
From: kan.liang @ 2017-03-27 15:47 UTC (permalink / raw)
  To: peterz, tglx, mingo, linux-kernel; +Cc: acme, eranian, jolsa, ak, Kan Liang

From: Kan Liang <Kan.liang@intel.com>

Currently, the SMIs are visible to all performance counters. Because
many users want to measure everything including SMIs. But in some
cases, the SMI cycles should not be count. For example, to calculate
the cost of SMI itself. So a knob is needed.

When setting FREEZE_WHILE_SMM bit in IA32_DEBUGCTL, all performance
counters will be effected. There is no way to do per-counter freeze
on SMI. So it should not use the per-event interface (e.g. ioctl or
event attribute) to set FREEZE_WHILE_SMM bit.

Adds sysfs entry /sys/device/cpu/freeze_on_smi to set FREEZE_WHILE_SMM
bit in IA32_DEBUGCTL. When set, freezes perfmon and trace messages
while in SMM.
Value has to be 0 or 1. It will be applied to all possible cpus.

Signed-off-by: Kan Liang <Kan.liang@intel.com>
---
 arch/x86/events/core.c           | 10 +++++++++
 arch/x86/events/intel/core.c     | 48 ++++++++++++++++++++++++++++++++++++++++
 arch/x86/events/perf_event.h     |  3 +++
 arch/x86/include/asm/msr-index.h |  2 ++
 4 files changed, 63 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 349d4d1..c16fb50 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -1750,6 +1750,8 @@ ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event)
 	return ret;
 }
 
+static struct attribute_group x86_pmu_attr_group;
+
 static int __init init_hw_perf_events(void)
 {
 	struct x86_pmu_quirk *quirk;
@@ -1813,6 +1815,14 @@ static int __init init_hw_perf_events(void)
 			x86_pmu_events_group.attrs = tmp;
 	}
 
+	if (x86_pmu.attrs) {
+		struct attribute **tmp;
+
+		tmp = merge_attr(x86_pmu_attr_group.attrs, x86_pmu.attrs);
+		if (!WARN_ON(!tmp))
+			x86_pmu_attr_group.attrs = tmp;
+	}
+
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
 	pr_info("... generic registers:      %d\n",     x86_pmu.num_counters);
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 4244bed..ecb321e 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3174,6 +3174,11 @@ static void intel_pmu_cpu_starting(int cpu)
 
 	cpuc->lbr_sel = NULL;
 
+	if (x86_pmu.attr_freeze_on_smi)
+		msr_set_bit_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT);
+	else
+		msr_clear_bit_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT);
+
 	if (!cpuc->shared_regs)
 		return;
 
@@ -3595,6 +3600,47 @@ static struct attribute *hsw_events_attrs[] = {
 	NULL
 };
 
+static ssize_t freeze_on_smi_show(struct device *cdev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return sprintf(buf, "%d\n", x86_pmu.attr_freeze_on_smi);
+}
+
+static ssize_t freeze_on_smi_store(struct device *cdev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	unsigned long val;
+	ssize_t ret;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	if (x86_pmu.attr_freeze_on_smi == val)
+		return count;
+
+	if (val)
+		msr_set_bit_on_cpus(cpu_possible_mask, MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT);
+	else
+		msr_clear_bit_on_cpus(cpu_possible_mask, MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT);
+
+	x86_pmu.attr_freeze_on_smi = val;
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(freeze_on_smi);
+
+static struct attribute *intel_pmu_attrs[] = {
+	&dev_attr_freeze_on_smi.attr,
+	NULL,
+};
+
 __init int intel_pmu_init(void)
 {
 	union cpuid10_edx edx;
@@ -3641,6 +3687,8 @@ __init int intel_pmu_init(void)
 
 	x86_pmu.max_pebs_events		= min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);
 
+
+	x86_pmu.attrs			= intel_pmu_attrs;
 	/*
 	 * Quirk: v2 perfmon does not report fixed-purpose events, so
 	 * assume at least 3 events, when not running in a hypervisor:
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index bcbb1d2..110cb9b0 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -561,6 +561,9 @@ struct x86_pmu {
 	ssize_t		(*events_sysfs_show)(char *page, u64 config);
 	struct attribute **cpu_events;
 
+	int		attr_freeze_on_smi;
+	struct attribute **attrs;
+
 	/*
 	 * CPU Hotplug hooks
 	 */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index d8b5f8a..bdb00fa 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -134,6 +134,8 @@
 #define DEBUGCTLMSR_BTS_OFF_OS		(1UL <<  9)
 #define DEBUGCTLMSR_BTS_OFF_USR		(1UL << 10)
 #define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI	(1UL << 11)
+#define DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT	14
+#define DEBUGCTLMSR_FREEZE_WHILE_SMM	(1UL << DEBUGCTLMSR_FREEZE_WHILE_SMM_BIT)
 
 #define MSR_PEBS_FRONTEND		0x000003f7
 
-- 
2.7.4

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

* Re: [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions
  2017-03-27 15:47 ` [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions kan.liang
@ 2017-03-27 16:57   ` Borislav Petkov
  2017-03-27 17:12     ` Liang, Kan
  0 siblings, 1 reply; 5+ messages in thread
From: Borislav Petkov @ 2017-03-27 16:57 UTC (permalink / raw)
  To: kan.liang; +Cc: peterz, tglx, mingo, linux-kernel, acme, eranian, jolsa, ak

On Mon, Mar 27, 2017 at 08:47:37AM -0700, kan.liang@intel.com wrote:
> From: Kan Liang <Kan.liang@intel.com>
> 
> Having msr_set/clear_bit on many cpus or given CPU can avoid extra
> unnecessory IPIs

How does that happen?

You have smp_call_function_many() sending IPIs to each CPU in the mask.
Doesn't look like avoiding anything to me.

Now if you want to have interfaces set/clear_bit_on_cpu(s), that's a
different story.

And those actually double the amount of IPIs the moment you do a
read-modify-write operation on the MSR, i.e., you want to read *and*
write afterwards.

If you only want to do a single operation - set or clear - like you're
doing in your other patch, then I guess that's fine as it wraps the
smp_call_function* boilerplate code.

> and simplify MSR content manipulation, when it only
> needs to flip a bit.
> There is already msr_set/clear_bit, but missing the _on_cpu and _on_cpus
> version.
> 
> Signed-off-by: Kan Liang <Kan.liang@intel.com>
> ---
>  arch/x86/include/asm/msr.h | 29 ++++++++++++++++++
>  arch/x86/lib/msr-smp.c     | 76 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 105 insertions(+)
> 
> diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
> index 898dba2..9bc999b 100644
> --- a/arch/x86/include/asm/msr.h
> +++ b/arch/x86/include/asm/msr.h
> @@ -20,6 +20,11 @@ struct msr {
>  	};
>  };
>  
> +struct msr_bit_info {
> +	u32 msr_no;
> +	u8 bit;
> +};

No, not *another* struct msr*info. Please reuse msr_info.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

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

* RE: [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions
  2017-03-27 16:57   ` Borislav Petkov
@ 2017-03-27 17:12     ` Liang, Kan
  0 siblings, 0 replies; 5+ messages in thread
From: Liang, Kan @ 2017-03-27 17:12 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: peterz, tglx, mingo, linux-kernel, acme, eranian, jolsa, ak


> 
> On Mon, Mar 27, 2017 at 08:47:37AM -0700, kan.liang@intel.com wrote:
> > From: Kan Liang <Kan.liang@intel.com>
> >
> > Having msr_set/clear_bit on many cpus or given CPU can avoid extra
> > unnecessory IPIs
> 
> How does that happen?
>

My previous patch did a read-modify-write operation. Compared with the
single operation set/clear, it will has extra IPIs.
Sorry for the confusing wording.
I will change the description. 

> You have smp_call_function_many() sending IPIs to each CPU in the mask.
> Doesn't look like avoiding anything to me.
> 
> Now if you want to have interfaces set/clear_bit_on_cpu(s), that's a
> different story.
> 
> And those actually double the amount of IPIs the moment you do a read-
> modify-write operation on the MSR, i.e., you want to read *and* write
> afterwards.
> 
> If you only want to do a single operation - set or clear - like you're doing in
> your other patch, then I guess that's fine as it wraps the
> smp_call_function* boilerplate code.
> 
> > and simplify MSR content manipulation, when it only needs to flip a
> > bit.
> > There is already msr_set/clear_bit, but missing the _on_cpu and
> > _on_cpus version.
> >
> > Signed-off-by: Kan Liang <Kan.liang@intel.com>
> > ---
> >  arch/x86/include/asm/msr.h | 29 ++++++++++++++++++
> >  arch/x86/lib/msr-smp.c     | 76
> ++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 105 insertions(+)
> >
> > diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
> > index 898dba2..9bc999b 100644
> > --- a/arch/x86/include/asm/msr.h
> > +++ b/arch/x86/include/asm/msr.h
> > @@ -20,6 +20,11 @@ struct msr {
> >  	};
> >  };
> >
> > +struct msr_bit_info {
> > +	u32 msr_no;
> > +	u8 bit;
> > +};
> 
> No, not *another* struct msr*info. Please reuse msr_info.
> 

OK.

Thanks,
Kan

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

end of thread, other threads:[~2017-03-27 17:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-27 15:47 [PATCH V2 0/2] measure SMI cost (kernel) kan.liang
2017-03-27 15:47 ` [PATCH V2 1/2] x86/msr: add msr_set/clear_bit_on_cpu/cpus access functions kan.liang
2017-03-27 16:57   ` Borislav Petkov
2017-03-27 17:12     ` Liang, Kan
2017-03-27 15:47 ` [PATCH V2 2/2] perf/x86: add sysfs entry to freeze counter on SMI kan.liang

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).