Prev: Selinux: Remove unused headers skbuff.h in selinux/nlmsgtab.c
Next: epoll clarification sought: multithreaded epoll_wait for UDP sockets?
From: Stephane Eranian on 3 Mar 2010 17:00 On Wed, Mar 3, 2010 at 5:39 PM, Peter Zijlstra <a.p.zijlstra(a)chello.nl> wrote: > Implement support for Intel LBR stacks that support > FREEZE_LBRS_ON_PMI. We do not (yet?) support the LBR config register > because that is SMT wide and would also put undue restraints on the > PEBS users. > You're saying PEBS users have priorities over pure LBR users? Why is that? Without coding this, how would you expose LBR configuration to userland given you're using the PERF_SAMPLE_BRANCH_STACK approach? > Signed-off-by: Peter Zijlstra <a.p.zijlstra(a)chello.nl> > --- > arch/x86/kernel/cpu/perf_event.c | 22 ++ > arch/x86/kernel/cpu/perf_event_intel.c | 13 + > arch/x86/kernel/cpu/perf_event_intel_lbr.c | 228 +++++++++++++++++++++++++++++ > 3 files changed, 263 insertions(+) > > Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event.c > +++ linux-2.6/arch/x86/kernel/cpu/perf_event.c > @@ -48,6 +48,12 @@ struct amd_nb { > struct event_constraint event_constraints[X86_PMC_IDX_MAX]; > }; > > +#define MAX_LBR_ENTRIES 16 > + > +struct lbr_entry { > + u64 from, to, flags; > +}; > + > struct cpu_hw_events { > /* > * Generic x86 PMC bits > @@ -70,6 +76,14 @@ struct cpu_hw_events { > u64 pebs_enabled; > > /* > + * Intel LBR bits > + */ > + int lbr_users; > + int lbr_entries; > + struct lbr_entry lbr_stack[MAX_LBR_ENTRIES]; > + void *lbr_context; > + > + /* > * AMD specific bits > */ > struct amd_nb *amd_nb; > @@ -154,6 +168,13 @@ struct x86_pmu { > int pebs_record_size; > void (*drain_pebs)(void); > struct event_constraint *pebs_constraints; > + > + /* > + * Intel LBR > + */ > + unsigned long lbr_tos, lbr_from, lbr_to; /* MSR base regs */ > + int lbr_nr; /* hardware stack size */ > + int lbr_format; /* hardware format */ > }; > > static struct x86_pmu x86_pmu __read_mostly; > @@ -1238,6 +1259,7 @@ undo: > > #include "perf_event_amd.c" > #include "perf_event_p6.c" > +#include "perf_event_intel_lbr.c" > #include "perf_event_intel_ds.c" > #include "perf_event_intel.c" > > Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_intel.c > +++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c > @@ -480,6 +480,7 @@ static void intel_pmu_disable_all(void) > intel_pmu_disable_bts(); > > intel_pmu_pebs_disable_all(); > + intel_pmu_lbr_disable_all(); > } > > static void intel_pmu_enable_all(void) > @@ -499,6 +500,7 @@ static void intel_pmu_enable_all(void) > } > > intel_pmu_pebs_enable_all(); > + intel_pmu_lbr_enable_all(); > } > > static inline u64 intel_pmu_get_status(void) > @@ -675,6 +677,8 @@ again: > inc_irq_stat(apic_perf_irqs); > ack = status; > > + intel_pmu_lbr_read(); > + > /* > * PEBS overflow sets bit 62 in the global status register > */ > @@ -847,6 +851,8 @@ static __init int intel_pmu_init(void) > memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, > sizeof(hw_cache_event_ids)); > > + intel_pmu_lbr_init_core(); > + > x86_pmu.event_constraints = intel_core2_event_constraints; > pr_cont("Core2 events, "); > break; > @@ -856,13 +862,18 @@ static __init int intel_pmu_init(void) > memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, > sizeof(hw_cache_event_ids)); > > + intel_pmu_lbr_init_nhm(); > + > x86_pmu.event_constraints = intel_nehalem_event_constraints; > pr_cont("Nehalem/Corei7 events, "); > break; > + > case 28: /* Atom */ > memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, > sizeof(hw_cache_event_ids)); > > + intel_pmu_lbr_init_atom(); > + > x86_pmu.event_constraints = intel_gen_event_constraints; > pr_cont("Atom events, "); > break; > @@ -872,6 +883,8 @@ static __init int intel_pmu_init(void) > memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, > sizeof(hw_cache_event_ids)); > > + intel_pmu_lbr_init_nhm(); > + > x86_pmu.event_constraints = intel_westmere_event_constraints; > pr_cont("Westmere events, "); > break; > Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c > =================================================================== > --- /dev/null > +++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c > @@ -0,0 +1,228 @@ > +#ifdef CONFIG_CPU_SUP_INTEL > + > +enum { > + LBR_FORMAT_32 = 0x00, > + LBR_FORMAT_LIP = 0x01, > + LBR_FORMAT_EIP = 0x02, > + LBR_FORMAT_EIP_FLAGS = 0x03, > +}; > + > +/* > + * We only support LBR implementations that have FREEZE_LBRS_ON_PMI > + * otherwise it becomes near impossible to get a reliable stack. > + */ > + > +#define X86_DEBUGCTL_LBR (1 << 0) > +#define X86_DEBUGCTL_FREEZE_LBRS_ON_PMI (1 << 11) > + > +static void __intel_pmu_lbr_enable(void) > +{ > + u64 debugctl; > + > + rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > + debugctl |= (X86_DEBUGCTL_LBR | X86_DEBUGCTL_FREEZE_LBRS_ON_PMI); > + wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +} > + > +static void __intel_pmu_lbr_disable(void) > +{ > + u64 debugctl; > + > + rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > + debugctl &= ~(X86_DEBUGCTL_LBR | X86_DEBUGCTL_FREEZE_LBRS_ON_PMI); > + wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +} > + > +static void intel_pmu_lbr_reset_32(void) > +{ > + int i; > + > + for (i = 0; i < x86_pmu.lbr_nr; i++) > + wrmsrl(x86_pmu.lbr_from + i, 0); > +} > + > +static void intel_pmu_lbr_reset_64(void) > +{ > + int i; > + > + for (i = 0; i < x86_pmu.lbr_nr; i++) { > + wrmsrl(x86_pmu.lbr_from + i, 0); > + wrmsrl(x86_pmu.lbr_to + i, 0); > + } > +} > + > +static void intel_pmu_lbr_reset(void) > +{ > + if (x86_pmu.lbr_format == LBR_FORMAT_32) > + intel_pmu_lbr_reset_32(); > + else > + intel_pmu_lbr_reset_64(); > +} > + > +static void intel_pmu_lbr_enable(struct perf_event *event) > +{ > + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > + if (!x86_pmu.lbr_nr) > + return; > + > + WARN_ON(cpuc->enabled); > + > + /* > + * Reset the LBR stack if this is the first LBR user or > + * we changed task context so as to avoid data leaks. > + */ > + > + if (!cpuc->lbr_users || > + (event->ctx->task && cpuc->lbr_context != event->ctx)) { > + intel_pmu_lbr_reset(); > + cpuc->lbr_context = event->ctx; > + } > + > + cpuc->lbr_users++; > +} > + > +static void intel_pmu_lbr_disable(struct perf_event *event) > +{ > + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > + if (!x86_pmu.lbr_nr) > + return; > + > + cpuc->lbr_users--; > + > + BUG_ON(cpuc->lbr_users < 0); > + WARN_ON(cpuc->enabled); > +} > + > +static void intel_pmu_lbr_enable_all(void) > +{ > + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > + if (cpuc->lbr_users) > + __intel_pmu_lbr_enable(); > +} > + > +static void intel_pmu_lbr_disable_all(void) > +{ > + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > + if (cpuc->lbr_users) > + __intel_pmu_lbr_disable(); > +} > + > +static inline u64 intel_pmu_lbr_tos(void) > +{ > + u64 tos; > + > + rdmsrl(x86_pmu.lbr_tos, tos); > + > + return tos; > +} > + > +static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) > +{ > + unsigned long mask = x86_pmu.lbr_nr - 1; > + u64 tos = intel_pmu_lbr_tos(); > + int i; > + > + for (i = 0; i < x86_pmu.lbr_nr; i++, tos--) { > + unsigned long lbr_idx = (tos - i) & mask; > + union { > + struct { > + u32 from; > + u32 to; > + }; > + u64 lbr; > + } msr_lastbranch; > + > + rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); > + > + cpuc->lbr_stack[i].from = msr_lastbranch.from; > + cpuc->lbr_stack[i].to = msr_lastbranch.to; > + cpuc->lbr_stack[i].flags = 0; > + } > + cpuc->lbr_entries = i; > +} > + > +#define LBR_FROM_FLAG_MISPRED (1ULL << 63) > + > +/* > + * Due to lack of segmentation in Linux the effective address (offset) > + * is the same as the linear address, allowing us to merge the LIP and EIP > + * LBR formats. > + */ > +static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) > +{ > + unsigned long mask = x86_pmu.lbr_nr - 1; > + u64 tos = intel_pmu_lbr_tos(); > + int i; > + > + for (i = 0; i < x86_pmu.lbr_nr; i++, tos--) { > + unsigned long lbr_idx = (tos - i) & mask; > + u64 from, to, flags = 0; > + > + rdmsrl(x86_pmu.lbr_from + lbr_idx, from); > + rdmsrl(x86_pmu.lbr_to + lbr_idx, to); > + > + if (x86_pmu.lbr_format == LBR_FORMAT_EIP_FLAGS) { > + flags = !!(from & LBR_FROM_FLAG_MISPRED); > + from = (u64)((((s64)from) << 1) >> 1); > + } > + > + cpuc->lbr_stack[i].from = from; > + cpuc->lbr_stack[i].to = to; > + cpuc->lbr_stack[i].flags = flags; > + } > + cpuc->lbr_entries = i; > +} > + > +static void intel_pmu_lbr_read(void) > +{ > + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > + if (!cpuc->lbr_users) > + return; > + > + if (x86_pmu.lbr_format == LBR_FORMAT_32) > + intel_pmu_lbr_read_32(cpuc); > + else > + intel_pmu_lbr_read_64(cpuc); > +} > + > +static int intel_pmu_lbr_format(void) > +{ > + u64 capabilities; > + > + rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities); > + return capabilities & 0x1f; > +} > + > +static void intel_pmu_lbr_init_core(void) > +{ > + x86_pmu.lbr_format = intel_pmu_lbr_format(); > + x86_pmu.lbr_nr = 4; > + x86_pmu.lbr_tos = 0x01c9; > + x86_pmu.lbr_from = 0x40; > + x86_pmu.lbr_to = 0x60; > +} > + > +static void intel_pmu_lbr_init_nhm(void) > +{ > + x86_pmu.lbr_format = intel_pmu_lbr_format(); > + x86_pmu.lbr_nr = 16; > + x86_pmu.lbr_tos = 0x01c9; > + x86_pmu.lbr_from = 0x680; > + x86_pmu.lbr_to = 0x6c0; > +} > + > +static void intel_pmu_lbr_init_atom(void) > +{ > + x86_pmu.lbr_format = intel_pmu_lbr_format(); > + x86_pmu.lbr_nr = 8; > + x86_pmu.lbr_tos = 0x01c9; > + x86_pmu.lbr_from = 0x40; > + x86_pmu.lbr_to = 0x60; > +} > + > +#endif /* CONFIG_CPU_SUP_INTEL */ > > -- > > -- Stephane Eranian | EMEA Software Engineering Google France | 38 avenue de l'Opéra | 75002 Paris Tel : +33 (0) 1 42 68 53 00 This email may be confidential or privileged. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it went to the wrong person. Thanks -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
From: Stephane Eranian on 3 Mar 2010 17:00 I don't understand how LBR state is migrated when a per-thread event is moved from one CPU to another. It seems LBR is managed per-cpu. Can you explain this to me? On Wed, Mar 3, 2010 at 5:39 PM, Peter Zijlstra <a.p.zijlstra(a)chello.nl> wrote: > Implement support for Intel LBR stacks that support > FREEZE_LBRS_ON_PMI. We do not (yet?) support the LBR config register > because that is SMT wide and would also put undue restraints on the > PEBS users. > > Signed-off-by: Peter Zijlstra <a.p.zijlstra(a)chello.nl> > --- >  arch/x86/kernel/cpu/perf_event.c      |  22 ++ >  arch/x86/kernel/cpu/perf_event_intel.c   |  13 + >  arch/x86/kernel/cpu/perf_event_intel_lbr.c |  228 +++++++++++++++++++++++++++++ >  3 files changed, 263 insertions(+) > > Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event.c > +++ linux-2.6/arch/x86/kernel/cpu/perf_event.c > @@ -48,6 +48,12 @@ struct amd_nb { >     struct event_constraint event_constraints[X86_PMC_IDX_MAX]; >  }; > > +#define MAX_LBR_ENTRIES         16 > + > +struct lbr_entry { > +    u64   from, to, flags; > +}; > + >  struct cpu_hw_events { >     /* >     * Generic x86 PMC bits > @@ -70,6 +76,14 @@ struct cpu_hw_events { >     u64           pebs_enabled; > >     /* > +     * Intel LBR bits > +     */ > +    int           lbr_users; > +    int           lbr_entries; > +    struct lbr_entry     lbr_stack[MAX_LBR_ENTRIES]; > +    void           *lbr_context; > + > +    /* >     * AMD specific bits >     */ >     struct amd_nb      *amd_nb; > @@ -154,6 +168,13 @@ struct x86_pmu { >     int       pebs_record_size; >     void       (*drain_pebs)(void); >     struct event_constraint *pebs_constraints; > + > +    /* > +     * Intel LBR > +     */ > +    unsigned long  lbr_tos, lbr_from, lbr_to; /* MSR base regs    */ > +    int       lbr_nr;           /* hardware stack size */ > +    int       lbr_format;         /* hardware format   */ >  }; > >  static struct x86_pmu x86_pmu __read_mostly; > @@ -1238,6 +1259,7 @@ undo: > >  #include "perf_event_amd.c" >  #include "perf_event_p6.c" > +#include "perf_event_intel_lbr.c" >  #include "perf_event_intel_ds.c" >  #include "perf_event_intel.c" > > Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_intel.c > +++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c > @@ -480,6 +480,7 @@ static void intel_pmu_disable_all(void) >         intel_pmu_disable_bts(); > >     intel_pmu_pebs_disable_all(); > +    intel_pmu_lbr_disable_all(); >  } > >  static void intel_pmu_enable_all(void) > @@ -499,6 +500,7 @@ static void intel_pmu_enable_all(void) >     } > >     intel_pmu_pebs_enable_all(); > +    intel_pmu_lbr_enable_all(); >  } > >  static inline u64 intel_pmu_get_status(void) > @@ -675,6 +677,8 @@ again: >     inc_irq_stat(apic_perf_irqs); >     ack = status; > > +    intel_pmu_lbr_read(); > + >     /* >     * PEBS overflow sets bit 62 in the global status register >     */ > @@ -847,6 +851,8 @@ static __init int intel_pmu_init(void) >         memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, >            sizeof(hw_cache_event_ids)); > > +        intel_pmu_lbr_init_core(); > + >         x86_pmu.event_constraints = intel_core2_event_constraints; >         pr_cont("Core2 events, "); >         break; > @@ -856,13 +862,18 @@ static __init int intel_pmu_init(void) >         memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, >            sizeof(hw_cache_event_ids)); > > +        intel_pmu_lbr_init_nhm(); > + >         x86_pmu.event_constraints = intel_nehalem_event_constraints; >         pr_cont("Nehalem/Corei7 events, "); >         break; > + >     case 28: /* Atom */ >         memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, >            sizeof(hw_cache_event_ids)); > > +        intel_pmu_lbr_init_atom(); > + >         x86_pmu.event_constraints = intel_gen_event_constraints; >         pr_cont("Atom events, "); >         break; > @@ -872,6 +883,8 @@ static __init int intel_pmu_init(void) >         memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, >            sizeof(hw_cache_event_ids)); > > +        intel_pmu_lbr_init_nhm(); > + >         x86_pmu.event_constraints = intel_westmere_event_constraints; >         pr_cont("Westmere events, "); >         break; > Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c > =================================================================== > --- /dev/null > +++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c > @@ -0,0 +1,228 @@ > +#ifdef CONFIG_CPU_SUP_INTEL > + > +enum { > +    LBR_FORMAT_32      = 0x00, > +    LBR_FORMAT_LIP      = 0x01, > +    LBR_FORMAT_EIP      = 0x02, > +    LBR_FORMAT_EIP_FLAGS   = 0x03, > +}; > + > +/* > + * We only support LBR implementations that have FREEZE_LBRS_ON_PMI > + * otherwise it becomes near impossible to get a reliable stack. > + */ > + > +#define X86_DEBUGCTL_LBR                (1 << 0) > +#define X86_DEBUGCTL_FREEZE_LBRS_ON_PMI         (1 << 11) > + > +static void __intel_pmu_lbr_enable(void) > +{ > +    u64 debugctl; > + > +    rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +    debugctl |= (X86_DEBUGCTL_LBR | X86_DEBUGCTL_FREEZE_LBRS_ON_PMI); > +    wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +} > + > +static void __intel_pmu_lbr_disable(void) > +{ > +    u64 debugctl; > + > +    rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +    debugctl &= ~(X86_DEBUGCTL_LBR | X86_DEBUGCTL_FREEZE_LBRS_ON_PMI); > +    wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); > +} > + > +static void intel_pmu_lbr_reset_32(void) > +{ > +    int i; > + > +    for (i = 0; i < x86_pmu.lbr_nr; i++) > +        wrmsrl(x86_pmu.lbr_from + i, 0); > +} > + > +static void intel_pmu_lbr_reset_64(void) > +{ > +    int i; > + > +    for (i = 0; i < x86_pmu.lbr_nr; i++) { > +        wrmsrl(x86_pmu.lbr_from + i, 0); > +        wrmsrl(x86_pmu.lbr_to  + i, 0); > +    } > +} > + > +static void intel_pmu_lbr_reset(void) > +{ > +    if (x86_pmu.lbr_format == LBR_FORMAT_32) > +        intel_pmu_lbr_reset_32(); > +    else > +        intel_pmu_lbr_reset_64(); > +} > + > +static void intel_pmu_lbr_enable(struct perf_event *event) > +{ > +    struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > +    if (!x86_pmu.lbr_nr) > +        return; > + > +    WARN_ON(cpuc->enabled); > + > +    /* > +     * Reset the LBR stack if this is the first LBR user or > +     * we changed task context so as to avoid data leaks. > +     */ > + > +    if (!cpuc->lbr_users || > +      (event->ctx->task && cpuc->lbr_context != event->ctx)) { > +        intel_pmu_lbr_reset(); > +        cpuc->lbr_context = event->ctx; > +    } > + > +    cpuc->lbr_users++; > +} > + > +static void intel_pmu_lbr_disable(struct perf_event *event) > +{ > +    struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > +    if (!x86_pmu.lbr_nr) > +        return; > + > +    cpuc->lbr_users--; > + > +    BUG_ON(cpuc->lbr_users < 0); > +    WARN_ON(cpuc->enabled); > +} > + > +static void intel_pmu_lbr_enable_all(void) > +{ > +    struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > +    if (cpuc->lbr_users) > +        __intel_pmu_lbr_enable(); > +} > + > +static void intel_pmu_lbr_disable_all(void) > +{ > +    struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > +    if (cpuc->lbr_users) > +        __intel_pmu_lbr_disable(); > +} > + > +static inline u64 intel_pmu_lbr_tos(void) > +{ > +    u64 tos; > + > +    rdmsrl(x86_pmu.lbr_tos, tos); > + > +    return tos; > +} > + > +static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) > +{ > +    unsigned long mask = x86_pmu.lbr_nr - 1; > +    u64 tos = intel_pmu_lbr_tos(); > +    int i; > + > +    for (i = 0; i < x86_pmu.lbr_nr; i++, tos--) { > +        unsigned long lbr_idx = (tos - i) & mask; > +        union { > +            struct { > +                u32 from; > +                u32 to; > +            }; > +            u64   lbr; > +        } msr_lastbranch; > + > +        rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); > + > +        cpuc->lbr_stack[i].from  = msr_lastbranch.from; > +        cpuc->lbr_stack[i].to   = msr_lastbranch.to; > +        cpuc->lbr_stack[i].flags = 0; > +    } > +    cpuc->lbr_entries = i; > +} > + > +#define LBR_FROM_FLAG_MISPRED  (1ULL << 63) > + > +/* > + * Due to lack of segmentation in Linux the effective address (offset) > + * is the same as the linear address, allowing us to merge the LIP and EIP > + * LBR formats. > + */ > +static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) > +{ > +    unsigned long mask = x86_pmu.lbr_nr - 1; > +    u64 tos = intel_pmu_lbr_tos(); > +    int i; > + > +    for (i = 0; i < x86_pmu.lbr_nr; i++, tos--) { > +        unsigned long lbr_idx = (tos - i) & mask; > +        u64 from, to, flags = 0; > + > +        rdmsrl(x86_pmu.lbr_from + lbr_idx, from); > +        rdmsrl(x86_pmu.lbr_to  + lbr_idx, to); > + > +        if (x86_pmu.lbr_format == LBR_FORMAT_EIP_FLAGS) { > +            flags = !!(from & LBR_FROM_FLAG_MISPRED); > +            from = (u64)((((s64)from) << 1) >> 1); > +        } > + > +        cpuc->lbr_stack[i].from  = from; > +        cpuc->lbr_stack[i].to   = to; > +        cpuc->lbr_stack[i].flags = flags; > +    } > +    cpuc->lbr_entries = i; > +} > + > +static void intel_pmu_lbr_read(void) > +{ > +    struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); > + > +    if (!cpuc->lbr_users) > +        return; > + > +    if (x86_pmu.lbr_format == LBR_FORMAT_32) > +        intel_pmu_lbr_read_32(cpuc); > +    else > +        intel_pmu_lbr_read_64(cpuc); > +} > + > +static int intel_pmu_lbr_format(void) > +{ > +    u64 capabilities; > + > +    rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities); > +    return capabilities & 0x1f; > +} > + > +static void intel_pmu_lbr_init_core(void) > +{ > +    x86_pmu.lbr_format = intel_pmu_lbr_format(); > +    x86_pmu.lbr_nr   = 4; > +    x86_pmu.lbr_tos   = 0x01c9; > +    x86_pmu.lbr_from  = 0x40; > +    x86_pmu.lbr_to   = 0x60; > +} > + > +static void intel_pmu_lbr_init_nhm(void) > +{ > +    x86_pmu.lbr_format = intel_pmu_lbr_format(); > +    x86_pmu.lbr_nr   = 16; > +    x86_pmu.lbr_tos   = 0x01c9; > +    x86_pmu.lbr_from  = 0x680; > +    x86_pmu.lbr_to   = 0x6c0; > +} > + > +static void intel_pmu_lbr_init_atom(void) > +{ > +    x86_pmu.lbr_format = intel_pmu_lbr_format(); > +    x86_pmu.lbr_nr   = 8; > +    x86_pmu.lbr_tos   = 0x01c9; > +    x86_pmu.lbr_from  = 0x40; > +    x86_pmu.lbr_to   = 0x60; > +} > + > +#endif /* CONFIG_CPU_SUP_INTEL */ > > -- > > -- Stephane Eranian | EMEA Software Engineering Google France | 38 avenue de l'Opéra | 75002 Paris Tel : +33 (0) 1 42 68 53 00 This email may be confidential or privileged. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it went to the wrong person. Thanks
From: Peter Zijlstra on 4 Mar 2010 04:00 On Wed, 2010-03-03 at 22:57 +0100, Stephane Eranian wrote: > I don't understand how LBR state is migrated when a per-thread event is moved > from one CPU to another. It seems LBR is managed per-cpu. > > Can you explain this to me? It is not, its basically impossible to do given that the TOS doesn't count more bits than is strictly needed. Or we should stop supporting cpu and task users at the same time. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
From: Peter Zijlstra on 4 Mar 2010 04:00 On Wed, 2010-03-03 at 22:52 +0100, Stephane Eranian wrote: > On Wed, Mar 3, 2010 at 5:39 PM, Peter Zijlstra <a.p.zijlstra(a)chello.nl> wrote: > > Implement support for Intel LBR stacks that support > > FREEZE_LBRS_ON_PMI. We do not (yet?) support the LBR config register > > because that is SMT wide and would also put undue restraints on the > > PEBS users. > > > You're saying PEBS users have priorities over pure LBR users? > Why is that? I say no such thing, I only say it would make scheduling the PEBS things more interesting. > Without coding this, how would you expose LBR configuration to userland > given you're using the PERF_SAMPLE_BRANCH_STACK approach? Possibly using a second config word in the attr, but given how sucky the hardware currently is (sharing the config between SMT) I'd be inclined to pretend it doesn't exist for the moment. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
From: Stephane Eranian on 4 Mar 2010 13:00
On Thu, Mar 4, 2010 at 12:58 AM, Peter Zijlstra <peterz(a)infradead.org> wrote: > On Wed, 2010-03-03 at 22:57 +0100, Stephane Eranian wrote: >> I don't understand how LBR state is migrated when a per-thread event is moved >> from one CPU to another. It seems LBR is managed per-cpu. >> >> Can you explain this to me? > > It is not, its basically impossible to do given that the TOS doesn't > count more bits than is strictly needed. > I don't get that about the TOS. So you are saying that one context switch out, you drop the current content of LBR. When you are scheduled back in on an another CPU, you grab whatever is there? > Or we should stop supporting cpu and task users at the same time. > Or you should consider LBR as an event which has a constraint that it can only run on one pseudo counter (similar to what you do with BTS). Scheduling would take care of the mutual exclusion. Multiplexing would provide the work-around. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ |