Skip to contentSkip to conversation

perfmon: X86 generic code (x86)

PATCH In review [email protected] 6 participants 42 messages Nov 26, 2008 – Nov 27, 2008 x86

lore
Share & tools
lore
#0 lore raw

PATCH 5/24 perfmon: X86 generic code (x86)

This patch adds the X86 generic perfmon code. It is in charge of implementing certain key functionalities required by the generic code such as read/write of the PMU registers, low-level interrupt handling.

--

arch/x86/perfmon/Kconfig new file +18 -0
Index: o3/arch/x86/perfmon/Kconfig
===================================================================
@@ -0,0 +1,18 @@
+menu "Hardware Performance Monitoring support"
+config PERFMON
+	bool "Perfmon2 performance monitoring interface"
+	select X86_LOCAL_APIC
+	default n
+	help
+	Enables the perfmon2 interface to access the hardware
+	performance counters. See <http://perfmon2.sf.net/> for
+	more details.
+
+config PERFMON_DEBUG
+	bool "Perfmon debugging"
+	default n
+	depends on PERFMON
+	help
+	Enables perfmon debugging support
+
+endmenu
arch/x86/perfmon/Makefile new file +5 -0
Index: o3/arch/x86/perfmon/Makefile
===================================================================
@@ -0,0 +1,5 @@
+#
+# Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
+# Contributed by Stephane Eranian <[email protected]>
+#
+obj-$(CONFIG_PERFMON)			+= perfmon.o
arch/x86/perfmon/perfmon.c new file +619 -0

619 lines not on this page · raw message

arch/x86/include/asm/Kbuild +1 -0
Index: o3/arch/x86/include/asm/Kbuild
===================================================================
@@ -10,6 +10,7 @@
 header-y += sigcontext32.h
 header-y += ucontext.h
 header-y += processor-flags.h
+header-y += perfmon.h
 
 unifdef-y += e820.h
 unifdef-y += ist.h
arch/x86/include/asm/perfmon.h new file +34 -0
Index: o3/arch/x86/include/asm/perfmon.h
===================================================================
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007 Hewlett-Packard Development Company, L.P.
+ * Contributed by Stephane Eranian <[email protected]>
+ *
+ * This file contains i386/x86_64 specific definitions for the perfmon
+ * interface.
+ *
+ * This file MUST never be included directly. Use linux/perfmon.h.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+  */
+#ifndef _ASM_X86_PERFMON__H_
+#define _ASM_X86_PERFMON__H_
+
+/*
+ * arch-specific user visible interface definitions
+ */
+
+#define PFM_ARCH_MAX_PMCS	(256+64) /* 256 HW 64 SW */
+#define PFM_ARCH_MAX_PMDS	(256+64) /* 256 HW 64 SW */
+
+#endif /* _ASM_X86_PERFMON_H_ */
arch/x86/include/asm/perfmon_kern.h new file +438 -0

438 lines not on this page · raw message

#1 lore raw
Quoted 6 lines · On Wed, Nov 26, 2008 at 12:42:09AM -0800, [email protected] wrote:

+ * set cannot be NULL. Context is locked. Interrupts are masked.
+ *
+ * Caller has already restored all PMD and PMC registers, if
+ * necessary (i.e., lazy restore scheme).
+ *
+ * On x86, the only common code just needs to unsecure RDPMC if necessary

What is insecure about RDPMC? (except perhaps when secure computing mode is on)

I think it should be enabled by default BTW because on Core2+ you can always read the fixed counters with it.

arch/x86/perfmon/perfmon.c line 291

Quoted 3 lines
arch/x86/perfmon/perfmon.c new file +3 -0
+	 */
+	if (using_nmi)
+		iip = __get_cpu_var(real_iip);

Call it real_rip perhaps?

arch/x86/perfmon/perfmon.c line 346

Quoted 11 lines
arch/x86/perfmon/perfmon.c new file +11 -0
+	/*
+	 * only NMI related calls
+	 */
+	if (val != DIE_NMI_IPI)
+		return NOTIFY_DONE;
+
+	/*
+	 * perfmon not using NMI
+	 */
+	if (!__get_cpu_var(pfm_using_nmi))
+		return NOTIFY_DONE;

It should not register in this case. die notifiers are costly because they make a lot of exceptions slower.

arch/x86/perfmon/perfmon.c line 614

Quoted 3 lines
arch/x86/perfmon/perfmon.c new file +3 -0
+	/*
+	 * we need to register our NMI handler when the kernels boots
+	 * to avoid a deadlock condition with the NMI watchdog or Oprofile

What deadlock?

arch/x86/include/asm/perfmon.h line 32

Quoted 11 lines
arch/x86/include/asm/perfmon.h new file +11 -0
+	 * if we were to try and register/unregister on-demand.
+	 */
+	register_die_notifier(&pfm_nmi_nb);
+	return 0;
+
+/*
+ * arch-specific user visible interface definitions
+ */
+
+#define PFM_ARCH_MAX_PMCS	(256+64) /* 256 HW 64 SW */
+#define PFM_ARCH_MAX_PMDS	(256+64) /* 256 HW 64 SW */

A little excessive for current x86s?

arch/x86/include/asm/perfmon_kern.h line 35

Quoted 9 lines
arch/x86/include/asm/perfmon_kern.h new file +9 -0
+#define _ASM_X86_PERFMON_KERN_H_
+
+#ifdef CONFIG_PERFMON
+#include <linux/unistd.h>
+#ifdef CONFIG_4KSTACKS
+#define PFM_ARCH_STK_ARG	8
+#else
+#define PFM_ARCH_STK_ARG	16
+#endif

Very fancy. But is it really worth it?

arch/x86/include/asm/perfmon_kern.h line 123

Quoted 11 lines
arch/x86/include/asm/perfmon_kern.h new file +11 -0
+	 * bits as this may cause crash on some processors.
+	 */
+	if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64)
+		value = (value | ~pfm_pmu_conf->ovfl_mask)
+		      & ~pfm_pmu_conf->pmd_desc[cnum].rsvd_msk;
+
+	PFM_DBG_ovfl("pfm_arch_write_pmd(0x%lx, 0x%Lx)",
+		     pfm_pmu_conf->pmd_desc[cnum].hw_addr,
+		     (unsigned long long) value);
+
+	wrmsrl(pfm_pmu_conf->pmd_desc[cnum].hw_addr, value);

Not sure how well error handling would fit in here, but it's normally a good idea to make at least the first wrmsrl to these counters a checking_wrmsrl because sometimes simulators or hypervisors don't implement them.

Quoted 2 lines

+ */
+static inline void pfm_arch_unload_context(struct pfm_context *ctx)

In general a lot of these inlines seem rather large. If they are called more than once consider out of lining for better code size.

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 7 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

-Andi

Signature · 1 line
[email protected]
#2 lore raw

Hi Andi,

Quoted 11 lines · On Wed, 26 Nov 2008 12:33:09 +0100 Andi Kleen <[email protected]> wrote:

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 8 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

These were added after comments from the PowerPC maintainer since how the bitmaps are accessed needs to be arch specific.

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#3 lore raw
Quoted 15 lines · Stephen Rothwell

Hi Andi,

Quoted 11 lines · On Wed, 26 Nov 2008 12:33:09 +0100 Andi Kleen <[email protected]> wrote:

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 8 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

Quoted 2 lines

These were added after comments from the PowerPC maintainer since how the bitmaps are accessed needs to be arch specific.

Why? They should not be exported outside, so endian shouldn't matter, should it?

-Andi

#4 lore raw

Hi Andi,

Quoted 16 lines · On Wed, 26 Nov 2008 13:22:17 +0100 Andi Kleen <[email protected]> wrote:
Quoted 14 lines · Stephen Rothwell
Quoted 11 lines · On Wed, 26 Nov 2008 12:33:09 +0100 Andi Kleen <[email protected]> wrote:

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 8 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

Quoted 5 lines
Quoted 2 lines

These were added after comments from the PowerPC maintainer since how the bitmaps are accessed needs to be arch specific.

Why? They should not be exported outside, so endian shouldn't matter, should it?

See http://lkml.org/lkml/2008/11/9/281 and the followups. Otherwise this should be answered by Paul and Stephane.

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#5 lore raw
In reply to Stephen Rothwell
Quoted 15 lines · Stephen Rothwell

Hi Andi,

Quoted 11 lines · On Wed, 26 Nov 2008 12:33:09 +0100 Andi Kleen <[email protected]> wrote:

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 8 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

Quoted 2 lines

These were added after comments from the PowerPC maintainer since how the bitmaps are accessed needs to be arch specific.

Just because perfmon uses u64 for bitfields instead of unsigned long, therefor it breaks on BE32 machines.

I have not yet found a good reason why it needs to use u64 instead of using what's there already.

Thanks,

tglx

#6 lore raw

Thomas,

Quoted 16 lines · Thomas Gleixner
Quoted 15 lines · Stephen Rothwell

Hi Andi,

Quoted 11 lines · On Wed, 26 Nov 2008 12:33:09 +0100 Andi Kleen <[email protected]> wrote:

arch/x86/include/asm/perfmon_kern.h line 379

Quoted 8 lines

+ * x86 does not need extra alignment requirements for the sampling buffer
+ */

arch/x86/include/asm/perfmon_kern.h new file +5 -0
+#define PFM_ARCH_SMPL_ALIGN_SIZE 0
+
+asmlinkage void  pmu_interrupt(void);
+
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)

All these bitmap wrappers just seem like unnecessary obfuscation. Could you just drop them and call the standard functions directly?

Quoted 9 lines
Quoted 2 lines

These were added after comments from the PowerPC maintainer since how the bitmaps are accessed needs to be arch specific.

Just because perfmon uses u64 for bitfields instead of unsigned long, therefor it breaks on BE32 machines.

I have not yet found a good reason why it needs to use u64 instead of using what's there already.

There is a good reason why we cannot use unsigned long. We must make sure all data structures exchanged between user mode and the kernel have fixed size. This way, we can have a 32-bit tool run unmodified on top of a 64-bit kernel AND we do not need trampoline code to marshall/unmarshall the parameters.

And yes, the abstraction for bitmask ops was introduced because of issues casting u64 -> unsigned long on Big-Endian32-bit machines such as PPC32.

#7 lore raw

Stephane,

Quoted 7 lines · stephane eranian
Quoted 3 lines

I have not yet found a good reason why it needs to use u64 instead of using what's there already.

There is a good reason why we cannot use unsigned long. We must make sure all data structures exchanged between user mode and the kernel have fixed size. This way, we can have a 32-bit tool run unmodified on top of a 64-bit kernel AND we do not need trampoline code to marshall/unmarshall the parameters.

That's not a good reason at all. We have in kernel interfaces and kernel-userspace interfaces. Making them the same is nice if it works, but horrible if it imposes crappy hackery like the bitops wrappers.

Quoted 2 lines

And yes, the abstraction for bitmask ops was introduced because of issues casting u64 -> unsigned long on Big-Endian32-bit machines such as PPC32.

Sorry, I think it is simply stupid.

You can keep the userspace interface u64 and use unsigned long for the bitmasks in the kernel and take care of it in the user space interface code and do the BE32 conversion when you copy stuff from and to user.

That's a single well defined place and does not add extra crappola over the kernel especially not into hot pathes like the interrupt.

Why do you want to do u64 -> u32 BE32 magic on every interrupt, context switch etc., if you can do it once in the userspace interface ?

Thanks,

tglx

#8 lore raw

Thomas,

Quoted 24 lines · Thomas Gleixner

Stephane,

Quoted 7 lines · stephane eranian
Quoted 3 lines

I have not yet found a good reason why it needs to use u64 instead of using what's there already.

There is a good reason why we cannot use unsigned long. We must make sure all data structures exchanged between user mode and the kernel have fixed size. This way, we can have a 32-bit tool run unmodified on top of a 64-bit kernel AND we do not need trampoline code to marshall/unmarshall the parameters.

That's not a good reason at all. We have in kernel interfaces and kernel-userspace interfaces. Making them the same is nice if it works, but horrible if it imposes crappy hackery like the bitops wrappers.

Quoted 2 lines

And yes, the abstraction for bitmask ops was introduced because of issues casting u64 -> unsigned long on Big-Endian32-bit machines such as PPC32.

Sorry, I think it is simply stupid.

You can keep the userspace interface u64 and use unsigned long for the bitmasks in the kernel and take care of it in the user space interface code and do the BE32 conversion when you copy stuff from and to user.

Quoted 6 lines

That's a single well defined place and does not add extra crappola over the kernel especially not into hot pathes like the interrupt.

Why do you want to do u64 -> u32 BE32 magic on every interrupt, context switch etc., if you can do it once in the userspace interface ?

I think we agree as to why the user visible structures have to have fixed size.

Some structures have bitfields in them (no in the current patchset yet). Here is an example:

#define PFM_PMD_BV (256/sizeof(__u64))

struct pfarg_pmd_attr {

        __u16 reg_num;          /* which register */
        __u16 reg_set;          /* which event set */
        __u32 reg_flags;        /* REGFL flags */
        __u64 reg_value;        /* 64-bit value */
        __u64 reg_long_reset;   /* write: value to reload after notification */
        __u64 reg_short_reset;  /* write: reset after counter overflow */
        __u64 reg_random_mask;  /* write: bitmask used to limit random value */

__u64 reg_smpl_pmds[PFM_PMD_BV]; /* write: record in sample */ __u64 reg_reset_pmds[PFM_PMD_BV]; /* write: reset on overflow */
__u64 reg_ovfl_swcnt; /* write: # of overflows before switch */
__u64 reg_smpl_eventid; /* write: opaque event identifier */
__u64 reg_last_value; /* read : return: PMD last reset value */
__u64 reg_reserved[8]; /* for future use */
};

So you are advocating keeping that layout for the user level code, i.e., the user level perfmon.h.
But then, in the kernel, you'd have a different version of the same structure with the same name
and the size but with the bitmask defined as unsigned long instead. All internal only bitmask
would also be unsigned long. So the structure would like as follows:

#define PFM_PMD_BV (256/sizeof(unsigned long))
struct pfarg_pmd_attr {

        __u16 reg_num;          /* which register */
        __u16 reg_set;          /* which event set */
        __u32 reg_flags;        /* REGFL flags */
        __u64 reg_value;        /* 64-bit value */
        __u64 reg_long_reset;   /* write: value to reload after notification */
        __u64 reg_short_reset;  /* write: reset after counter overflow */
        __u64 reg_random_mask;  /* write: bitmask used to limit random value */

unsigned long reg_smpl_pmds[PFM_PMD_BV]; /* write: record in sample */ unsigned long reg_reset_pmds[PFM_PMD_BV]; /* write: reset on overflow */
__u64 reg_ovfl_swcnt; /* write: # of overflows before switch */
__u64 reg_smpl_eventid; /* write: opaque event identifier */
__u64 reg_last_value; /* read : return: PMD last reset value */
__u64 reg_reserved[8]; /* for future use */
};

Then we could not directly export include/linux/perfmon.h to user via Kbuild.

#9 lore raw

Stephane,

Quoted 18 lines · stephane eranian
Quoted 3 lines

Why do you want to do u64 -> u32 BE32 magic on every interrupt, context switch etc., if you can do it once in the userspace interface ?

I think we agree as to why the user visible structures have to have fixed size.

Some structures have bitfields in them (no in the current patchset yet). Here is an example:

#define PFM_PMD_BV (256/sizeof(__u64))

struct pfarg_pmd_attr {

        __u16 reg_num;          /* which register */
        __u16 reg_set;          /* which event set */
        __u32 reg_flags;        /* REGFL flags */
        __u64 reg_value;        /* 64-bit value */
        __u64 reg_long_reset;   /* write: value to reload after notification */
        __u64 reg_short_reset;  /* write: reset after counter overflow */
        __u64 reg_random_mask;  /* write: bitmask used to limit random value */
Quoted 7 lines

__u64 reg_smpl_pmds[PFM_PMD_BV]; /* write: record in sample */ __u64 reg_reset_pmds[PFM_PMD_BV]; /* write: reset on overflow */
__u64 reg_ovfl_swcnt; /* write: # of overflows before switch */
__u64 reg_smpl_eventid; /* write: opaque event identifier */
__u64 reg_last_value; /* read : return: PMD last reset value */
__u64 reg_reserved[8]; /* for future use */
};

__attribute__ ((packed)); ???

Quoted 25 lines

So you are advocating keeping that layout for the user level code, i.e., the user level perfmon.h.
But then, in the kernel, you'd have a different version of the same structure with the same name
and the size but with the bitmask defined as unsigned long instead. All internal only bitmask
would also be unsigned long. So the structure would like as follows:

#define PFM_PMD_BV (256/sizeof(unsigned long))
struct pfarg_pmd_attr {

        __u16 reg_num;          /* which register */
        __u16 reg_set;          /* which event set */
        __u32 reg_flags;        /* REGFL flags */
        __u64 reg_value;        /* 64-bit value */
        __u64 reg_long_reset;   /* write: value to reload after notification */
        __u64 reg_short_reset;  /* write: reset after counter overflow */
        __u64 reg_random_mask;  /* write: bitmask used to limit random value */

unsigned long reg_smpl_pmds[PFM_PMD_BV]; /* write: record in sample */ unsigned long reg_reset_pmds[PFM_PMD_BV]; /* write: reset on overflow */
__u64 reg_ovfl_swcnt; /* write: # of overflows before switch */
__u64 reg_smpl_eventid; /* write: opaque event identifier */
__u64 reg_last_value; /* read : return: PMD last reset value */
__u64 reg_reserved[8]; /* for future use */
};

Quoted 2 lines

Then we could not directly export include/linux/perfmon.h to user via Kbuild.

I really can not see the problem.

1) perfmon.h can have a section for kernel and user space. We have tons of examples of this in the kernel already.

The user space data structures are separate, simply because they are an user space ABI and can not be changed.

Kernel data structures can be completely different from the user ABI and can be changed at any given time as the code evolves. The design you are proposing is tying the in kernel data structures to the user ABI forever.

I can see that it might be good performance wise if you dont have to touch stuff twice, but reshuffling the bitmasks should not be that expensive.

2) You can have an union of

union {

   	 __u64 bla[N];
	 unsigned long blub[M];

};

Where M = N for 64 bit and M = 2 * N for 32 bit.

FYI, I talked to Paulus about that and he thinks that doing the PPC BE32 bitops for u64 are pretty cheap, but we agreed that this is neither a perfmon nor an arch feature and has to be done as generic as possible similar to the atomic64 ops. That way we have just two implementations (generic and BE32) and not 10 copies of the same wrappers around ulong bitops all over the place.

Also test_bit_64() is definitely more acceptable and more useful than pfm_arch_bv_test_bit().

Thanks,

tglx

#10 lore raw

From: Thomas Gleixner <[email protected]>
Date: Thu, 27 Nov 2008 11:56:24 +0100 (CET)

Quoted 29 lines

Stephane,

Quoted 18 lines · stephane eranian
Quoted 3 lines

Why do you want to do u64 -> u32 BE32 magic on every interrupt, context switch etc., if you can do it once in the userspace interface ?

I think we agree as to why the user visible structures have to have fixed size.

Some structures have bitfields in them (no in the current patchset yet). Here is an example:

#define PFM_PMD_BV (256/sizeof(__u64))

struct pfarg_pmd_attr {

        __u16 reg_num;          /* which register */
        __u16 reg_set;          /* which event set */
        __u32 reg_flags;        /* REGFL flags */
        __u64 reg_value;        /* 64-bit value */
        __u64 reg_long_reset;   /* write: value to reload after notification */
        __u64 reg_short_reset;  /* write: reset after counter overflow */
        __u64 reg_random_mask;  /* write: bitmask used to limit random value */
Quoted 7 lines

__u64 reg_smpl_pmds[PFM_PMD_BV]; /* write: record in sample */ __u64 reg_reset_pmds[PFM_PMD_BV]; /* write: reset on overflow */
__u64 reg_ovfl_swcnt; /* write: # of overflows before switch */
__u64 reg_smpl_eventid; /* write: opaque event identifier */
__u64 reg_last_value; /* read : return: PMD last reset value */
__u64 reg_reserved[8]; /* for future use */
};

Quoted 1 line

__attribute__ ((packed)); ???

Shouldn't be needed and this woule kill performance on RISC (every struct member is accessed with byte sized loads and shifts/masking).

We did this for the pfkey.h structures by accident, and I truly regret it.

#11 lore raw
Quoted 8 lines · David Miller

From: Thomas Gleixner <[email protected]>

Quoted 1 line

__attribute__ ((packed)); ???

Shouldn't be needed and this woule kill performance on RISC (every struct member is accessed with byte sized loads and shifts/masking).

We did this for the pfkey.h structures by accident, and I truly regret it.

Fair enough.

Thanks,

tglx

#12 lore raw
In reply to [email protected]

Stephane,

Quoted 13 lines · On Wed, 26 Nov 2008, [email protected] wrote:

This patch adds the X86 generic perfmon code. It is in charge of implementing certain key functionalities required by the generic code such as read/write of the PMU registers, low-level interrupt handling.

--

Index: o3/arch/x86/perfmon/Kconfig
===================================================================

arch/x86/perfmon/Kconfig line 4

Quoted 4 lines
arch/x86/perfmon/Kconfig new file +4 -0
@@ -0,0 +1,18 @@
+menu "Hardware Performance Monitoring support"
+config PERFMON
+	bool "Perfmon2 performance monitoring interface"
+	select X86_LOCAL_APIC

depends on X86_LOCAL_APIC

arch/x86/perfmon/Kconfig line 18

Quoted 8 lines
arch/x86/perfmon/Kconfig new file +8 -0
+config PERFMON_DEBUG
+	bool "Perfmon debugging"
+	default n
+	depends on PERFMON
+	help
+	Enables perfmon debugging support
+
+endmenu

Please move this config options into perfmon/Kconfig

config PERFMON
bool "Perfmon2 performance monitoring interface" depends on ARCH_HAS_PERFMON_SUPPORT

So we avoid duplicating that all over the tree

arch/x86/perfmon/Kconfig

Quoted 4 lines

Index: o3/arch/x86/perfmon/perfmon.c

arch/x86/perfmon/Kconfig new file +3 -0
+
+DEFINE_PER_CPU(unsigned long, real_iip);
+DEFINE_PER_CPU(int, pfm_using_nmi);

static

Quoted 9 lines

+/**
+ * pfm_arch_ctxswin_thread - thread context switch in
+ * @task: task switched in
+ * @ctx: context for the task
+ * @set: active event set
+ *
+ * Called from pfm_ctxsw(). Task is guaranteed to be current.
+ * set cannot be NULL. Context is locked. Interrupts are masked.
+ *

Quoted 8 lines

+ * Caller has already restored all PMD and PMC registers, if
+ * necessary (i.e., lazy restore scheme).
+ *
+ * On x86, the only common code just needs to unsecure RDPMC if necessary
+ *
+ * On model-specific features, e.g., PEBS, IBS, are taken care of in the
+ * corresponding PMU description module
+ */

Can we please move these docbook comments to include/linux/perfmon.h ?

Otherwise we have them in ten different places and probably out of sync sooner than later. kgdb and other infrastructures which are cross arch do the same.

arch/x86/perfmon/Kconfig

Quoted 5 lines
arch/x86/perfmon/Kconfig new file +5 -0
+void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx)
+{
+	struct pfm_arch_context *ctx_arch;
+
+	ctx_arch = pfm_ctx_arch(ctx);

Can we please make this

	struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx);

Same on various places below.

arch/x86/perfmon/Kconfig

Quoted 3 lines
arch/x86/perfmon/Kconfig new file +3 -0
+void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
+{
+	u16 i, num;

why u16 ? int is fine for loop counters

Quoted 11 lines
arch/x86/perfmon/Kconfig new file +11 -0
+	num = set->nused_pmds;
+
+	/*
+	 * we can restore only the PMD we use because:
+	 *
+	 * 	- can only read with pfm_read_pmds() the registers
+	 * 	  declared used via pfm_write_pmds()
+	 *
+	 * 	- if cr4.pce=1, only counters are exposed to user. RDPMC
+	 * 	  does not work with other types of PMU registers.Thus, no
+	 * 	  address is ever exposed by counters

arch/x86/perfmon/Kconfig

Quoted 10 lines
arch/x86/perfmon/Kconfig new file +10 -0
+	 *
+	 * 	- there is never a dependency between one pmd register and
+	 * 	  another
+	 */
+	for (i = 0; num; i++) {
+		if (likely(pfm_arch_bv_test_bit(i, set->used_pmds))) {
+			pfm_write_pmd(ctx, i, set->pmds[i]);
+			num--;
+		}
+	}

This loop construct looks scary. It relies on set->nused_pmds >= bits set in set->used_pmds. I had to look more than once to understand that. It's used all over the code in variations.

Quoted 4 lines
arch/x86/perfmon/Kconfig new file +4 -0
+/**
+ * smp_pmu_interrupt - lowest level PMU interrupt handler for X86
+ * @regs: machine state
+ *

arch/x86/perfmon/Kconfig

Quoted 10 lines
arch/x86/perfmon/Kconfig new file +10 -0
+ * The PMU interrupt is handled through an interrupt gate, therefore
+ * the CPU automatically clears the EFLAGS.IF, i.e., masking interrupts.
+ *
+ * The perfmon interrupt handler MUST run with interrupts disabled due
+ * to possible race with other, higher priority interrupts, such as timer
+ * or IPI function calls.
+ *
+ * See description in IA-32 architecture manual, Vol 3 section 5.8.1
+ */
+void smp_pmu_interrupt(struct pt_regs *regs)

Why is this only hooked up to x86_64 ?

arch/x86/perfmon/Kconfig

Quoted 9 lines
arch/x86/perfmon/Kconfig new file +8 -0
+/**
+ * pfm_handle_nmi - PMU NMI handler notifier callback
 
+ * Cannot grab any locks, include the perfmon context lock
+	/*
+	 * we stop the PMU to avoid further overflow before this
+	 * one is treated by lower priority interrupt handler
+	 */
+	pmu_info->quiesce();

This calls into the intel/amd implementations and iterates over pfm_pmu_conf->regs_all.pmcs and clears the event select registers.

How is that NMI safe against pfm_arch_write_pmc() in other places ?

arch/x86/perfmon/Kconfig

Quoted 9 lines
arch/x86/perfmon/Kconfig new file +9 -0
+	/*
+	 * record actual instruction pointer
+	 */
+	__get_cpu_var(real_iip) = instruction_pointer(args->regs);
+
+	/*
+	 * post lower priority interrupt (LOCAL_PERFMON_VECTOR)
+	 */
+	pfm_arch_resend_irq(ctx);

Do we really need this whole NMI business ?

arch/x86/perfmon/Kconfig

Quoted 5 lines
arch/x86/perfmon/Kconfig new file +5 -0
+	/*
+	 * we need to rewrite the APIC vector on Intel
+	 */
+	if (current_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+		apic_write(APIC_LVTPC, APIC_DM_NMI);

Why reenable _before_ we handled the current set ?

arch/x86/perfmon/Kconfig

Quoted 13 lines
arch/x86/perfmon/Kconfig new file +12 -0
+/**
+ * pfm_arch_resend_irq - post perfmon interrupt on regular vector
+ *
+ * called from pfm_ctxswin_thread() and pfm_handle_nmi()
+ */
+void pfm_arch_resend_irq(struct pfm_context *ctx)
+{
 
+	 * Instead we send ourself an IPI on the perfmon
+	 * vector.
+	 */
+	val  = APIC_DEST_SELF|APIC_INT_ASSERT|
+	       APIC_DM_FIXED|LOCAL_PERFMON_VECTOR;

Please use

       send_IPI_self(LOCAL_PERFMON_VECTOR);

instead of open coding it.

Your code is also missing apic_wait_icr_idle() so it would kill an queued, but not yet delivered IPI.

arch/x86/perfmon/Kconfig

Quoted 1 line
arch/x86/perfmon/Kconfig new file +1 -0
+			PFM_DBG("pmc%d(%s) already used", i, d->desc);

cant we simply use pr_debug ?

arch/x86/perfmon/Kconfig

Quoted 2 lines
arch/x86/perfmon/Kconfig new file +2 -0
+		if (pmu_info->flags & PFM_X86_FL_NO_SHARING) {
+			PFM_INFO("PMU already used by another subsystem, "

printk please

Quoted 39 lines
arch/x86/perfmon/Kconfig new file +39 -0
+/**
+ * pfm-arch_pmu_release_percpu - clear NMI state for one CPU
+ *
+ */
+static void pfm_arch_pmu_release_percpu(void *data)
+{
+	struct pfm_arch_pmu_info *pmu_info;
+
+	pmu_info = pfm_pmu_conf->pmu_info;
+
+	__get_cpu_var(pfm_using_nmi) = 0;
+	/*
+	 * invoke model specific release routine.
+	 */
+	if (pmu_info->release_pmu_percpu)
+		pmu_info->release_pmu_percpu();
+}
+
+/**
+ * pfm_arch_pmu_release - release PMU resource to system
+ *
+ * called from pfm_pmu_release()
+ * interrupts are not masked
+ *
+ * On x86, we return the PMU registers to the MSR allocator
+ */
+void pfm_arch_pmu_release(void)
+{
+	struct pfm_regmap_desc *d;
+	u16 i, n;
+
+	d = pfm_pmu_conf->pmc_desc;
+	n = pfm_pmu_conf->regs_all.num_pmcs;
+	for (i = 0; n; i++, d++) {
+		if (!pfm_arch_bv_test_bit(i, pfm_pmu_conf->regs_all.pmcs))
+			continue;
+		release_evntsel_nmi(d->hw_addr);
+		n--;
+		PFM_DBG("pmc%u released", i);

arch/x86/perfmon/Kconfig

Quoted 10 lines
arch/x86/perfmon/Kconfig new file +10 -0
+	}
+	d = pfm_pmu_conf->pmd_desc;
+	n = pfm_pmu_conf->regs_all.num_pmds;
+	for (i = 0; n; i++, d++) {
+		if (!pfm_arch_bv_test_bit(i, pfm_pmu_conf->regs_all.pmds))
+			continue;
+		release_perfctr_nmi(d->hw_addr);
+		n--;
+		PFM_DBG("pmd%u released", i);
+	}

What is masking the vectors ?

Quoted 8 lines
arch/x86/perfmon/Kconfig new file +5 -0
+	/* clear NMI variable if used */
+	if (__get_cpu_var(pfm_using_nmi))
+		on_each_cpu(pfm_arch_pmu_release_percpu, NULL , 1);
+}
+

Index: o3/arch/x86/include/asm/perfmon_kern.h

arch/x86/perfmon/Kconfig

Quoted 10 lines
arch/x86/perfmon/Kconfig new file +8 -0
+static inline void pfm_arch_unload_context(struct pfm_context *ctx)
+static inline int pfm_arch_load_context(struct pfm_context *ctx)
 
+void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set);
+void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx);
+void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx);
 
+static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx,
+static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx)
+static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, unsigned int cnum)

80 chars.

Quoted 1 line

+static inline int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags)

Ditto.

arch/x86/perfmon/Kconfig

Quoted 5 lines
arch/x86/perfmon/Kconfig new file +4 -0
+static inline void pfm_arch_context_free(struct pfm_context *ctx)
 
+/*
+ * functions implemented in arch/x86/perfmon/perfmon.c
+ */

The above non inlines are in perfmon.c as well.

Quoted 17 lines
arch/x86/perfmon/Kconfig new file +17 -0
+int  pfm_arch_init(void);
+void pfm_arch_resend_irq(struct pfm_context *ctx);
+
+int  pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx);
+void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx);
+
+void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
+int  pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg);
+void pfm_arch_pmu_config_remove(void);
+char *pfm_arch_get_pmu_module_name(void);
+int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds);
+void pfm_arch_pmu_release(void);
+
+static inline void pfm_arch_serialize(void)
+{}
+
+static inline void pfm_arch_arm_handle_work(struct task_struct *task)

arch/x86/perfmon/Kconfig

Quoted 10 lines
arch/x86/perfmon/Kconfig new file +10 -0
+{}
+
+static inline void pfm_arch_disarm_handle_work(struct task_struct *task)
+{}
+
+#define PFM_ARCH_CTX_SIZE	(sizeof(struct pfm_arch_context))
+/*
+ * x86 does not need extra alignment requirements for the sampling buffer
+ */
+#define PFM_ARCH_SMPL_ALIGN_SIZE	0

Defines in one place please

arch/x86/perfmon/Kconfig

Quoted 7 lines
arch/x86/perfmon/Kconfig new file +6 -0
+asmlinkage void  pmu_interrupt(void);
 
+static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits)
+{
+	bitmap_copy((unsigned long *)a,
+		    (unsigned long *)b,
+		    nbits);
	bitmap_copy((unsigned long *) a, (unsigned long *) b, nbits);

Please.

arch/x86/perfmon/Kconfig

Quoted 8 lines
arch/x86/perfmon/Kconfig new file +8 -0
+static inline void pfm_arch_bv_or(u64 *a, u64 *b, u64 *c, int nbits)
+static inline void pfm_arch_bv_and(u64 *a, u64 *b, u64 *c, int nbits)
+static inline void pfm_arch_bv_zero(u64 *a, int nbits)
+static inline int pfm_arch_bv_weight(u64 *a, int nbits)
+static inline void pfm_arch_bv_set_bit(int b, u64 *a)
+static inline void pfm_arch_bv_clear_bit(int b, u64 *a)
+static inline int pfm_arch_bv_test_bit(int b, u64 *a)
+static inline unsigned long pfm_arch_bv_find_next_bit(const u64 *addr,

9 simple wrappers around generic bitops. The only reason you need those is because you use 64bit variables and that does not work on 32bit BE machines.

I do not understand in the first place why you cant use simple unsigned longs for the bitfields, but if this is necessary for whatever non obvious reason, then its not an excuse to make this arch dependent code at all. You need a LE/BE64 and a BE32 version. So you need a generic and a special be32 version. That's not arch specific.

Thanks,

tglx

#13 lore raw
Quoted 8 lines · Thomas Gleixner
Quoted 8 lines
arch/x86/perfmon/perfmon.c new file +8 -0
+	 * 	  does not work with other types of PMU registers.Thus, no
+	 * 	  address is ever exposed by counters
+	 *
+	 * 	- there is never a dependency between one pmd register and
+	 * 	  another
+	 */
+	for (i = 0; num; i++) {
+		if (likely(pfm_arch_bv_test_bit(i, set->used_pmds))) {
Quoted 8 lines

arch/x86/perfmon/perfmon.c line 203

Quoted 4 lines
arch/x86/perfmon/perfmon.c new file +4 -0
+			pfm_write_pmd(ctx, i, set->pmds[i]);
+			num--;
+		}
+	}

This loop construct looks scary. It relies on set->nused_pmds >= bits set in set->used_pmds. I had to look more than once to understand that. It's used all over the code in variations.

FWIW this loop style tripped me up during review too.

Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	 */
+	pfm_arch_resend_irq(ctx);

Do we really need this whole NMI business ?

Without it you cannot profile interrupts off regions well.

Quoted 10 lines

9 simple wrappers around generic bitops. The only reason you need those is because you use 64bit variables and that does not work on 32bit BE machines.

I do not understand in the first place why you cant use simple unsigned longs for the bitfields, but if this is necessary for whatever non obvious reason, then its not an excuse to make this arch dependent code at all. You need a LE/BE64 and a BE32 version. So you need a generic and a special be32 version. That's not arch specific.

Or a unsigned long x[VALUE_DEPENDS_ON_WORD_SIZE]

-Andi

#14 lore raw
Quoted 18 lines · Andi Kleen
Quoted 8 lines · Thomas Gleixner
Quoted 8 lines
arch/x86/perfmon/perfmon.c new file +8 -0
+	 * 	  does not work with other types of PMU registers.Thus, no
+	 * 	  address is ever exposed by counters
+	 *
+	 * 	- there is never a dependency between one pmd register and
+	 * 	  another
+	 */
+	for (i = 0; num; i++) {
+		if (likely(pfm_arch_bv_test_bit(i, set->used_pmds))) {
Quoted 8 lines

arch/x86/perfmon/perfmon.c line 203

Quoted 4 lines
arch/x86/perfmon/perfmon.c new file +4 -0
+			pfm_write_pmd(ctx, i, set->pmds[i]);
+			num--;
+		}
+	}

This loop construct looks scary. It relies on set->nused_pmds >= bits set in set->used_pmds. I had to look more than once to understand that. It's used all over the code in variations.

Quoted 1 line

FWIW this loop style tripped me up during review too.

It's even worse than I thought when looking at it a second time:

All the loops iterate over an array which means in the worst case we do full array_size iterations. In each iteration we check whether the corresponding bit in the bitmask is set or not.

What a nonsense. We have a bitmask already. Why not iterate over the bitmask and be done ?

Thanks,

tglx

#15 lore raw

Thomas,

Quoted 22 lines · Thomas Gleixner
Quoted 14 lines · Andi Kleen
Quoted 13 lines · Thomas Gleixner
Quoted 12 lines
arch/x86/perfmon/perfmon.c new file +12 -0
+  *        does not work with other types of PMU registers.Thus, no
+  *        address is ever exposed by counters
+  *
+  *      - there is never a dependency between one pmd register and
+  *        another
+  */
+ for (i = 0; num; i++) {
+         if (likely(pfm_arch_bv_test_bit(i, set->used_pmds))) {
+                 pfm_write_pmd(ctx, i, set->pmds[i]);
+                 num--;
+         }
+ }
Quoted 5 lines
Quoted 3 lines

This loop construct looks scary. It relies on set->nused_pmds >= bits set in set->used_pmds. I had to look more than once to understand that. It's used all over the code in variations.

FWIW this loop style tripped me up during review too.

Quoted 9 lines

It's even worse than I thought when looking at it a second time:

All the loops iterate over an array which means in the worst case we do full array_size iterations. In each iteration we check whether the corresponding bit in the bitmask is set or not.

What a nonsense. We have a bitmask already. Why not iterate over the bitmask and be done ?

Bitmask can be sparsed. Num represents the number of bits we have to find. The idea is that we don't need to scan the entire bitmask, we stop as soon as we have found all the bits we care about (i.e., all the bits that are set).

Example:

         num = 3
     bitmask=0000000010001001
                                    ^ we will iterate until we are

done with that bit.

#16 lore raw
Quoted 8 lines · stephane eranian
Quoted 3 lines

What a nonsense. We have a bitmask already. Why not iterate over the bitmask and be done ?

Bitmask can be sparsed. Num represents the number of bits we have to find. The idea is that we don't need to scan the entire bitmask, we stop as soon as we have found all the bits we care about (i.e., all the bits that are set).

Quoted 5 lines

Example:

         num = 3
     bitmask=0000000010001001
                                    ^ we will iterate until we are

done with that bit.

Errm.

#define for_each_bit(bit, addr, size) \
        for ((bit) = find_first_bit((addr), (size)); \
             (bit) < (size); \
             (bit) = find_next_bit((addr), (size), (bit) + 1))

find_first_bit() and find_next_bit() are single instructions on most architectures. "size" is known upfront at setup time of the context/set and can be cached.

This takes exactly 3 iterations, while your method needs 8. And it gets worse with the following example:

Example:
num = 1
bitmask=1000 0000 0000 0000 0000 0000 0000 00000

^ you will iterate until we are done with that bit (32 times)

for_each_bit() will iterate exactly _once_.

Thanks,

tglx

#17 lore raw

Thomas,

Quoted 29 lines · Thomas Gleixner
Quoted 8 lines · stephane eranian
Quoted 3 lines

What a nonsense. We have a bitmask already. Why not iterate over the bitmask and be done ?

Bitmask can be sparsed. Num represents the number of bits we have to find. The idea is that we don't need to scan the entire bitmask, we stop as soon as we have found all the bits we care about (i.e., all the bits that are set).

Quoted 5 lines

Example:

         num = 3
     bitmask=0000000010001001
                                    ^ we will iterate until we are

done with that bit.

Errm.

#define for_each_bit(bit, addr, size) \
       for ((bit) = find_first_bit((addr), (size)); \
            (bit) < (size); \
            (bit) = find_next_bit((addr), (size), (bit) + 1))

find_first_bit() and find_next_bit() are single instructions on most architectures. "size" is known upfront at setup time of the context/set and can be cached.

This takes exactly 3 iterations, while your method needs 8. And it gets worse with the following example:

Quoted 8 lines

Example:
num = 1
bitmask=1000 0000 0000 0000 0000 0000 0000 00000

^ you will iterate until we are done with that bit (32 times)

for_each_bit() will iterate exactly _once_.

Ok, you've convinced me. I will make the change.
Thanks.

#18 lore raw
In reply to Andi Kleen
Quoted 7 lines · Andi Kleen
Quoted 4 lines · Thomas Gleixner

Review

Quoted 2 lines
(quoted diff) +2 -0
+	 */
+	pfm_arch_resend_irq(ctx);

Do we really need this whole NMI business ?

Without it you cannot profile interrupts off regions well.

Fair enough, but I doubt that this is a real solution.

There is not even an attempt to avoid the obvious wrmrsl races, while there are several comments which explain how expensive wrmrsl is. In the NMI handler we enable the NMI right away. This might cause multiple NMIs for nothing when the NMIs hit between the manipulations of the counters. Not likely but can happen depending on the counter settings.

Sending an self-IPI from NMI simply sucks: For every NMI we get an extra local interrupt and we have an extra of 2 * NR_ACTIVE_COUNTERS accesses to MSRs.

Designing that code to use lockless buffers instead is not really rocket science.

This code sucks performance wise in all aspects I have looked at so far.

Thanks,

tglx

#19 lore raw
Quoted 18 lines · Thomas Gleixner
Quoted 7 lines · Andi Kleen
Quoted 4 lines · Thomas Gleixner

Review

Quoted 2 lines
(quoted diff) +2 -0
+	 */
+	pfm_arch_resend_irq(ctx);

Do we really need this whole NMI business ?

Without it you cannot profile interrupts off regions well.

Fair enough, but I doubt that this is a real solution.

There is not even an attempt to avoid the obvious wrmrsl races, while there are several comments which explain how expensive wrmrsl is. In the NMI handler we enable the NMI right away. This might cause multiple NMIs for nothing when the NMIs hit between the manipulations of the counters. Not likely but can happen depending on the counter settings.

Quoted 3 lines

Sending an self-IPI from NMI simply sucks: For every NMI we get an extra local interrupt and we have an extra of 2 * NR_ACTIVE_COUNTERS accesses to MSRs.

In newer Intel the counters can be reset/rearmed by accessing only a few global control msrs. But it's probably still a problem on other PMUs.

On the other hand it also has PEBS which allows at least some profiling of irq-off regions without using NMIs.

Quoted 3 lines

Designing that code to use lockless buffers instead is not really rocket science.

Lockless buffers are nasty, but it works in oprofile at least.

Taking out NMis in the first version at least seems like a reasonable solution. After all you can still use standard oprofile where they work just fine.

-Andi

Signature · 1 line
[email protected]
#20 lore raw

Andi, Thomas,

Quoted 30 lines · Andi Kleen
Quoted 18 lines · Thomas Gleixner
Quoted 7 lines · Andi Kleen
Quoted 4 lines · Thomas Gleixner

Review

Quoted 2 lines
(quoted diff) +2 -0
+        */
+       pfm_arch_resend_irq(ctx);

Do we really need this whole NMI business ?

Without it you cannot profile interrupts off regions well.

Fair enough, but I doubt that this is a real solution.

There is not even an attempt to avoid the obvious wrmrsl races, while there are several comments which explain how expensive wrmrsl is. In the NMI handler we enable the NMI right away. This might cause multiple NMIs for nothing when the NMIs hit between the manipulations of the counters. Not likely but can happen depending on the counter settings.

Quoted 3 lines

Sending an self-IPI from NMI simply sucks: For every NMI we get an extra local interrupt and we have an extra of 2 * NR_ACTIVE_COUNTERS accesses to MSRs.

In newer Intel the counters can be reset/rearmed by accessing only a few global control msrs. But it's probably still a problem on other PMUs.

On the other hand it also has PEBS which allows at least some profiling of irq-off regions without using NMIs.

Quoted 1 line
Quoted 9 lines
Quoted 2 lines

Designing that code to use lockless buffers instead is not really rocket science.

Lockless buffers are nasty, but it works in oprofile at least.

Taking out NMis in the first version at least seems like a reasonable solution. After all you can still use standard oprofile where they work just fine.

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

#21 lore raw
Quoted 10 lines · stephane eranian
Quoted 6 lines

Lockless buffers are nasty, but it works in oprofile at least.

Taking out NMis in the first version at least seems like a reasonable solution. After all you can still use standard oprofile where they work just fine.

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

We can limit the functionality here. Fail or disable the NMI watchdog are both valid solutions.

Thanks,

tglx

#22 lore raw
In reply to stephane eranian
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

The NMI watchdog is now off by default so failing with it enabled is fine.

Longer term having NMI profiling is still a useful feature I think, but of course it needs to be implemented cleanly.

-Andi

Signature · 1 line
[email protected]
#23 lore raw
Quoted 7 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

Quoted 4 lines

Longer term having NMI profiling is still a useful feature I think, but of course it needs to be implemented cleanly.

The difficulty with NMI is locking. Unlike Oprofile, perfmon code needs locking. If you recall our discussion yesterday about passing the file descriptor
around or even using it with multiple threads inside the same process. You have to handle the case where the NMI fires while you are holding a perfmon lock. What you have in the patch (and the the fully-featured version) is that we get the NMI and we stop the PMU WITHOUT grabbing any perfmon lock, and the we repost the interrupt with the regular vector. We also make sure we grab the RIP at NMI. That is the one we want to see reported in the sampling buffer.

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

#24 lore raw

From: "stephane eranian" <[email protected]>
Date: Thu, 27 Nov 2008 12:35:54 +0100

Quoted 2 lines

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

There's only one profiling buffer active on a given cpu, so it's pure per-cpu value insertion.

In any event I think that NMI profiling is a must, especially for the kernel. You get total unusable crap otherwise. I just learned this the hard way having gotten an NMI'ish scheme working on sparc64 just the other day.

#25 lore raw
Quoted 6 lines · David Miller

From: "stephane eranian" <[email protected]>
Date: Thu, 27 Nov 2008 12:35:54 +0100

Quoted 2 lines

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

Quoted 7 lines

There's only one profiling buffer active on a given cpu, so it's pure per-cpu value insertion.

In any event I think that NMI profiling is a must, especially for the kernel. You get total unusable crap otherwise. I just learned this the hard way having gotten an NMI'ish scheme working on sparc64 just the other day.

Not arguing about that, I'm just not agreeing with the implementation.

So for the moment we can go w/o the NMI and implement it cleanly after we got the initial lot in.

Thanks,

tglx

#26 lore raw
Quoted 16 lines · Thomas Gleixner
Quoted 6 lines · David Miller

From: "stephane eranian" <[email protected]>
Date: Thu, 27 Nov 2008 12:35:54 +0100

Quoted 2 lines

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

Quoted 7 lines

There's only one profiling buffer active on a given cpu, so it's pure per-cpu value insertion.

In any event I think that NMI profiling is a must, especially for the kernel. You get total unusable crap otherwise. I just learned this the hard way having gotten an NMI'ish scheme working on sparc64 just the other day.

Quoted 4 lines

Not arguing about that, I'm just not agreeing with the implementation.

So for the moment we can go w/o the NMI and implement it cleanly after we got the initial lot in.

Note once Stephane readds PEBS support (it is currently stripped out) you'll be also able to get somewhat reasonable results at least on modern Intel x86 without NMI profiling. But longer term it is still very useful because PEBS has some drawbacks too

-Andi

Signature · 1 line
[email protected]
#27 lore raw
Quoted 19 lines · Andi Kleen
Quoted 18 lines · Thomas Gleixner
Quoted 6 lines · David Miller

From: "stephane eranian" <[email protected]>
Date: Thu, 27 Nov 2008 12:35:54 +0100

Quoted 2 lines

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

Quoted 7 lines

There's only one profiling buffer active on a given cpu, so it's pure per-cpu value insertion.

In any event I think that NMI profiling is a must, especially for the kernel. You get total unusable crap otherwise. I just learned this the hard way having gotten an NMI'ish scheme working on sparc64 just the other day.

Not arguing about that, I'm just not agreeing with the implementation.

Quoted 7 lines
Quoted 2 lines

So for the moment we can go w/o the NMI and implement it cleanly after we got the initial lot in.

Note once Stephane readds PEBS support (it is currently stripped out) you'll be also able to get somewhat reasonable results at least on modern Intel x86 without NMI profiling. But longer term it is still very useful because PEBS has some drawbacks too

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

#28 lore raw
Quoted 3 lines

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

Assuming that the irqs off regions are not too long (and that's usually the case) that should be enough, shouldn't it?

Sure there are still CPUs with neither IBS or PEBS.

-Andi

Signature · 1 line
[email protected]
#29 lore raw
In reply to stephane eranian
Quoted 3 lines · stephane eranian

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

Exactly the same amount which you get with the NMI/self_IPI out of an irq-off region.

Thanks,

tglx

#30 lore raw
Quoted 8 lines · Thomas Gleixner
Quoted 3 lines · stephane eranian

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

Exactly the same amount which you get with the NMI/self_IPI out of an irq-off region.

Why would you get only one sample per irq-off region if you use NMI? I would think you could get multiple, depending on your sampling period and the size of the region.

#31 lore raw
Quoted 6 lines · stephane eranian
Quoted 5 lines · Thomas Gleixner
Quoted 3 lines · stephane eranian

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

Quoted 6 lines
Quoted 3 lines

Exactly the same amount which you get with the NMI/self_IPI out of an irq-off region.

Why would you get only one sample per irq-off region if you use NMI? I would think you could get multiple, depending on your sampling period and the size of the region.

Because of the self IPI. You would need a NMI safe queue between NMI and self IPI, but then you could as well have the same queue between NMI and process readers.

-Andi

Signature · 1 line
[email protected]
#32 lore raw
In reply to Thomas Gleixner
Quoted 7 lines · Thomas Gleixner
Quoted 3 lines · stephane eranian

That's true for Intel.
On AMD64, I think you can get at most one sample out of a irq-off region using IBS.

Exactly the same amount which you get with the NMI/self_IPI out of an irq-off region.

True. It would really need a NMI safe queue.

-Andi

Signature · 1 line
[email protected]
#33 lore raw
In reply to stephane eranian
Quoted 10 lines · stephane eranian
Quoted 7 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

So? You can disable it on the fly when there is a perfmon user.

#34 lore raw

Peter,

Quoted 7 lines · Peter Zijlstra
Quoted 6 lines · stephane eranian
Quoted 5 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

So? You can disable it on the fly when there is a perfmon user.

Yes, you can. There is clearly an interface to do this. I think this is the best solution. I know it can work because it experimented with this approach no later than last month. But I ran into a bug which I reported on LKML. I did not provide a patch because I did not fully understand the connection to suspend/resume.

The bug has to do with some obscure suspend/resume sequence in:

void setup_apic_nmi_watchdog(void *unused)

{
        if (__get_cpu_var(wd_enabled))
                return;

        /* cheap hack to support suspend/resume */
        /* if cpu0 is not active neither should the other cpus */
        if (smp_processor_id() != 0 && atomic_read(&nmi_active) <= 0)
                return;

Basically, when you re-enable the NMI watchdog, it is not always re-enabled correctly on all CPUs, it depends on the order if which they process the IPI.

#35 lore raw
Quoted 35 lines · stephane eranian

Peter,

Quoted 7 lines · Peter Zijlstra
Quoted 6 lines · stephane eranian
Quoted 5 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

So? You can disable it on the fly when there is a perfmon user.

Yes, you can. There is clearly an interface to do this. I think this is the best solution. I know it can work because it experimented with this approach no later than last month. But I ran into a bug which I reported on LKML. I did not provide a patch because I did not fully understand the connection to suspend/resume.

The bug has to do with some obscure suspend/resume sequence in:

void setup_apic_nmi_watchdog(void *unused)

{
        if (__get_cpu_var(wd_enabled))
                return;

        /* cheap hack to support suspend/resume */
        /* if cpu0 is not active neither should the other cpus */
        if (smp_processor_id() != 0 && atomic_read(&nmi_active) <= 0)
                return;
Quoted 2 lines

Basically, when you re-enable the NMI watchdog, it is not always re-enabled correctly on all CPUs, it depends on the order if which they process the IPI.

Hmm, either we loose that bit and fix the suspend/resume bit properly, or we can send the IPIs one by one in the correct order ;-)

Dunno, CC'ed all the folks who touched it last.

#36 lore raw
In reply to stephane eranian
Quoted 10 lines · stephane eranian
Quoted 7 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

Really? Why?

Old distros of course do it but only because they run old kernels.

Quoted 9 lines

You have to handle the case where the NMI fires while you are holding a perfmon lock. What you have in the patch (and the the fully-featured version) is that we get the NMI and we stop the PMU WITHOUT grabbing any perfmon lock, and the we repost the interrupt with the regular vector. We also make sure we grab the RIP at NMI. That is the one we want to see reported in the sampling buffer.

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

It uses per CPU buffers (so no races on the writer) and readers can of course use a lock to coordinate between themselves.

I wrote a similar scheme for mce_log() (although the current version in tree has some issues too)

-Andi

#37 lore raw
Quoted 7 lines · Andi Kleen
Quoted 6 lines · stephane eranian
Quoted 5 lines · Andi Kleen
Quoted 4 lines

The only reason why I have to deal with NMI is not so much to allow for profiling irq-off regions but because I have to share the PMU with the NMI watchdog. Otherwise I'd have to fail or disable the NMI watchdog on the fly.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

The NMI watchdog is now off by default so failing with it enabled is fine.

Yes, but most likely it is on in distro kernels.

Really? Why?

To make sure they can get a crash dump off of production systems.

Quoted 10 lines

Old distros of course do it but only because they run old kernels.

Quoted 7 lines

You have to handle the case where the NMI fires while you are holding a perfmon lock. What you have in the patch (and the the fully-featured version) is that we get the NMI and we stop the PMU WITHOUT grabbing any perfmon lock, and the we repost the interrupt with the regular vector. We also make sure we grab the RIP at NMI. That is the one we want to see reported in the sampling buffer.

Quoted 6 lines
Quoted 2 lines

I am still wondering how Oprofile handles the case where multiple processes or threads access the same file descriptor.

It uses per CPU buffers (so no races on the writer) and readers can of course use a lock to coordinate between themselves.

What if a threads reprograms the counters while another is reading them? How is the buffer reset?

#38 lore raw
Quoted 1 line

What if a threads reprograms the counters while another is reading them?

In the worst case you get an invalid event, which is then discarded. I think. I've never tried to understand it in all details, but at least it seems to work.

Quoted 1 line

How is the buffer reset?

drivers/oprofile/cpu_buffer.c:

/* Resets the cpu buffer to a sane state. */
void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf)

{
        /* reset these to invalid values; the next sample
         * collected will populate the buffer with proper
         * values to initialize the buffer
         */
        cpu_buf->last_is_kernel = -1;
        cpu_buf->last_task = NULL;
}

-Andi

Signature · 1 line
[email protected]
#39 lore raw
Quoted 12 lines · Andi Kleen
Quoted 1 line

What if a threads reprograms the counters while another is reading them?

In the worst case you get an invalid event, which is then discarded. I think. I've never tried to understand it in all details, but at least it seems to work.

Quoted 1 line

How is the buffer reset?

drivers/oprofile/cpu_buffer.c:

/* Resets the cpu buffer to a sane state. */
void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf)

Quoted 9 lines
{
       /* reset these to invalid values; the next sample
        * collected will populate the buffer with proper
        * values to initialize the buffer
        */
       cpu_buf->last_is_kernel = -1;
       cpu_buf->last_task = NULL;
}

What about a thread doing this and another one in the middle of read the buffer?

Or what about a thread trying to reset the buffer while you're processing an PMU interrupt on another CPU. I know each buffer is per-CPU, but that does not prevent two threads for trying to operate on it at the same time from different CPUs.

#40 lore raw
Quoted 1 line

What about a thread doing this and another one in the middle of read the buffer?

I assume that uses locks. Locking between threads is easy.

Quoted 5 lines

Or what about a thread trying to reset the buffer while you're processing an PMU interrupt on another CPU. I know each buffer is per-CPU, but that does not prevent two threads for trying to operate on it at the same time from different CPUs.

That happens per CPU.

-Andi

Signature · 1 line
[email protected]
#41 lore raw
Quoted 4 lines · Andi Kleen
Quoted 1 line

What about a thread doing this and another one in the middle of read the buffer?

I assume that uses locks. Locking between threads is easy.

I think that is fine as long as the interrupt handler does not need to grab locks.
But that, in turn, means that the state needed/modified by the handler cannot be altered in any other way that could be harmful.

Quoted 8 lines
Quoted 5 lines

Or what about a thread trying to reset the buffer while you're processing an PMU interrupt on another CPU. I know each buffer is per-CPU, but that does not prevent two threads for trying to operate on it at the same time from different CPUs.

That happens per CPU.

So you're saying a thread can only access the buffer from the CPU it is running on?