mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (172 commits) perf_event, amd: Fix spinlock initialization perf_event: Fix preempt warning in perf_clock() perf tools: Flush maps on COMM events perf_events, x86: Split PMU definitions into separate files perf annotate: Handle samples not at objdump output addr boundaries perf_events, x86: Remove superflous MSR writes perf_events: Simplify code by removing cpu argument to hw_perf_group_sched_in() perf_events, x86: AMD event scheduling perf_events: Add new start/stop PMU callbacks perf_events: Report the MMAP pgoff value in bytes perf annotate: Defer allocating sym_priv->hist array perf symbols: Improve debugging information about symtab origins perf top: Use a macro instead of a constant variable perf symbols: Check the right return variable perf/scripts: Tag syscall_name helper as not yet available perf/scripts: Add perf-trace-python Documentation perf/scripts: Remove unnecessary PyTuple resizes perf/scripts: Add syscall tracing scripts perf/scripts: Add Python scripting engine perf/scripts: Remove check-perf-trace from listed scripts ... Fix trivial conflict in tools/perf/util/probe-event.c
This commit is contained in:
@@ -24,6 +24,7 @@ Synopsis of kprobe_events
|
||||
-------------------------
|
||||
p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe
|
||||
r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe
|
||||
-:[GRP/]EVENT : Clear a probe
|
||||
|
||||
GRP : Group name. If omitted, use "kprobes" for it.
|
||||
EVENT : Event name. If omitted, the event name is generated
|
||||
@@ -37,15 +38,12 @@ Synopsis of kprobe_events
|
||||
@SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol)
|
||||
$stackN : Fetch Nth entry of stack (N >= 0)
|
||||
$stack : Fetch stack address.
|
||||
$argN : Fetch function argument. (N >= 0)(*)
|
||||
$retval : Fetch return value.(**)
|
||||
+|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(***)
|
||||
$retval : Fetch return value.(*)
|
||||
+|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
|
||||
NAME=FETCHARG: Set NAME as the argument name of FETCHARG.
|
||||
|
||||
(*) aN may not correct on asmlinkaged functions and at the middle of
|
||||
function body.
|
||||
(**) only for return probe.
|
||||
(***) this is useful for fetching a field of data structures.
|
||||
(*) only for return probe.
|
||||
(**) this is useful for fetching a field of data structures.
|
||||
|
||||
|
||||
Per-Probe Event Filtering
|
||||
@@ -82,13 +80,16 @@ Usage examples
|
||||
To add a probe as a new event, write a new definition to kprobe_events
|
||||
as below.
|
||||
|
||||
echo p:myprobe do_sys_open dfd=$arg0 filename=$arg1 flags=$arg2 mode=$arg3 > /sys/kernel/debug/tracing/kprobe_events
|
||||
echo 'p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)' > /sys/kernel/debug/tracing/kprobe_events
|
||||
|
||||
This sets a kprobe on the top of do_sys_open() function with recording
|
||||
1st to 4th arguments as "myprobe" event. As this example shows, users can
|
||||
choose more familiar names for each arguments.
|
||||
1st to 4th arguments as "myprobe" event. Note, which register/stack entry is
|
||||
assigned to each function argument depends on arch-specific ABI. If you unsure
|
||||
the ABI, please try to use probe subcommand of perf-tools (you can find it
|
||||
under tools/perf/).
|
||||
As this example shows, users can choose more familiar names for each arguments.
|
||||
|
||||
echo r:myretprobe do_sys_open $retval >> /sys/kernel/debug/tracing/kprobe_events
|
||||
echo 'r:myretprobe do_sys_open $retval' >> /sys/kernel/debug/tracing/kprobe_events
|
||||
|
||||
This sets a kretprobe on the return point of do_sys_open() function with
|
||||
recording return value as "myretprobe" event.
|
||||
@@ -97,23 +98,24 @@ recording return value as "myretprobe" event.
|
||||
|
||||
cat /sys/kernel/debug/tracing/events/kprobes/myprobe/format
|
||||
name: myprobe
|
||||
ID: 75
|
||||
ID: 780
|
||||
format:
|
||||
field:unsigned short common_type; offset:0; size:2;
|
||||
field:unsigned char common_flags; offset:2; size:1;
|
||||
field:unsigned char common_preempt_count; offset:3; size:1;
|
||||
field:int common_pid; offset:4; size:4;
|
||||
field:int common_tgid; offset:8; size:4;
|
||||
field:unsigned short common_type; offset:0; size:2; signed:0;
|
||||
field:unsigned char common_flags; offset:2; size:1; signed:0;
|
||||
field:unsigned char common_preempt_count; offset:3; size:1;signed:0;
|
||||
field:int common_pid; offset:4; size:4; signed:1;
|
||||
field:int common_lock_depth; offset:8; size:4; signed:1;
|
||||
|
||||
field: unsigned long ip; offset:16;tsize:8;
|
||||
field: int nargs; offset:24;tsize:4;
|
||||
field: unsigned long dfd; offset:32;tsize:8;
|
||||
field: unsigned long filename; offset:40;tsize:8;
|
||||
field: unsigned long flags; offset:48;tsize:8;
|
||||
field: unsigned long mode; offset:56;tsize:8;
|
||||
field:unsigned long __probe_ip; offset:12; size:4; signed:0;
|
||||
field:int __probe_nargs; offset:16; size:4; signed:1;
|
||||
field:unsigned long dfd; offset:20; size:4; signed:0;
|
||||
field:unsigned long filename; offset:24; size:4; signed:0;
|
||||
field:unsigned long flags; offset:28; size:4; signed:0;
|
||||
field:unsigned long mode; offset:32; size:4; signed:0;
|
||||
|
||||
print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->ip, REC->dfd, REC->filename, REC->flags, REC->mode
|
||||
|
||||
print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->__probe_ip,
|
||||
REC->dfd, REC->filename, REC->flags, REC->mode
|
||||
|
||||
You can see that the event has 4 arguments as in the expressions you specified.
|
||||
|
||||
@@ -121,6 +123,12 @@ print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->ip, REC->dfd, R
|
||||
|
||||
This clears all probe points.
|
||||
|
||||
Or,
|
||||
|
||||
echo -:myprobe >> kprobe_events
|
||||
|
||||
This clears probe points selectively.
|
||||
|
||||
Right after definition, each event is disabled by default. For tracing these
|
||||
events, you need to enable it.
|
||||
|
||||
@@ -146,4 +154,3 @@ events, you need to enable it.
|
||||
returns from SYMBOL(e.g. "sys_open+0x1b/0x1d <- do_sys_open" means kernel
|
||||
returns from do_sys_open to sys_open+0x1b).
|
||||
|
||||
|
||||
|
||||
@@ -870,7 +870,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
|
||||
return 1;
|
||||
|
||||
ss_probe:
|
||||
#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER)
|
||||
#if !defined(CONFIG_PREEMPT)
|
||||
if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) {
|
||||
/* Boost up -- we can execute copied instructions directly */
|
||||
ia64_psr(regs)->ri = p->ainsn.slot;
|
||||
|
||||
@@ -495,9 +495,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
|
||||
|
||||
entry->nr = 0;
|
||||
|
||||
if (current->pid == 0) /* idle task? */
|
||||
return entry;
|
||||
|
||||
if (!user_mode(regs)) {
|
||||
perf_callchain_kernel(regs, entry);
|
||||
if (current->mm)
|
||||
|
||||
@@ -718,10 +718,10 @@ static int collect_events(struct perf_event *group, int max_count,
|
||||
return n;
|
||||
}
|
||||
|
||||
static void event_sched_in(struct perf_event *event, int cpu)
|
||||
static void event_sched_in(struct perf_event *event)
|
||||
{
|
||||
event->state = PERF_EVENT_STATE_ACTIVE;
|
||||
event->oncpu = cpu;
|
||||
event->oncpu = smp_processor_id();
|
||||
event->tstamp_running += event->ctx->time - event->tstamp_stopped;
|
||||
if (is_software_event(event))
|
||||
event->pmu->enable(event);
|
||||
@@ -735,7 +735,7 @@ static void event_sched_in(struct perf_event *event, int cpu)
|
||||
*/
|
||||
int hw_perf_group_sched_in(struct perf_event *group_leader,
|
||||
struct perf_cpu_context *cpuctx,
|
||||
struct perf_event_context *ctx, int cpu)
|
||||
struct perf_event_context *ctx)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
long i, n, n0;
|
||||
@@ -766,10 +766,10 @@ int hw_perf_group_sched_in(struct perf_event *group_leader,
|
||||
cpuhw->event[i]->hw.config = cpuhw->events[i];
|
||||
cpuctx->active_oncpu += n;
|
||||
n = 1;
|
||||
event_sched_in(group_leader, cpu);
|
||||
event_sched_in(group_leader);
|
||||
list_for_each_entry(sub, &group_leader->sibling_list, group_entry) {
|
||||
if (sub->state != PERF_EVENT_STATE_OFF) {
|
||||
event_sched_in(sub, cpu);
|
||||
event_sched_in(sub);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,6 @@ perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||
|
||||
is_user = user_mode(regs);
|
||||
|
||||
if (!current || current->pid == 0)
|
||||
return;
|
||||
|
||||
if (is_user && current->state != TASK_RUNNING)
|
||||
return;
|
||||
|
||||
|
||||
@@ -980,10 +980,10 @@ static int collect_events(struct perf_event *group, int max_count,
|
||||
return n;
|
||||
}
|
||||
|
||||
static void event_sched_in(struct perf_event *event, int cpu)
|
||||
static void event_sched_in(struct perf_event *event)
|
||||
{
|
||||
event->state = PERF_EVENT_STATE_ACTIVE;
|
||||
event->oncpu = cpu;
|
||||
event->oncpu = smp_processor_id();
|
||||
event->tstamp_running += event->ctx->time - event->tstamp_stopped;
|
||||
if (is_software_event(event))
|
||||
event->pmu->enable(event);
|
||||
@@ -991,7 +991,7 @@ static void event_sched_in(struct perf_event *event, int cpu)
|
||||
|
||||
int hw_perf_group_sched_in(struct perf_event *group_leader,
|
||||
struct perf_cpu_context *cpuctx,
|
||||
struct perf_event_context *ctx, int cpu)
|
||||
struct perf_event_context *ctx)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
struct perf_event *sub;
|
||||
@@ -1015,10 +1015,10 @@ int hw_perf_group_sched_in(struct perf_event *group_leader,
|
||||
|
||||
cpuctx->active_oncpu += n;
|
||||
n = 1;
|
||||
event_sched_in(group_leader, cpu);
|
||||
event_sched_in(group_leader);
|
||||
list_for_each_entry(sub, &group_leader->sibling_list, group_entry) {
|
||||
if (sub->state != PERF_EVENT_STATE_OFF) {
|
||||
event_sched_in(sub, cpu);
|
||||
event_sched_in(sub);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *text, void *text_end);
|
||||
extern void alternatives_smp_module_del(struct module *mod);
|
||||
extern void alternatives_smp_switch(int smp);
|
||||
extern int alternatives_text_reserved(void *start, void *end);
|
||||
#else
|
||||
static inline void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end) {}
|
||||
static inline void alternatives_smp_module_del(struct module *mod) {}
|
||||
static inline void alternatives_smp_switch(int smp) {}
|
||||
static inline int alternatives_text_reserved(void *start, void *end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/* alternative assembly primitive: */
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
which debugging register was responsible for the trap. The other bits
|
||||
are either reserved or not of interest to us. */
|
||||
|
||||
/* Define reserved bits in DR6 which are always set to 1 */
|
||||
#define DR6_RESERVED (0xFFFF0FF0)
|
||||
|
||||
#define DR_TRAP0 (0x1) /* db0 */
|
||||
#define DR_TRAP1 (0x2) /* db1 */
|
||||
#define DR_TRAP2 (0x4) /* db2 */
|
||||
|
||||
@@ -19,7 +19,6 @@ extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
|
||||
extern int check_nmi_watchdog(void);
|
||||
extern int nmi_watchdog_enabled;
|
||||
extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
|
||||
extern int avail_to_resrv_perfctr_nmi(unsigned int);
|
||||
extern int reserve_perfctr_nmi(unsigned int);
|
||||
extern void release_perfctr_nmi(unsigned int);
|
||||
extern int reserve_evntsel_nmi(unsigned int);
|
||||
|
||||
@@ -27,7 +27,14 @@
|
||||
/*
|
||||
* Includes eventsel and unit mask as well:
|
||||
*/
|
||||
#define ARCH_PERFMON_EVENT_MASK 0xffff
|
||||
|
||||
|
||||
#define INTEL_ARCH_EVTSEL_MASK 0x000000FFULL
|
||||
#define INTEL_ARCH_UNIT_MASK 0x0000FF00ULL
|
||||
#define INTEL_ARCH_EDGE_MASK 0x00040000ULL
|
||||
#define INTEL_ARCH_INV_MASK 0x00800000ULL
|
||||
#define INTEL_ARCH_CNT_MASK 0xFF000000ULL
|
||||
#define INTEL_ARCH_EVENT_MASK (INTEL_ARCH_UNIT_MASK|INTEL_ARCH_EVTSEL_MASK)
|
||||
|
||||
/*
|
||||
* filter mask to validate fixed counter events.
|
||||
@@ -38,7 +45,12 @@
|
||||
* The other filters are supported by fixed counters.
|
||||
* The any-thread option is supported starting with v3.
|
||||
*/
|
||||
#define ARCH_PERFMON_EVENT_FILTER_MASK 0xff840000
|
||||
#define INTEL_ARCH_FIXED_MASK \
|
||||
(INTEL_ARCH_CNT_MASK| \
|
||||
INTEL_ARCH_INV_MASK| \
|
||||
INTEL_ARCH_EDGE_MASK|\
|
||||
INTEL_ARCH_UNIT_MASK|\
|
||||
INTEL_ARCH_EVTSEL_MASK)
|
||||
|
||||
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
|
||||
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
|
||||
|
||||
@@ -274,10 +274,6 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get Nth argument at function call */
|
||||
extern unsigned long regs_get_argument_nth(struct pt_regs *regs,
|
||||
unsigned int n);
|
||||
|
||||
/*
|
||||
* These are defined as per linux/ptrace.h, which see.
|
||||
*/
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
extern int kstack_depth_to_print;
|
||||
|
||||
int x86_is_stack_id(int id, char *name);
|
||||
|
||||
struct thread_info;
|
||||
struct stacktrace_ops;
|
||||
|
||||
|
||||
@@ -390,6 +390,24 @@ void alternatives_smp_switch(int smp)
|
||||
mutex_unlock(&smp_alt);
|
||||
}
|
||||
|
||||
/* Return 1 if the address range is reserved for smp-alternatives */
|
||||
int alternatives_text_reserved(void *start, void *end)
|
||||
{
|
||||
struct smp_alt_module *mod;
|
||||
u8 **ptr;
|
||||
u8 *text_start = start;
|
||||
u8 *text_end = end;
|
||||
|
||||
list_for_each_entry(mod, &smp_alt_modules, next) {
|
||||
if (mod->text > text_end || mod->text_end < text_start)
|
||||
continue;
|
||||
for (ptr = mod->locks; ptr < mod->locks_end; ptr++)
|
||||
if (text_start <= *ptr && text_end >= *ptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
|
||||
+572
-1358
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,416 @@
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(amd_nb_lock);
|
||||
|
||||
static __initconst u64 amd_hw_cache_event_ids
|
||||
[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
|
||||
{
|
||||
[ C(L1D) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */
|
||||
[ C(RESULT_MISS) ] = 0x0041, /* Data Cache Misses */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0267, /* Data Prefetcher :attempts */
|
||||
[ C(RESULT_MISS) ] = 0x0167, /* Data Prefetcher :cancelled */
|
||||
},
|
||||
},
|
||||
[ C(L1I ) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0080, /* Instruction cache fetches */
|
||||
[ C(RESULT_MISS) ] = 0x0081, /* Instruction cache misses */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x014B, /* Prefetch Instructions :Load */
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
},
|
||||
[ C(LL ) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x037D, /* Requests to L2 Cache :IC+DC */
|
||||
[ C(RESULT_MISS) ] = 0x037E, /* L2 Cache Misses : IC+DC */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x017F, /* L2 Fill/Writeback */
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0,
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
},
|
||||
[ C(DTLB) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */
|
||||
[ C(RESULT_MISS) ] = 0x0046, /* L1 DTLB and L2 DLTB Miss */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0,
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0,
|
||||
[ C(RESULT_MISS) ] = 0,
|
||||
},
|
||||
},
|
||||
[ C(ITLB) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x0080, /* Instruction fecthes */
|
||||
[ C(RESULT_MISS) ] = 0x0085, /* Instr. fetch ITLB misses */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
},
|
||||
},
|
||||
[ C(BPU ) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = 0x00c2, /* Retired Branch Instr. */
|
||||
[ C(RESULT_MISS) ] = 0x00c3, /* Retired Mispredicted BI */
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* AMD Performance Monitor K7 and later.
|
||||
*/
|
||||
static const u64 amd_perfmon_event_map[] =
|
||||
{
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 0x0076,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x0081,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5,
|
||||
};
|
||||
|
||||
static u64 amd_pmu_event_map(int hw_event)
|
||||
{
|
||||
return amd_perfmon_event_map[hw_event];
|
||||
}
|
||||
|
||||
static u64 amd_pmu_raw_event(u64 hw_event)
|
||||
{
|
||||
#define K7_EVNTSEL_EVENT_MASK 0xF000000FFULL
|
||||
#define K7_EVNTSEL_UNIT_MASK 0x00000FF00ULL
|
||||
#define K7_EVNTSEL_EDGE_MASK 0x000040000ULL
|
||||
#define K7_EVNTSEL_INV_MASK 0x000800000ULL
|
||||
#define K7_EVNTSEL_REG_MASK 0x0FF000000ULL
|
||||
|
||||
#define K7_EVNTSEL_MASK \
|
||||
(K7_EVNTSEL_EVENT_MASK | \
|
||||
K7_EVNTSEL_UNIT_MASK | \
|
||||
K7_EVNTSEL_EDGE_MASK | \
|
||||
K7_EVNTSEL_INV_MASK | \
|
||||
K7_EVNTSEL_REG_MASK)
|
||||
|
||||
return hw_event & K7_EVNTSEL_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* AMD64 events are detected based on their event codes.
|
||||
*/
|
||||
static inline int amd_is_nb_event(struct hw_perf_event *hwc)
|
||||
{
|
||||
return (hwc->config & 0xe0) == 0xe0;
|
||||
}
|
||||
|
||||
static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
|
||||
struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct amd_nb *nb = cpuc->amd_nb;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* only care about NB events
|
||||
*/
|
||||
if (!(nb && amd_is_nb_event(hwc)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* need to scan whole list because event may not have
|
||||
* been assigned during scheduling
|
||||
*
|
||||
* no race condition possible because event can only
|
||||
* be removed on one CPU at a time AND PMU is disabled
|
||||
* when we come here
|
||||
*/
|
||||
for (i = 0; i < x86_pmu.num_events; i++) {
|
||||
if (nb->owners[i] == event) {
|
||||
cmpxchg(nb->owners+i, event, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AMD64 NorthBridge events need special treatment because
|
||||
* counter access needs to be synchronized across all cores
|
||||
* of a package. Refer to BKDG section 3.12
|
||||
*
|
||||
* NB events are events measuring L3 cache, Hypertransport
|
||||
* traffic. They are identified by an event code >= 0xe00.
|
||||
* They measure events on the NorthBride which is shared
|
||||
* by all cores on a package. NB events are counted on a
|
||||
* shared set of counters. When a NB event is programmed
|
||||
* in a counter, the data actually comes from a shared
|
||||
* counter. Thus, access to those counters needs to be
|
||||
* synchronized.
|
||||
*
|
||||
* We implement the synchronization such that no two cores
|
||||
* can be measuring NB events using the same counters. Thus,
|
||||
* we maintain a per-NB allocation table. The available slot
|
||||
* is propagated using the event_constraint structure.
|
||||
*
|
||||
* We provide only one choice for each NB event based on
|
||||
* the fact that only NB events have restrictions. Consequently,
|
||||
* if a counter is available, there is a guarantee the NB event
|
||||
* will be assigned to it. If no slot is available, an empty
|
||||
* constraint is returned and scheduling will eventually fail
|
||||
* for this event.
|
||||
*
|
||||
* Note that all cores attached the same NB compete for the same
|
||||
* counters to host NB events, this is why we use atomic ops. Some
|
||||
* multi-chip CPUs may have more than one NB.
|
||||
*
|
||||
* Given that resources are allocated (cmpxchg), they must be
|
||||
* eventually freed for others to use. This is accomplished by
|
||||
* calling amd_put_event_constraints().
|
||||
*
|
||||
* Non NB events are not impacted by this restriction.
|
||||
*/
|
||||
static struct event_constraint *
|
||||
amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct amd_nb *nb = cpuc->amd_nb;
|
||||
struct perf_event *old = NULL;
|
||||
int max = x86_pmu.num_events;
|
||||
int i, j, k = -1;
|
||||
|
||||
/*
|
||||
* if not NB event or no NB, then no constraints
|
||||
*/
|
||||
if (!(nb && amd_is_nb_event(hwc)))
|
||||
return &unconstrained;
|
||||
|
||||
/*
|
||||
* detect if already present, if so reuse
|
||||
*
|
||||
* cannot merge with actual allocation
|
||||
* because of possible holes
|
||||
*
|
||||
* event can already be present yet not assigned (in hwc->idx)
|
||||
* because of successive calls to x86_schedule_events() from
|
||||
* hw_perf_group_sched_in() without hw_perf_enable()
|
||||
*/
|
||||
for (i = 0; i < max; i++) {
|
||||
/*
|
||||
* keep track of first free slot
|
||||
*/
|
||||
if (k == -1 && !nb->owners[i])
|
||||
k = i;
|
||||
|
||||
/* already present, reuse */
|
||||
if (nb->owners[i] == event)
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* not present, so grab a new slot
|
||||
* starting either at:
|
||||
*/
|
||||
if (hwc->idx != -1) {
|
||||
/* previous assignment */
|
||||
i = hwc->idx;
|
||||
} else if (k != -1) {
|
||||
/* start from free slot found */
|
||||
i = k;
|
||||
} else {
|
||||
/*
|
||||
* event not found, no slot found in
|
||||
* first pass, try again from the
|
||||
* beginning
|
||||
*/
|
||||
i = 0;
|
||||
}
|
||||
j = i;
|
||||
do {
|
||||
old = cmpxchg(nb->owners+i, NULL, event);
|
||||
if (!old)
|
||||
break;
|
||||
if (++i == max)
|
||||
i = 0;
|
||||
} while (i != j);
|
||||
done:
|
||||
if (!old)
|
||||
return &nb->event_constraints[i];
|
||||
|
||||
return &emptyconstraint;
|
||||
}
|
||||
|
||||
static __initconst struct x86_pmu amd_pmu = {
|
||||
.name = "AMD",
|
||||
.handle_irq = x86_pmu_handle_irq,
|
||||
.disable_all = x86_pmu_disable_all,
|
||||
.enable_all = x86_pmu_enable_all,
|
||||
.enable = x86_pmu_enable_event,
|
||||
.disable = x86_pmu_disable_event,
|
||||
.eventsel = MSR_K7_EVNTSEL0,
|
||||
.perfctr = MSR_K7_PERFCTR0,
|
||||
.event_map = amd_pmu_event_map,
|
||||
.raw_event = amd_pmu_raw_event,
|
||||
.max_events = ARRAY_SIZE(amd_perfmon_event_map),
|
||||
.num_events = 4,
|
||||
.event_bits = 48,
|
||||
.event_mask = (1ULL << 48) - 1,
|
||||
.apic = 1,
|
||||
/* use highest bit to detect overflow */
|
||||
.max_period = (1ULL << 47) - 1,
|
||||
.get_event_constraints = amd_get_event_constraints,
|
||||
.put_event_constraints = amd_put_event_constraints
|
||||
};
|
||||
|
||||
static struct amd_nb *amd_alloc_nb(int cpu, int nb_id)
|
||||
{
|
||||
struct amd_nb *nb;
|
||||
int i;
|
||||
|
||||
nb = kmalloc(sizeof(struct amd_nb), GFP_KERNEL);
|
||||
if (!nb)
|
||||
return NULL;
|
||||
|
||||
memset(nb, 0, sizeof(*nb));
|
||||
nb->nb_id = nb_id;
|
||||
|
||||
/*
|
||||
* initialize all possible NB constraints
|
||||
*/
|
||||
for (i = 0; i < x86_pmu.num_events; i++) {
|
||||
set_bit(i, nb->event_constraints[i].idxmsk);
|
||||
nb->event_constraints[i].weight = 1;
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
static void amd_pmu_cpu_online(int cpu)
|
||||
{
|
||||
struct cpu_hw_events *cpu1, *cpu2;
|
||||
struct amd_nb *nb = NULL;
|
||||
int i, nb_id;
|
||||
|
||||
if (boot_cpu_data.x86_max_cores < 2)
|
||||
return;
|
||||
|
||||
/*
|
||||
* function may be called too early in the
|
||||
* boot process, in which case nb_id is bogus
|
||||
*/
|
||||
nb_id = amd_get_nb_id(cpu);
|
||||
if (nb_id == BAD_APICID)
|
||||
return;
|
||||
|
||||
cpu1 = &per_cpu(cpu_hw_events, cpu);
|
||||
cpu1->amd_nb = NULL;
|
||||
|
||||
raw_spin_lock(&amd_nb_lock);
|
||||
|
||||
for_each_online_cpu(i) {
|
||||
cpu2 = &per_cpu(cpu_hw_events, i);
|
||||
nb = cpu2->amd_nb;
|
||||
if (!nb)
|
||||
continue;
|
||||
if (nb->nb_id == nb_id)
|
||||
goto found;
|
||||
}
|
||||
|
||||
nb = amd_alloc_nb(cpu, nb_id);
|
||||
if (!nb) {
|
||||
pr_err("perf_events: failed NB allocation for CPU%d\n", cpu);
|
||||
raw_spin_unlock(&amd_nb_lock);
|
||||
return;
|
||||
}
|
||||
found:
|
||||
nb->refcnt++;
|
||||
cpu1->amd_nb = nb;
|
||||
|
||||
raw_spin_unlock(&amd_nb_lock);
|
||||
}
|
||||
|
||||
static void amd_pmu_cpu_offline(int cpu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
|
||||
if (boot_cpu_data.x86_max_cores < 2)
|
||||
return;
|
||||
|
||||
cpuhw = &per_cpu(cpu_hw_events, cpu);
|
||||
|
||||
raw_spin_lock(&amd_nb_lock);
|
||||
|
||||
if (--cpuhw->amd_nb->refcnt == 0)
|
||||
kfree(cpuhw->amd_nb);
|
||||
|
||||
cpuhw->amd_nb = NULL;
|
||||
|
||||
raw_spin_unlock(&amd_nb_lock);
|
||||
}
|
||||
|
||||
static __init int amd_pmu_init(void)
|
||||
{
|
||||
/* Performance-monitoring supported from K7 and later: */
|
||||
if (boot_cpu_data.x86 < 6)
|
||||
return -ENODEV;
|
||||
|
||||
x86_pmu = amd_pmu;
|
||||
|
||||
/* Events are common for all AMDs */
|
||||
memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
|
||||
/*
|
||||
* explicitly initialize the boot cpu, other cpus will get
|
||||
* the cpu hotplug callbacks from smp_init()
|
||||
*/
|
||||
amd_pmu_cpu_online(smp_processor_id());
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_CPU_SUP_AMD */
|
||||
|
||||
static int amd_pmu_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_pmu_cpu_online(int cpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void amd_pmu_cpu_offline(int cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
#ifdef CONFIG_CPU_SUP_INTEL
|
||||
|
||||
/*
|
||||
* Not sure about some of these
|
||||
*/
|
||||
static const u64 p6_perfmon_event_map[] =
|
||||
{
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 0x0079,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0f2e,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x012e,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5,
|
||||
[PERF_COUNT_HW_BUS_CYCLES] = 0x0062,
|
||||
};
|
||||
|
||||
static u64 p6_pmu_event_map(int hw_event)
|
||||
{
|
||||
return p6_perfmon_event_map[hw_event];
|
||||
}
|
||||
|
||||
/*
|
||||
* Event setting that is specified not to count anything.
|
||||
* We use this to effectively disable a counter.
|
||||
*
|
||||
* L2_RQSTS with 0 MESI unit mask.
|
||||
*/
|
||||
#define P6_NOP_EVENT 0x0000002EULL
|
||||
|
||||
static u64 p6_pmu_raw_event(u64 hw_event)
|
||||
{
|
||||
#define P6_EVNTSEL_EVENT_MASK 0x000000FFULL
|
||||
#define P6_EVNTSEL_UNIT_MASK 0x0000FF00ULL
|
||||
#define P6_EVNTSEL_EDGE_MASK 0x00040000ULL
|
||||
#define P6_EVNTSEL_INV_MASK 0x00800000ULL
|
||||
#define P6_EVNTSEL_REG_MASK 0xFF000000ULL
|
||||
|
||||
#define P6_EVNTSEL_MASK \
|
||||
(P6_EVNTSEL_EVENT_MASK | \
|
||||
P6_EVNTSEL_UNIT_MASK | \
|
||||
P6_EVNTSEL_EDGE_MASK | \
|
||||
P6_EVNTSEL_INV_MASK | \
|
||||
P6_EVNTSEL_REG_MASK)
|
||||
|
||||
return hw_event & P6_EVNTSEL_MASK;
|
||||
}
|
||||
|
||||
static struct event_constraint p6_event_constraints[] =
|
||||
{
|
||||
INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
|
||||
INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
|
||||
INTEL_EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */
|
||||
INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
|
||||
INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
|
||||
INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
static void p6_pmu_disable_all(void)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
/* p6 only has one enable register */
|
||||
rdmsrl(MSR_P6_EVNTSEL0, val);
|
||||
val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
|
||||
wrmsrl(MSR_P6_EVNTSEL0, val);
|
||||
}
|
||||
|
||||
static void p6_pmu_enable_all(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
/* p6 only has one enable register */
|
||||
rdmsrl(MSR_P6_EVNTSEL0, val);
|
||||
val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
|
||||
wrmsrl(MSR_P6_EVNTSEL0, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
p6_pmu_disable_event(struct hw_perf_event *hwc, int idx)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
u64 val = P6_NOP_EVENT;
|
||||
|
||||
if (cpuc->enabled)
|
||||
val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
|
||||
|
||||
(void)checking_wrmsrl(hwc->config_base + idx, val);
|
||||
}
|
||||
|
||||
static void p6_pmu_enable_event(struct hw_perf_event *hwc, int idx)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
u64 val;
|
||||
|
||||
val = hwc->config;
|
||||
if (cpuc->enabled)
|
||||
val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
|
||||
|
||||
(void)checking_wrmsrl(hwc->config_base + idx, val);
|
||||
}
|
||||
|
||||
static __initconst struct x86_pmu p6_pmu = {
|
||||
.name = "p6",
|
||||
.handle_irq = x86_pmu_handle_irq,
|
||||
.disable_all = p6_pmu_disable_all,
|
||||
.enable_all = p6_pmu_enable_all,
|
||||
.enable = p6_pmu_enable_event,
|
||||
.disable = p6_pmu_disable_event,
|
||||
.eventsel = MSR_P6_EVNTSEL0,
|
||||
.perfctr = MSR_P6_PERFCTR0,
|
||||
.event_map = p6_pmu_event_map,
|
||||
.raw_event = p6_pmu_raw_event,
|
||||
.max_events = ARRAY_SIZE(p6_perfmon_event_map),
|
||||
.apic = 1,
|
||||
.max_period = (1ULL << 31) - 1,
|
||||
.version = 0,
|
||||
.num_events = 2,
|
||||
/*
|
||||
* Events have 40 bits implemented. However they are designed such
|
||||
* that bits [32-39] are sign extensions of bit 31. As such the
|
||||
* effective width of a event for P6-like PMU is 32 bits only.
|
||||
*
|
||||
* See IA-32 Intel Architecture Software developer manual Vol 3B
|
||||
*/
|
||||
.event_bits = 32,
|
||||
.event_mask = (1ULL << 32) - 1,
|
||||
.get_event_constraints = x86_get_event_constraints,
|
||||
.event_constraints = p6_event_constraints,
|
||||
};
|
||||
|
||||
static __init int p6_pmu_init(void)
|
||||
{
|
||||
switch (boot_cpu_data.x86_model) {
|
||||
case 1:
|
||||
case 3: /* Pentium Pro */
|
||||
case 5:
|
||||
case 6: /* Pentium II */
|
||||
case 7:
|
||||
case 8:
|
||||
case 11: /* Pentium III */
|
||||
case 9:
|
||||
case 13:
|
||||
/* Pentium M */
|
||||
break;
|
||||
default:
|
||||
pr_cont("unsupported p6 CPU model %d ",
|
||||
boot_cpu_data.x86_model);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
x86_pmu = p6_pmu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CPU_SUP_INTEL */
|
||||
@@ -115,17 +115,6 @@ int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
|
||||
|
||||
return !test_bit(counter, perfctr_nmi_owner);
|
||||
}
|
||||
|
||||
/* checks the an msr for availability */
|
||||
int avail_to_resrv_perfctr_nmi(unsigned int msr)
|
||||
{
|
||||
unsigned int counter;
|
||||
|
||||
counter = nmi_perfctr_msr_to_bit(msr);
|
||||
BUG_ON(counter > NMI_MAX_COUNTER_BITS);
|
||||
|
||||
return !test_bit(counter, perfctr_nmi_owner);
|
||||
}
|
||||
EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
|
||||
|
||||
int reserve_perfctr_nmi(unsigned int msr)
|
||||
|
||||
@@ -18,11 +18,6 @@
|
||||
|
||||
#include "dumpstack.h"
|
||||
|
||||
/* Just a stub for now */
|
||||
int x86_is_stack_id(int id, char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_trace(struct task_struct *task, struct pt_regs *regs,
|
||||
unsigned long *stack, unsigned long bp,
|
||||
|
||||
@@ -33,11 +33,6 @@ static char x86_stack_ids[][8] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
int x86_is_stack_id(int id, char *name)
|
||||
{
|
||||
return x86_stack_ids[id - 1] == name;
|
||||
}
|
||||
|
||||
static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
|
||||
unsigned *usedp, char **idp)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user