提交 90489a72 编写于 作者: L Linus Torvalds

Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Ingo Molnar:
 "The main kernel changes were:

   - add support for Intel's "adaptive PEBS v4" - which embedds LBS data
     in PEBS records and can thus batch up and reduce the IRQ (NMI) rate
     significantly - reducing overhead and making call-graph profiling
     less intrusive.

   - add Intel CPU core and uncore support updates for Tremont, Icelake,

   - extend the x86 PMU constraints scheduler with 'constraint ranges'
     to better support Icelake hw constraints,

   - make x86 call-chain support work better with CONFIG_FRAME_POINTER=y

   - misc other changes

  Tooling changes:

   - updates to the main tools: 'perf record', 'perf trace', 'perf
     stat'

   - updated Intel and S/390 vendor events

   - libtraceevent updates

   - misc other updates and fixes"

* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (69 commits)
  perf/x86: Make perf callchains work without CONFIG_FRAME_POINTER
  watchdog: Fix typo in comment
  perf/x86/intel: Add Tremont core PMU support
  perf/x86/intel/uncore: Add Intel Icelake uncore support
  perf/x86/msr: Add Icelake support
  perf/x86/intel/rapl: Add Icelake support
  perf/x86/intel/cstate: Add Icelake support
  perf/x86/intel: Add Icelake support
  perf/x86: Support constraint ranges
  perf/x86/lbr: Avoid reading the LBRs when adaptive PEBS handles them
  perf/x86/intel: Support adaptive PEBS v4
  perf/x86/intel/ds: Extract code of event update in short period
  perf/x86/intel: Extract memory code PEBS parser for reuse
  perf/x86: Support outputting XMM registers
  perf/x86/intel: Force resched when TFA sysctl is modified
  perf/core: Add perf_pmu_resched() as global function
  perf/headers: Fix stale comment for struct perf_addr_filter
  perf/core: Make perf_swevent_init_cpu() static
  perf/x86: Add sanity checks to x86_schedule_events()
  perf/x86: Optimize x86_schedule_events()
  ...
......@@ -560,6 +560,21 @@ int x86_pmu_hw_config(struct perf_event *event)
return -EINVAL;
}
/* sample_regs_user never support XMM registers */
if (unlikely(event->attr.sample_regs_user & PEBS_XMM_REGS))
return -EINVAL;
/*
* Besides the general purpose registers, XMM registers may
* be collected in PEBS on some platforms, e.g. Icelake
*/
if (unlikely(event->attr.sample_regs_intr & PEBS_XMM_REGS)) {
if (x86_pmu.pebs_no_xmm_regs)
return -EINVAL;
if (!event->attr.precise_ip)
return -EINVAL;
}
return x86_setup_perfctr(event);
}
......@@ -661,6 +676,10 @@ static inline int is_x86_event(struct perf_event *event)
return event->pmu == &pmu;
}
struct pmu *x86_get_pmu(void)
{
return &pmu;
}
/*
* Event scheduler state:
*
......@@ -849,18 +868,43 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
struct event_constraint *c;
unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
struct perf_event *e;
int i, wmin, wmax, unsched = 0;
int n0, i, wmin, wmax, unsched = 0;
struct hw_perf_event *hwc;
bitmap_zero(used_mask, X86_PMC_IDX_MAX);
/*
* Compute the number of events already present; see x86_pmu_add(),
* validate_group() and x86_pmu_commit_txn(). For the former two
* cpuc->n_events hasn't been updated yet, while for the latter
* cpuc->n_txn contains the number of events added in the current
* transaction.
*/
n0 = cpuc->n_events;
if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
n0 -= cpuc->n_txn;
if (x86_pmu.start_scheduling)
x86_pmu.start_scheduling(cpuc);
for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
cpuc->event_constraint[i] = NULL;
c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
cpuc->event_constraint[i] = c;
c = cpuc->event_constraint[i];
/*
* Previously scheduled events should have a cached constraint,
* while new events should not have one.
*/
WARN_ON_ONCE((c && i >= n0) || (!c && i < n0));
/*
* Request constraints for new events; or for those events that
* have a dynamic constraint -- for those the constraint can
* change due to external factors (sibling state, allow_tfa).
*/
if (!c || (c->flags & PERF_X86_EVENT_DYNAMIC)) {
c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
cpuc->event_constraint[i] = c;
}
wmin = min(wmin, c->weight);
wmax = max(wmax, c->weight);
......@@ -925,25 +969,20 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
if (!unsched && assign) {
for (i = 0; i < n; i++) {
e = cpuc->event_list[i];
e->hw.flags |= PERF_X86_EVENT_COMMITTED;
if (x86_pmu.commit_scheduling)
x86_pmu.commit_scheduling(cpuc, i, assign[i]);
}
} else {
for (i = 0; i < n; i++) {
for (i = n0; i < n; i++) {
e = cpuc->event_list[i];
/*
* do not put_constraint() on comitted events,
* because they are good to go
*/
if ((e->hw.flags & PERF_X86_EVENT_COMMITTED))
continue;
/*
* release events that failed scheduling
*/
if (x86_pmu.put_event_constraints)
x86_pmu.put_event_constraints(cpuc, e);
cpuc->event_constraint[i] = NULL;
}
}
......@@ -1372,11 +1411,6 @@ static void x86_pmu_del(struct perf_event *event, int flags)
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
int i;
/*
* event is descheduled
*/
event->hw.flags &= ~PERF_X86_EVENT_COMMITTED;
/*
* If we're called during a txn, we only need to undo x86_pmu.add.
* The events never got scheduled and ->cancel_txn will truncate
......@@ -1413,6 +1447,7 @@ static void x86_pmu_del(struct perf_event *event, int flags)
cpuc->event_list[i-1] = cpuc->event_list[i];
cpuc->event_constraint[i-1] = cpuc->event_constraint[i];
}
cpuc->event_constraint[i-1] = NULL;
--cpuc->n_events;
perf_event_update_userpage(event);
......@@ -2024,7 +2059,7 @@ static int validate_event(struct perf_event *event)
if (IS_ERR(fake_cpuc))
return PTR_ERR(fake_cpuc);
c = x86_pmu.get_event_constraints(fake_cpuc, -1, event);
c = x86_pmu.get_event_constraints(fake_cpuc, 0, event);
if (!c || !c->weight)
ret = -EINVAL;
......@@ -2072,8 +2107,7 @@ static int validate_group(struct perf_event *event)
if (n < 0)
goto out;
fake_cpuc->n_events = n;
fake_cpuc->n_events = 0;
ret = x86_pmu.schedule_events(fake_cpuc, n, NULL);
out:
......@@ -2348,6 +2382,15 @@ void arch_perf_update_userpage(struct perf_event *event,
cyc2ns_read_end();
}
/*
* Determine whether the regs were taken from an irq/exception handler rather
* than from perf_arch_fetch_caller_regs().
*/
static bool perf_hw_regs(struct pt_regs *regs)
{
return regs->flags & X86_EFLAGS_FIXED;
}
void
perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
{
......@@ -2359,11 +2402,15 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
return;
}
if (perf_callchain_store(entry, regs->ip))
return;
if (perf_hw_regs(regs)) {
if (perf_callchain_store(entry, regs->ip))
return;
unwind_start(&state, current, regs, NULL);
} else {
unwind_start(&state, current, NULL, (void *)regs->sp);
}
for (unwind_start(&state, current, regs, NULL); !unwind_done(&state);
unwind_next_frame(&state)) {
for (; !unwind_done(&state); unwind_next_frame(&state)) {
addr = unwind_get_return_address(&state);
if (!addr || perf_callchain_store(entry, addr))
return;
......
......@@ -239,6 +239,35 @@ static struct extra_reg intel_skl_extra_regs[] __read_mostly = {
EVENT_EXTRA_END
};
static struct event_constraint intel_icl_event_constraints[] = {
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
INTEL_UEVENT_CONSTRAINT(0x1c0, 0), /* INST_RETIRED.PREC_DIST */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
FIXED_EVENT_CONSTRAINT(0x0400, 3), /* SLOTS */
INTEL_EVENT_CONSTRAINT_RANGE(0x03, 0x0a, 0xf),
INTEL_EVENT_CONSTRAINT_RANGE(0x1f, 0x28, 0xf),
INTEL_EVENT_CONSTRAINT(0x32, 0xf), /* SW_PREFETCH_ACCESS.* */
INTEL_EVENT_CONSTRAINT_RANGE(0x48, 0x54, 0xf),
INTEL_EVENT_CONSTRAINT_RANGE(0x60, 0x8b, 0xf),
INTEL_UEVENT_CONSTRAINT(0x04a3, 0xff), /* CYCLE_ACTIVITY.STALLS_TOTAL */
INTEL_UEVENT_CONSTRAINT(0x10a3, 0xff), /* CYCLE_ACTIVITY.STALLS_MEM_ANY */
INTEL_EVENT_CONSTRAINT(0xa3, 0xf), /* CYCLE_ACTIVITY.* */
INTEL_EVENT_CONSTRAINT_RANGE(0xa8, 0xb0, 0xf),
INTEL_EVENT_CONSTRAINT_RANGE(0xb7, 0xbd, 0xf),
INTEL_EVENT_CONSTRAINT_RANGE(0xd0, 0xe6, 0xf),
INTEL_EVENT_CONSTRAINT_RANGE(0xf0, 0xf4, 0xf),
EVENT_CONSTRAINT_END
};
static struct extra_reg intel_icl_extra_regs[] __read_mostly = {
INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3fffff9fffull, RSP_0),
INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3fffff9fffull, RSP_1),
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
INTEL_UEVENT_EXTRA_REG(0x01c6, MSR_PEBS_FRONTEND, 0x7fff17, FE),
EVENT_EXTRA_END
};
EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3");
EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3");
EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2");
......@@ -1827,6 +1856,45 @@ static __initconst const u64 glp_hw_cache_extra_regs
},
};
#define TNT_LOCAL_DRAM BIT_ULL(26)
#define TNT_DEMAND_READ GLM_DEMAND_DATA_RD
#define TNT_DEMAND_WRITE GLM_DEMAND_RFO
#define TNT_LLC_ACCESS GLM_ANY_RESPONSE
#define TNT_SNP_ANY (SNB_SNP_NOT_NEEDED|SNB_SNP_MISS| \
SNB_NO_FWD|SNB_SNP_FWD|SNB_HITM)
#define TNT_LLC_MISS (TNT_SNP_ANY|SNB_NON_DRAM|TNT_LOCAL_DRAM)
static __initconst const u64 tnt_hw_cache_extra_regs
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(LL)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = TNT_DEMAND_READ|
TNT_LLC_ACCESS,
[C(RESULT_MISS)] = TNT_DEMAND_READ|
TNT_LLC_MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = TNT_DEMAND_WRITE|
TNT_LLC_ACCESS,
[C(RESULT_MISS)] = TNT_DEMAND_WRITE|
TNT_LLC_MISS,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = 0x0,
[C(RESULT_MISS)] = 0x0,
},
},
};
static struct extra_reg intel_tnt_extra_regs[] __read_mostly = {
/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffffff9fffull, RSP_0),
INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0xffffff9fffull, RSP_1),
EVENT_EXTRA_END
};
#define KNL_OT_L2_HITE BIT_ULL(19) /* Other Tile L2 Hit */
#define KNL_OT_L2_HITF BIT_ULL(20) /* Other Tile L2 Hit */
#define KNL_MCDRAM_LOCAL BIT_ULL(21)
......@@ -2015,7 +2083,7 @@ static void intel_tfa_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int
/*
* We're going to use PMC3, make sure TFA is set before we touch it.
*/
if (cntr == 3 && !cpuc->is_fake)
if (cntr == 3)
intel_set_tfa(cpuc, true);
}
......@@ -2149,6 +2217,11 @@ static void intel_pmu_enable_fixed(struct perf_event *event)
bits <<= (idx * 4);
mask = 0xfULL << (idx * 4);
if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip) {
bits |= ICL_FIXED_0_ADAPTIVE << (idx * 4);
mask |= ICL_FIXED_0_ADAPTIVE << (idx * 4);
}
rdmsrl(hwc->config_base, ctrl_val);
ctrl_val &= ~mask;
ctrl_val |= bits;
......@@ -2692,7 +2765,7 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
if (x86_pmu.event_constraints) {
for_each_event_constraint(c, x86_pmu.event_constraints) {
if ((event->hw.config & c->cmask) == c->code) {
if (constraint_match(c, event->hw.config)) {
event->hw.flags |= c->flags;
return c;
}
......@@ -2842,7 +2915,7 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
struct intel_excl_states *xlo;
int tid = cpuc->excl_thread_id;
int is_excl, i;
int is_excl, i, w;
/*
* validating a group does not require
......@@ -2898,36 +2971,40 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
* SHARED : sibling counter measuring non-exclusive event
* UNUSED : sibling counter unused
*/
w = c->weight;
for_each_set_bit(i, c->idxmsk, X86_PMC_IDX_MAX) {
/*
* exclusive event in sibling counter
* our corresponding counter cannot be used
* regardless of our event
*/
if (xlo->state[i] == INTEL_EXCL_EXCLUSIVE)
if (xlo->state[i] == INTEL_EXCL_EXCLUSIVE) {
__clear_bit(i, c->idxmsk);
w--;
continue;
}
/*
* if measuring an exclusive event, sibling
* measuring non-exclusive, then counter cannot
* be used
*/
if (is_excl && xlo->state[i] == INTEL_EXCL_SHARED)
if (is_excl && xlo->state[i] == INTEL_EXCL_SHARED) {
__clear_bit(i, c->idxmsk);
w--;
continue;
}
}
/*
* recompute actual bit weight for scheduling algorithm
*/
c->weight = hweight64(c->idxmsk64);
/*
* if we return an empty mask, then switch
* back to static empty constraint to avoid
* the cost of freeing later on
*/
if (c->weight == 0)
if (!w)
c = &emptyconstraint;
c->weight = w;
return c;
}
......@@ -2935,11 +3012,9 @@ static struct event_constraint *
intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
{
struct event_constraint *c1 = NULL;
struct event_constraint *c2;
struct event_constraint *c1, *c2;
if (idx >= 0) /* fake does < 0 */
c1 = cpuc->event_constraint[idx];
c1 = cpuc->event_constraint[idx];
/*
* first time only
......@@ -2947,7 +3022,8 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
* - dynamic constraint: handled by intel_get_excl_constraints()
*/
c2 = __intel_get_event_constraints(cpuc, idx, event);
if (c1 && (c1->flags & PERF_X86_EVENT_DYNAMIC)) {
if (c1) {
WARN_ON_ONCE(!(c1->flags & PERF_X86_EVENT_DYNAMIC));
bitmap_copy(c1->idxmsk, c2->idxmsk, X86_PMC_IDX_MAX);
c1->weight = c2->weight;
c2 = c1;
......@@ -3370,6 +3446,12 @@ static struct event_constraint counter0_constraint =
static struct event_constraint counter2_constraint =
EVENT_CONSTRAINT(0, 0x4, 0);
static struct event_constraint fixed0_constraint =
FIXED_EVENT_CONSTRAINT(0x00c0, 0);
static struct event_constraint fixed0_counter0_constraint =
INTEL_ALL_EVENT_CONSTRAINT(0, 0x100000001ULL);
static struct event_constraint *
hsw_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
......@@ -3388,6 +3470,21 @@ hsw_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
return c;
}
static struct event_constraint *
icl_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
{
/*
* Fixed counter 0 has less skid.
* Force instruction:ppp in Fixed counter 0
*/
if ((event->attr.precise_ip == 3) &&
constraint_match(&fixed0_constraint, event->hw.config))
return &fixed0_constraint;
return hsw_get_event_constraints(cpuc, idx, event);
}
static struct event_constraint *
glp_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
......@@ -3403,6 +3500,29 @@ glp_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
return c;
}
static struct event_constraint *
tnt_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
{
struct event_constraint *c;
/*
* :ppp means to do reduced skid PEBS,
* which is available on PMC0 and fixed counter 0.
*/
if (event->attr.precise_ip == 3) {
/* Force instruction:ppp on PMC0 and Fixed counter 0 */
if (constraint_match(&fixed0_constraint, event->hw.config))
return &fixed0_counter0_constraint;
return &counter0_constraint;
}
c = intel_get_event_constraints(cpuc, idx, event);
return c;
}
static bool allow_tsx_force_abort = true;
static struct event_constraint *
......@@ -3414,7 +3534,7 @@ tfa_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
/*
* Without TFA we must not use PMC3.
*/
if (!allow_tsx_force_abort && test_bit(3, c->idxmsk) && idx >= 0) {
if (!allow_tsx_force_abort && test_bit(3, c->idxmsk)) {
c = dyn_constraint(cpuc, c, idx);
c->idxmsk64 &= ~(1ULL << 3);
c->weight--;
......@@ -3511,6 +3631,8 @@ static struct intel_excl_cntrs *allocate_excl_cntrs(int cpu)
int intel_cpuc_prepare(struct cpu_hw_events *cpuc, int cpu)
{
cpuc->pebs_record_size = x86_pmu.pebs_record_size;
if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) {
cpuc->shared_regs = allocate_shared_regs(cpu);
if (!cpuc->shared_regs)
......@@ -4118,6 +4240,42 @@ static struct attribute *hsw_tsx_events_attrs[] = {
NULL
};
EVENT_ATTR_STR(tx-capacity-read, tx_capacity_read, "event=0x54,umask=0x80");
EVENT_ATTR_STR(tx-capacity-write, tx_capacity_write, "event=0x54,umask=0x2");
EVENT_ATTR_STR(el-capacity-read, el_capacity_read, "event=0x54,umask=0x80");
EVENT_ATTR_STR(el-capacity-write, el_capacity_write, "event=0x54,umask=0x2");
static struct attribute *icl_events_attrs[] = {
EVENT_PTR(mem_ld_hsw),
EVENT_PTR(mem_st_hsw),
NULL,
};
static struct attribute *icl_tsx_events_attrs[] = {
EVENT_PTR(tx_start),
EVENT_PTR(tx_abort),
EVENT_PTR(tx_commit),
EVENT_PTR(tx_capacity_read),
EVENT_PTR(tx_capacity_write),
EVENT_PTR(tx_conflict),
EVENT_PTR(el_start),
EVENT_PTR(el_abort),
EVENT_PTR(el_commit),
EVENT_PTR(el_capacity_read),
EVENT_PTR(el_capacity_write),
EVENT_PTR(el_conflict),
EVENT_PTR(cycles_t),
EVENT_PTR(cycles_ct),
NULL,
};
static __init struct attribute **get_icl_events_attrs(void)
{
return boot_cpu_has(X86_FEATURE_RTM) ?
merge_attr(icl_events_attrs, icl_tsx_events_attrs) :
icl_events_attrs;
}
static ssize_t freeze_on_smi_show(struct device *cdev,
struct device_attribute *attr,
char *buf)
......@@ -4157,6 +4315,50 @@ static ssize_t freeze_on_smi_store(struct device *cdev,
return count;
}
static void update_tfa_sched(void *ignored)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
/*
* check if PMC3 is used
* and if so force schedule out for all event types all contexts
*/
if (test_bit(3, cpuc->active_mask))
perf_pmu_resched(x86_get_pmu());
}
static ssize_t show_sysctl_tfa(struct device *cdev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", allow_tsx_force_abort);
}
static ssize_t set_sysctl_tfa(struct device *cdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
bool val;
ssize_t ret;
ret = kstrtobool(buf, &val);
if (ret)
return ret;
/* no change */
if (val == allow_tsx_force_abort)
return count;
allow_tsx_force_abort = val;
get_online_cpus();
on_each_cpu(update_tfa_sched, NULL, 1);
put_online_cpus();
return count;
}
static DEVICE_ATTR_RW(freeze_on_smi);
static ssize_t branches_show(struct device *cdev,
......@@ -4189,7 +4391,9 @@ static struct attribute *intel_pmu_caps_attrs[] = {
NULL
};
static DEVICE_BOOL_ATTR(allow_tsx_force_abort, 0644, allow_tsx_force_abort);
static DEVICE_ATTR(allow_tsx_force_abort, 0644,
show_sysctl_tfa,
set_sysctl_tfa);
static struct attribute *intel_pmu_attrs[] = {
&dev_attr_freeze_on_smi.attr,
......@@ -4450,6 +4654,32 @@ __init int intel_pmu_init(void)
name = "goldmont_plus";
break;
case INTEL_FAM6_ATOM_TREMONT_X:
x86_pmu.late_ack = true;
memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, tnt_hw_cache_extra_regs,
sizeof(hw_cache_extra_regs));
hw_cache_event_ids[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
intel_pmu_lbr_init_skl();
x86_pmu.event_constraints = intel_slm_event_constraints;
x86_pmu.extra_regs = intel_tnt_extra_regs;
/*
* It's recommended to use CPU_CLK_UNHALTED.CORE_P + NPEBS
* for precise cycles.
*/
x86_pmu.pebs_aliases = NULL;
x86_pmu.pebs_prec_dist = true;
x86_pmu.lbr_pt_coexist = true;
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
x86_pmu.get_event_constraints = tnt_get_event_constraints;
extra_attr = slm_format_attr;
pr_cont("Tremont events, ");
name = "Tremont";
break;
case INTEL_FAM6_WESTMERE:
case INTEL_FAM6_WESTMERE_EP:
case INTEL_FAM6_WESTMERE_EX:
......@@ -4698,13 +4928,41 @@ __init int intel_pmu_init(void)
x86_pmu.get_event_constraints = tfa_get_event_constraints;
x86_pmu.enable_all = intel_tfa_pmu_enable_all;
x86_pmu.commit_scheduling = intel_tfa_commit_scheduling;
intel_pmu_attrs[1] = &dev_attr_allow_tsx_force_abort.attr.attr;
intel_pmu_attrs[1] = &dev_attr_allow_tsx_force_abort.attr;
}
pr_cont("Skylake events, ");
name = "skylake";
break;
case INTEL_FAM6_ICELAKE_MOBILE:
x86_pmu.late_ack = true;
memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
hw_cache_event_ids[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
intel_pmu_lbr_init_skl();
x86_pmu.event_constraints = intel_icl_event_constraints;
x86_pmu.pebs_constraints = intel_icl_pebs_event_constraints;
x86_pmu.extra_regs = intel_icl_extra_regs;
x86_pmu.pebs_aliases = NULL;
x86_pmu.pebs_prec_dist = true;
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
x86_pmu.hw_config = hsw_hw_config;
x86_pmu.get_event_constraints = icl_get_event_constraints;
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
hsw_format_attr : nhm_format_attr;
extra_attr = merge_attr(extra_attr, skl_format_attr);
x86_pmu.cpu_events = get_icl_events_attrs();
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xca, .umask=0x02);
x86_pmu.lbr_pt_coexist = true;
intel_pmu_pebs_data_source_skl(false);
pr_cont("Icelake events, ");
name = "icelake";
break;
default:
switch (x86_pmu.version) {
case 1:
......
......@@ -578,6 +578,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_X, glm_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_MOBILE, snb_cstates),
{ },
};
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
......
此差异已折叠。
......@@ -488,6 +488,8 @@ void intel_pmu_lbr_add(struct perf_event *event)
* be 'new'. Conversely, a new event can get installed through the
* context switch path for the first time.
*/
if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0)
cpuc->lbr_pebs_users++;
perf_sched_cb_inc(event->ctx->pmu);
if (!cpuc->lbr_users++ && !event->total_time_running)
intel_pmu_lbr_reset();
......@@ -507,8 +509,11 @@ void intel_pmu_lbr_del(struct perf_event *event)
task_ctx->lbr_callstack_users--;
}
if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0)
cpuc->lbr_pebs_users--;
cpuc->lbr_users--;
WARN_ON_ONCE(cpuc->lbr_users < 0);
WARN_ON_ONCE(cpuc->lbr_pebs_users < 0);
perf_sched_cb_dec(event->ctx->pmu);
}
......@@ -658,7 +663,13 @@ void intel_pmu_lbr_read(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
if (!cpuc->lbr_users)
/*
* Don't read when all LBRs users are using adaptive PEBS.
*
* This could be smarter and actually check the event,
* but this simple approach seems to work for now.
*/
if (!cpuc->lbr_users || cpuc->lbr_users == cpuc->lbr_pebs_users)
return;
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
......@@ -1080,6 +1091,28 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
}
}
void intel_pmu_store_pebs_lbrs(struct pebs_lbr *lbr)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
int i;
cpuc->lbr_stack.nr = x86_pmu.lbr_nr;
for (i = 0; i < x86_pmu.lbr_nr; i++) {
u64 info = lbr->lbr[i].info;
struct perf_branch_entry *e = &cpuc->lbr_entries[i];
e->from = lbr->lbr[i].from;
e->to = lbr->lbr[i].to;
e->mispred = !!(info & LBR_INFO_MISPRED);
e->predicted = !(info & LBR_INFO_MISPRED);
e->in_tx = !!(info & LBR_INFO_IN_TX);
e->abort = !!(info & LBR_INFO_ABORT);
e->cycles = info & LBR_INFO_CYCLES;
e->reserved = 0;
}
intel_pmu_lbr_filter(cpuc);
}
/*
* Map interface branch filters onto LBR filters
*/
......
......@@ -775,6 +775,8 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_X, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, skl_rapl_init),
{},
};
......
......@@ -1367,6 +1367,11 @@ static const struct intel_uncore_init_fun skx_uncore_init __initconst = {
.pci_init = skx_uncore_pci_init,
};
static const struct intel_uncore_init_fun icl_uncore_init __initconst = {
.cpu_init = icl_uncore_cpu_init,
.pci_init = skl_uncore_pci_init,
};
static const struct x86_cpu_id intel_uncore_match[] __initconst = {
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP, nhm_uncore_init),
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM, nhm_uncore_init),
......@@ -1393,6 +1398,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, skx_uncore_init),
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, skl_uncore_init),
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_uncore_init),
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, icl_uncore_init),
{},
};
......
......@@ -512,6 +512,7 @@ int skl_uncore_pci_init(void);
void snb_uncore_cpu_init(void);
void nhm_uncore_cpu_init(void);
void skl_uncore_cpu_init(void);
void icl_uncore_cpu_init(void);
int snb_pci2phy_map_init(int devid);
/* uncore_snbep.c */
......
......@@ -34,6 +34,8 @@
#define PCI_DEVICE_ID_INTEL_CFL_4S_S_IMC 0x3e33
#define PCI_DEVICE_ID_INTEL_CFL_6S_S_IMC 0x3eca
#define PCI_DEVICE_ID_INTEL_CFL_8S_S_IMC 0x3e32
#define PCI_DEVICE_ID_INTEL_ICL_U_IMC 0x8a02
#define PCI_DEVICE_ID_INTEL_ICL_U2_IMC 0x8a12
/* SNB event control */
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
......@@ -93,6 +95,12 @@
#define SKL_UNC_PERF_GLOBAL_CTL 0xe01
#define SKL_UNC_GLOBAL_CTL_CORE_ALL ((1 << 5) - 1)
/* ICL Cbo register */
#define ICL_UNC_CBO_CONFIG 0x396
#define ICL_UNC_NUM_CBO_MASK 0xf
#define ICL_UNC_CBO_0_PER_CTR0 0x702
#define ICL_UNC_CBO_MSR_OFFSET 0x8
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
......@@ -280,6 +288,70 @@ void skl_uncore_cpu_init(void)
snb_uncore_arb.ops = &skl_uncore_msr_ops;
}
static struct intel_uncore_type icl_uncore_cbox = {
.name = "cbox",
.num_counters = 4,
.perf_ctr_bits = 44,
.perf_ctr = ICL_UNC_CBO_0_PER_CTR0,
.event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0,
.event_mask = SNB_UNC_RAW_EVENT_MASK,
.msr_offset = ICL_UNC_CBO_MSR_OFFSET,
.ops = &skl_uncore_msr_ops,
.format_group = &snb_uncore_format_group,
};
static struct uncore_event_desc icl_uncore_events[] = {
INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff"),
{ /* end: all zeroes */ },
};
static struct attribute *icl_uncore_clock_formats_attr[] = {
&format_attr_event.attr,
NULL,
};
static struct attribute_group icl_uncore_clock_format_group = {
.name = "format",
.attrs = icl_uncore_clock_formats_attr,
};
static struct intel_uncore_type icl_uncore_clockbox = {
.name = "clock",
.num_counters = 1,
.num_boxes = 1,
.fixed_ctr_bits = 48,
.fixed_ctr = SNB_UNC_FIXED_CTR,
.fixed_ctl = SNB_UNC_FIXED_CTR_CTRL,
.single_fixed = 1,
.event_mask = SNB_UNC_CTL_EV_SEL_MASK,
.format_group = &icl_uncore_clock_format_group,
.ops = &skl_uncore_msr_ops,
.event_descs = icl_uncore_events,
};
static struct intel_uncore_type *icl_msr_uncores[] = {
&icl_uncore_cbox,
&snb_uncore_arb,
&icl_uncore_clockbox,
NULL,
};
static int icl_get_cbox_num(void)
{
u64 num_boxes;
rdmsrl(ICL_UNC_CBO_CONFIG, num_boxes);
return num_boxes & ICL_UNC_NUM_CBO_MASK;
}
void icl_uncore_cpu_init(void)
{
uncore_msr_uncores = icl_msr_uncores;
icl_uncore_cbox.num_boxes = icl_get_cbox_num();
snb_uncore_arb.ops = &skl_uncore_msr_ops;
}
enum {
SNB_PCI_UNCORE_IMC,
};
......@@ -668,6 +740,18 @@ static const struct pci_device_id skl_uncore_pci_ids[] = {
{ /* end: all zeroes */ },
};
static const struct pci_device_id icl_uncore_pci_ids[] = {
{ /* IMC */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICL_U_IMC),
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
},
{ /* IMC */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICL_U2_IMC),
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
},
{ /* end: all zeroes */ },
};
static struct pci_driver snb_uncore_pci_driver = {
.name = "snb_uncore",
.id_table = snb_uncore_pci_ids,
......@@ -693,6 +777,11 @@ static struct pci_driver skl_uncore_pci_driver = {
.id_table = skl_uncore_pci_ids,
};
static struct pci_driver icl_uncore_pci_driver = {
.name = "icl_uncore",
.id_table = icl_uncore_pci_ids,
};
struct imc_uncore_pci_dev {
__u32 pci_id;
struct pci_driver *driver;
......@@ -732,6 +821,8 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
IMC_DEV(CFL_4S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 4 Cores Server */
IMC_DEV(CFL_6S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 6 Cores Server */
IMC_DEV(CFL_8S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 8 Cores Server */
IMC_DEV(ICL_U_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
IMC_DEV(ICL_U2_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
{ /* end marker */ }
};
......
......@@ -89,6 +89,7 @@ static bool test_intel(int idx)
case INTEL_FAM6_SKYLAKE_X:
case INTEL_FAM6_KABYLAKE_MOBILE:
case INTEL_FAM6_KABYLAKE_DESKTOP:
case INTEL_FAM6_ICELAKE_MOBILE:
if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
return true;
break;
......
......@@ -49,28 +49,33 @@ struct event_constraint {
unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
u64 idxmsk64;
};
u64 code;
u64 cmask;
int weight;
int overlap;
int flags;
u64 code;
u64 cmask;
int weight;
int overlap;
int flags;
unsigned int size;
};
static inline bool constraint_match(struct event_constraint *c, u64 ecode)
{
return ((ecode & c->cmask) - c->code) <= (u64)c->size;
}
/*
* struct hw_perf_event.flags flags
*/
#define PERF_X86_EVENT_PEBS_LDLAT 0x0001 /* ld+ldlat data address sampling */
#define PERF_X86_EVENT_PEBS_ST 0x0002 /* st data address sampling */
#define PERF_X86_EVENT_PEBS_ST_HSW 0x0004 /* haswell style datala, store */
#define PERF_X86_EVENT_COMMITTED 0x0008 /* event passed commit_txn */
#define PERF_X86_EVENT_PEBS_LD_HSW 0x0010 /* haswell style datala, load */
#define PERF_X86_EVENT_PEBS_NA_HSW 0x0020 /* haswell style datala, unknown */
#define PERF_X86_EVENT_EXCL 0x0040 /* HT exclusivity on counter */
#define PERF_X86_EVENT_DYNAMIC 0x0080 /* dynamic alloc'd constraint */
#define PERF_X86_EVENT_RDPMC_ALLOWED 0x0100 /* grant rdpmc permission */
#define PERF_X86_EVENT_EXCL_ACCT 0x0200 /* accounted EXCL event */
#define PERF_X86_EVENT_AUTO_RELOAD 0x0400 /* use PEBS auto-reload */
#define PERF_X86_EVENT_LARGE_PEBS 0x0800 /* use large PEBS */
#define PERF_X86_EVENT_PEBS_LD_HSW 0x0008 /* haswell style datala, load */
#define PERF_X86_EVENT_PEBS_NA_HSW 0x0010 /* haswell style datala, unknown */
#define PERF_X86_EVENT_EXCL 0x0020 /* HT exclusivity on counter */
#define PERF_X86_EVENT_DYNAMIC 0x0040 /* dynamic alloc'd constraint */
#define PERF_X86_EVENT_RDPMC_ALLOWED 0x0080 /* grant rdpmc permission */
#define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */
#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */
#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */
struct amd_nb {
int nb_id; /* NorthBridge id */
......@@ -116,6 +121,24 @@ struct amd_nb {
(1ULL << PERF_REG_X86_R14) | \
(1ULL << PERF_REG_X86_R15))
#define PEBS_XMM_REGS \
((1ULL << PERF_REG_X86_XMM0) | \
(1ULL << PERF_REG_X86_XMM1) | \
(1ULL << PERF_REG_X86_XMM2) | \
(1ULL << PERF_REG_X86_XMM3) | \
(1ULL << PERF_REG_X86_XMM4) | \
(1ULL << PERF_REG_X86_XMM5) | \
(1ULL << PERF_REG_X86_XMM6) | \
(1ULL << PERF_REG_X86_XMM7) | \
(1ULL << PERF_REG_X86_XMM8) | \
(1ULL << PERF_REG_X86_XMM9) | \
(1ULL << PERF_REG_X86_XMM10) | \
(1ULL << PERF_REG_X86_XMM11) | \
(1ULL << PERF_REG_X86_XMM12) | \
(1ULL << PERF_REG_X86_XMM13) | \
(1ULL << PERF_REG_X86_XMM14) | \
(1ULL << PERF_REG_X86_XMM15))
/*
* Per register state.
*/
......@@ -207,10 +230,16 @@ struct cpu_hw_events {
int n_pebs;
int n_large_pebs;
/* Current super set of events hardware configuration */
u64 pebs_data_cfg;
u64 active_pebs_data_cfg;
int pebs_record_size;
/*
* Intel LBR bits
*/
int lbr_users;
int lbr_pebs_users;
struct perf_branch_stack lbr_stack;
struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES];
struct er_account *lbr_sel;
......@@ -257,18 +286,29 @@ struct cpu_hw_events {
void *kfree_on_online[X86_PERF_KFREE_MAX];
};
#define __EVENT_CONSTRAINT(c, n, m, w, o, f) {\
#define __EVENT_CONSTRAINT_RANGE(c, e, n, m, w, o, f) { \
{ .idxmsk64 = (n) }, \
.code = (c), \
.size = (e) - (c), \
.cmask = (m), \
.weight = (w), \
.overlap = (o), \
.flags = f, \
}
#define __EVENT_CONSTRAINT(c, n, m, w, o, f) \
__EVENT_CONSTRAINT_RANGE(c, c, n, m, w, o, f)
#define EVENT_CONSTRAINT(c, n, m) \
__EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0)
/*
* The constraint_match() function only works for 'simple' event codes
* and not for extended (AMD64_EVENTSEL_EVENT) events codes.
*/
#define EVENT_CONSTRAINT_RANGE(c, e, n, m) \
__EVENT_CONSTRAINT_RANGE(c, e, n, m, HWEIGHT(n), 0, 0)
#define INTEL_EXCLEVT_CONSTRAINT(c, n) \
__EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT, HWEIGHT(n),\
0, PERF_X86_EVENT_EXCL)
......@@ -303,6 +343,12 @@ struct cpu_hw_events {
#define INTEL_EVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT)
/*
* Constraint on a range of Event codes
*/
#define INTEL_EVENT_CONSTRAINT_RANGE(c, e, n) \
EVENT_CONSTRAINT_RANGE(c, e, n, ARCH_PERFMON_EVENTSEL_EVENT)
/*
* Constraint on the Event code + UMask + fixed-mask
*
......@@ -350,6 +396,9 @@ struct cpu_hw_events {
#define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
#define INTEL_FLAGS_EVENT_CONSTRAINT_RANGE(c, e, n) \
EVENT_CONSTRAINT_RANGE(c, e, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
/* Check only flags, but allow all event/umask */
#define INTEL_ALL_EVENT_CONSTRAINT(code, n) \
EVENT_CONSTRAINT(code, n, X86_ALL_EVENT_FLAGS)
......@@ -366,6 +415,11 @@ struct cpu_hw_events {
ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(code, end, n) \
__EVENT_CONSTRAINT_RANGE(code, end, n, \
ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD(code, n) \
__EVENT_CONSTRAINT(code, n, \
ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
......@@ -473,6 +527,7 @@ union perf_capabilities {
* values > 32bit.
*/
u64 full_width_write:1;
u64 pebs_baseline:1;
};
u64 capabilities;
};
......@@ -613,14 +668,16 @@ struct x86_pmu {
pebs_broken :1,
pebs_prec_dist :1,
pebs_no_tlb :1,
pebs_no_isolation :1;
pebs_no_isolation :1,
pebs_no_xmm_regs :1;
int pebs_record_size;
int pebs_buffer_size;
int max_pebs_events;
void (*drain_pebs)(struct pt_regs *regs);
struct event_constraint *pebs_constraints;
void (*pebs_aliases)(struct perf_event *event);
int max_pebs_events;
unsigned long large_pebs_flags;
u64 rtm_abort_event;
/*
* Intel LBR
......@@ -714,6 +771,7 @@ static struct perf_pmu_events_ht_attr event_attr_##v = { \
.event_str_ht = ht, \
}
struct pmu *x86_get_pmu(void);
extern struct x86_pmu x86_pmu __read_mostly;
static inline bool x86_pmu_has_lbr_callstack(void)
......@@ -941,6 +999,8 @@ extern struct event_constraint intel_bdw_pebs_event_constraints[];
extern struct event_constraint intel_skl_pebs_event_constraints[];
extern struct event_constraint intel_icl_pebs_event_constraints[];
struct event_constraint *intel_pebs_constraints(struct perf_event *event);
void intel_pmu_pebs_add(struct perf_event *event);
......@@ -959,6 +1019,8 @@ void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in);
void intel_pmu_auto_reload_read(struct perf_event *event);
void intel_pmu_store_pebs_lbrs(struct pebs_lbr *lbr);
void intel_ds_init(void);
void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
......
......@@ -8,7 +8,7 @@
/* The maximal number of PEBS events: */
#define MAX_PEBS_EVENTS 8
#define MAX_FIXED_PEBS_EVENTS 3
#define MAX_FIXED_PEBS_EVENTS 4
/*
* A debug store configuration.
......
......@@ -116,6 +116,7 @@
#define LBR_INFO_CYCLES 0xffff
#define MSR_IA32_PEBS_ENABLE 0x000003f1
#define MSR_PEBS_DATA_CFG 0x000003f2
#define MSR_IA32_DS_AREA 0x00000600
#define MSR_IA32_PERF_CAPABILITIES 0x00000345
#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6
......
......@@ -7,7 +7,7 @@
*/
#define INTEL_PMC_MAX_GENERIC 32
#define INTEL_PMC_MAX_FIXED 3
#define INTEL_PMC_MAX_FIXED 4
#define INTEL_PMC_IDX_FIXED 32
#define X86_PMC_IDX_MAX 64
......@@ -32,6 +32,8 @@
#define HSW_IN_TX (1ULL << 32)
#define HSW_IN_TX_CHECKPOINTED (1ULL << 33)
#define ICL_EVENTSEL_ADAPTIVE (1ULL << 34)
#define ICL_FIXED_0_ADAPTIVE (1ULL << 32)
#define AMD64_EVENTSEL_INT_CORE_ENABLE (1ULL << 36)
#define AMD64_EVENTSEL_GUESTONLY (1ULL << 40)
......@@ -87,6 +89,12 @@
#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6
#define ARCH_PERFMON_EVENTS_COUNT 7
#define PEBS_DATACFG_MEMINFO BIT_ULL(0)
#define PEBS_DATACFG_GP BIT_ULL(1)
#define PEBS_DATACFG_XMMS BIT_ULL(2)
#define PEBS_DATACFG_LBRS BIT_ULL(3)
#define PEBS_DATACFG_LBR_SHIFT 24
/*
* Intel "Architectural Performance Monitoring" CPUID
* detection/enumeration details:
......@@ -176,6 +184,41 @@ struct x86_pmu_capability {
#define GLOBAL_STATUS_LBRS_FROZEN BIT_ULL(58)
#define GLOBAL_STATUS_TRACE_TOPAPMI BIT_ULL(55)
/*
* Adaptive PEBS v4
*/
struct pebs_basic {
u64 format_size;
u64 ip;
u64 applicable_counters;
u64 tsc;
};
struct pebs_meminfo {
u64 address;
u64 aux;
u64 latency;
u64 tsx_tuning;
};
struct pebs_gprs {
u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di;
u64 r8, r9, r10, r11, r12, r13, r14, r15;
};
struct pebs_xmm {
u64 xmm[16*2]; /* two entries for each register */
};
struct pebs_lbr_entry {
u64 from, to, info;
};
struct pebs_lbr {
struct pebs_lbr_entry lbr[0]; /* Variable length */
};
/*
* IBS cpuid feature detection
*/
......@@ -248,6 +291,11 @@ extern void perf_events_lapic_init(void);
#define PERF_EFLAGS_VM (1UL << 5)
struct pt_regs;
struct x86_perf_regs {
struct pt_regs regs;
u64 *xmm_regs;
};
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
......@@ -260,14 +308,9 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
*/
#define perf_arch_fetch_caller_regs(regs, __ip) { \
(regs)->ip = (__ip); \
(regs)->bp = caller_frame_pointer(); \
(regs)->sp = (unsigned long)__builtin_frame_address(0); \
(regs)->cs = __KERNEL_CS; \
regs->flags = 0; \
asm volatile( \
_ASM_MOV "%%"_ASM_SP ", %0\n" \
: "=m" ((regs)->sp) \
:: "memory" \
); \
}
struct perf_guest_switch_msr {
......
......@@ -98,19 +98,6 @@ struct stack_frame_ia32 {
u32 return_address;
};
static inline unsigned long caller_frame_pointer(void)
{
struct stack_frame *frame;
frame = __builtin_frame_address(0);
#ifdef CONFIG_FRAME_POINTER
frame = frame->next_frame;
#endif
return (unsigned long)frame;
}
void show_opcodes(struct pt_regs *regs, const char *loglvl);
void show_ip(struct pt_regs *regs, const char *loglvl);
#endif /* _ASM_X86_STACKTRACE_H */
......@@ -27,8 +27,29 @@ enum perf_event_x86_regs {
PERF_REG_X86_R13,
PERF_REG_X86_R14,
PERF_REG_X86_R15,
/* These are the limits for the GPRs. */
PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1,
PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1,
/* These all need two bits set because they are 128bit */
PERF_REG_X86_XMM0 = 32,
PERF_REG_X86_XMM1 = 34,
PERF_REG_X86_XMM2 = 36,
PERF_REG_X86_XMM3 = 38,
PERF_REG_X86_XMM4 = 40,
PERF_REG_X86_XMM5 = 42,
PERF_REG_X86_XMM6 = 44,
PERF_REG_X86_XMM7 = 46,
PERF_REG_X86_XMM8 = 48,
PERF_REG_X86_XMM9 = 50,
PERF_REG_X86_XMM10 = 52,
PERF_REG_X86_XMM11 = 54,
PERF_REG_X86_XMM12 = 56,
PERF_REG_X86_XMM13 = 58,
PERF_REG_X86_XMM14 = 60,
PERF_REG_X86_XMM15 = 62,
/* These include both GPRs and XMMX registers */
PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
};
#endif /* _ASM_X86_PERF_REGS_H */
......@@ -59,18 +59,34 @@ static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
u64 perf_reg_value(struct pt_regs *regs, int idx)
{
struct x86_perf_regs *perf_regs;
if (idx >= PERF_REG_X86_XMM0 && idx < PERF_REG_X86_XMM_MAX) {
perf_regs = container_of(regs, struct x86_perf_regs, regs);
if (!perf_regs->xmm_regs)
return 0;
return perf_regs->xmm_regs[idx - PERF_REG_X86_XMM0];
}
if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
return 0;
return regs_get_register(regs, pt_regs_offset[idx]);
}
#define REG_RESERVED (~((1ULL << PERF_REG_X86_MAX) - 1ULL))
#ifdef CONFIG_X86_32
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
(1ULL << PERF_REG_X86_R9) | \
(1ULL << PERF_REG_X86_R10) | \
(1ULL << PERF_REG_X86_R11) | \
(1ULL << PERF_REG_X86_R12) | \
(1ULL << PERF_REG_X86_R13) | \
(1ULL << PERF_REG_X86_R14) | \
(1ULL << PERF_REG_X86_R15))
int perf_reg_validate(u64 mask)
{
if (!mask || mask & REG_RESERVED)
if (!mask || (mask & REG_NOSUPPORT))
return -EINVAL;
return 0;
......@@ -96,10 +112,7 @@ void perf_get_regs_user(struct perf_regs *regs_user,
int perf_reg_validate(u64 mask)
{
if (!mask || mask & REG_RESERVED)
return -EINVAL;
if (mask & REG_NOSUPPORT)
if (!mask || (mask & REG_NOSUPPORT))
return -EINVAL;
return 0;
......
......@@ -463,7 +463,7 @@ enum perf_addr_filter_action_t {
/**
* struct perf_addr_filter - address range filter definition
* @entry: event's filter list linkage
* @inode: object file's inode for file-based filters
* @path: object file's path for file-based filters
* @offset: filter range offset
* @size: filter range size (size==0 means single address trigger)
* @action: filter/start/stop
......@@ -887,6 +887,9 @@ extern void perf_sched_cb_dec(struct pmu *pmu);
extern void perf_sched_cb_inc(struct pmu *pmu);
extern int perf_event_task_disable(void);
extern int perf_event_task_enable(void);
extern void perf_pmu_resched(struct pmu *pmu);
extern int perf_event_refresh(struct perf_event *event, int refresh);
extern void perf_event_update_userpage(struct perf_event *event);
extern int perf_event_release_kernel(struct perf_event *event);
......@@ -1054,12 +1057,18 @@ static inline void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned lo
#endif
/*
* Take a snapshot of the regs. Skip ip and frame pointer to
* the nth caller. We only need a few of the regs:
* When generating a perf sample in-line, instead of from an interrupt /
* exception, we lack a pt_regs. This is typically used from software events
* like: SW_CONTEXT_SWITCHES, SW_MIGRATIONS and the tie-in with tracepoints.
*
* We typically don't need a full set, but (for x86) do require:
* - ip for PERF_SAMPLE_IP
* - cs for user_mode() tests
* - bp for callchains
* - eflags, for future purposes, just in case
* - sp for PERF_SAMPLE_CALLCHAIN
* - eflags for MISC bits and CALLCHAIN (see: perf_hw_regs())
*
* NOTE: assumes @regs is otherwise already 0 filled; this is important for
* things like PERF_SAMPLE_REGS_INTR.
*/
static inline void perf_fetch_caller_regs(struct pt_regs *regs)
{
......
......@@ -2478,6 +2478,16 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
perf_pmu_enable(cpuctx->ctx.pmu);
}
void perf_pmu_resched(struct pmu *pmu)
{
struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
struct perf_event_context *task_ctx = cpuctx->task_ctx;
perf_ctx_lock(cpuctx, task_ctx);
ctx_resched(cpuctx, task_ctx, EVENT_ALL|EVENT_CPU);
perf_ctx_unlock(cpuctx, task_ctx);
}
/*
* Cross CPU call to install and enable a performance event
*
......@@ -11917,7 +11927,7 @@ static void __init perf_event_init_all_cpus(void)
}
}
void perf_swevent_init_cpu(unsigned int cpu)
static void perf_swevent_init_cpu(unsigned int cpu)
{
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
......
......@@ -590,7 +590,7 @@ static void lockup_detector_reconfigure(void)
* Create the watchdog thread infrastructure and configure the detector(s).
*
* The threads are not unparked as watchdog_allowed_mask is empty. When
* the threads are sucessfully initialized, take the proper locks and
* the threads are successfully initialized, take the proper locks and
* unpark the threads in the watchdog_cpumask if the watchdog is enabled.
*/
static __init void lockup_detector_setup(void)
......
......@@ -67,6 +67,7 @@ FEATURE_TESTS_BASIC := \
sdt \
setns \
libaio \
libzstd \
disassembler-four-args
# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
......@@ -120,6 +121,7 @@ FEATURE_DISPLAY ?= \
get_cpuid \
bpf \
libaio \
libzstd \
disassembler-four-args
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
......
......@@ -62,7 +62,8 @@ FILES= \
test-clang.bin \
test-llvm.bin \
test-llvm-version.bin \
test-libaio.bin
test-libaio.bin \
test-libzstd.bin
FILES := $(addprefix $(OUTPUT),$(FILES))
......@@ -301,6 +302,9 @@ $(OUTPUT)test-clang.bin:
$(OUTPUT)test-libaio.bin:
$(BUILD) -lrt
$(OUTPUT)test-libzstd.bin:
$(BUILD) -lzstd
###############################
clean:
......
......@@ -182,6 +182,10 @@
# include "test-disassembler-four-args.c"
#undef main
#define main main_test_zstd
# include "test-libzstd.c"
#undef main
int main(int argc, char *argv[])
{
main_test_libpython();
......@@ -224,6 +228,7 @@ int main(int argc, char *argv[])
main_test_libaio();
main_test_reallocarray();
main_test_disassembler_four_args();
main_test_libzstd();
return 0;
}
// SPDX-License-Identifier: GPL-2.0
#include <zstd.h>
int main(void)
{
ZSTD_CStream *cstream;
cstream = ZSTD_createCStream();
ZSTD_freeCStream(cstream);
return 0;
}
......@@ -8,6 +8,22 @@
#include "event-parse-local.h"
#include "event-utils.h"
/**
* tep_get_event - returns the event with the given index
* @tep: a handle to the tep_handle
* @index: index of the requested event, in the range 0 .. nr_events
*
* This returns pointer to the element of the events array with the given index
* If @tep is NULL, or @index is not in the range 0 .. nr_events, NULL is returned.
*/
struct tep_event *tep_get_event(struct tep_handle *tep, int index)
{
if (tep && tep->events && index < tep->nr_events)
return tep->events[index];
return NULL;
}
/**
* tep_get_first_event - returns the first event in the events array
* @tep: a handle to the tep_handle
......@@ -17,10 +33,7 @@
*/
struct tep_event *tep_get_first_event(struct tep_handle *tep)
{
if (tep && tep->events)
return tep->events[0];
return NULL;
return tep_get_event(tep, 0);
}
/**
......@@ -32,7 +45,7 @@ struct tep_event *tep_get_first_event(struct tep_handle *tep)
*/
int tep_get_events_count(struct tep_handle *tep)
{
if(tep)
if (tep)
return tep->nr_events;
return 0;
}
......@@ -43,19 +56,47 @@ int tep_get_events_count(struct tep_handle *tep)
* @flag: flag, or combination of flags to be set
* can be any combination from enum tep_flag
*
* This sets a flag or mbination of flags from enum tep_flag
*/
* This sets a flag or combination of flags from enum tep_flag
*/
void tep_set_flag(struct tep_handle *tep, int flag)
{
if(tep)
if (tep)
tep->flags |= flag;
}
unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data)
/**
* tep_clear_flag - clear event parser flag
* @tep: a handle to the tep_handle
* @flag: flag to be cleared
*
* This clears a tep flag
*/
void tep_clear_flag(struct tep_handle *tep, enum tep_flag flag)
{
if (tep)
tep->flags &= ~flag;
}
/**
* tep_test_flag - check the state of event parser flag
* @tep: a handle to the tep_handle
* @flag: flag to be checked
*
* This returns the state of the requested tep flag.
* Returns: true if the flag is set, false otherwise.
*/
bool tep_test_flag(struct tep_handle *tep, enum tep_flag flag)
{
if (tep)
return tep->flags & flag;
return false;
}
unsigned short tep_data2host2(struct tep_handle *tep, unsigned short data)
{
unsigned short swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
if (!tep || tep->host_bigendian == tep->file_bigendian)
return data;
swap = ((data & 0xffULL) << 8) |
......@@ -64,11 +105,11 @@ unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data)
return swap;
}
unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data)
unsigned int tep_data2host4(struct tep_handle *tep, unsigned int data)
{
unsigned int swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
if (!tep || tep->host_bigendian == tep->file_bigendian)
return data;
swap = ((data & 0xffULL) << 24) |
......@@ -80,11 +121,11 @@ unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data)
}
unsigned long long
tep_data2host8(struct tep_handle *pevent, unsigned long long data)
tep_data2host8(struct tep_handle *tep, unsigned long long data)
{
unsigned long long swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
if (!tep || tep->host_bigendian == tep->file_bigendian)
return data;
swap = ((data & 0xffULL) << 56) |
......@@ -101,175 +142,232 @@ tep_data2host8(struct tep_handle *pevent, unsigned long long data)
/**
* tep_get_header_page_size - get size of the header page
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
*
* This returns size of the header page
* If @pevent is NULL, 0 is returned.
* If @tep is NULL, 0 is returned.
*/
int tep_get_header_page_size(struct tep_handle *tep)
{
if (tep)
return tep->header_page_size_size;
return 0;
}
/**
* tep_get_header_timestamp_size - get size of the timestamp in the header page
* @tep: a handle to the tep_handle
*
* This returns size of the timestamp in the header page
* If @tep is NULL, 0 is returned.
*/
int tep_get_header_page_size(struct tep_handle *pevent)
int tep_get_header_timestamp_size(struct tep_handle *tep)
{
if(pevent)
return pevent->header_page_size_size;
if (tep)
return tep->header_page_ts_size;
return 0;
}
/**
* tep_get_cpus - get the number of CPUs
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
*
* This returns the number of CPUs
* If @pevent is NULL, 0 is returned.
* If @tep is NULL, 0 is returned.
*/
int tep_get_cpus(struct tep_handle *pevent)
int tep_get_cpus(struct tep_handle *tep)
{
if(pevent)
return pevent->cpus;
if (tep)
return tep->cpus;
return 0;
}
/**
* tep_set_cpus - set the number of CPUs
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
*
* This sets the number of CPUs
*/
void tep_set_cpus(struct tep_handle *pevent, int cpus)
void tep_set_cpus(struct tep_handle *tep, int cpus)
{
if(pevent)
pevent->cpus = cpus;
if (tep)
tep->cpus = cpus;
}
/**
* tep_get_long_size - get the size of a long integer on the current machine
* @pevent: a handle to the tep_handle
* tep_get_long_size - get the size of a long integer on the traced machine
* @tep: a handle to the tep_handle
*
* This returns the size of a long integer on the current machine
* If @pevent is NULL, 0 is returned.
* This returns the size of a long integer on the traced machine
* If @tep is NULL, 0 is returned.
*/
int tep_get_long_size(struct tep_handle *pevent)
int tep_get_long_size(struct tep_handle *tep)
{
if(pevent)
return pevent->long_size;
if (tep)
return tep->long_size;
return 0;
}
/**
* tep_set_long_size - set the size of a long integer on the current machine
* @pevent: a handle to the tep_handle
* tep_set_long_size - set the size of a long integer on the traced machine
* @tep: a handle to the tep_handle
* @size: size, in bytes, of a long integer
*
* This sets the size of a long integer on the current machine
* This sets the size of a long integer on the traced machine
*/
void tep_set_long_size(struct tep_handle *pevent, int long_size)
void tep_set_long_size(struct tep_handle *tep, int long_size)
{
if(pevent)
pevent->long_size = long_size;
if (tep)
tep->long_size = long_size;
}
/**
* tep_get_page_size - get the size of a memory page on the current machine
* @pevent: a handle to the tep_handle
* tep_get_page_size - get the size of a memory page on the traced machine
* @tep: a handle to the tep_handle
*
* This returns the size of a memory page on the current machine
* If @pevent is NULL, 0 is returned.
* This returns the size of a memory page on the traced machine
* If @tep is NULL, 0 is returned.
*/
int tep_get_page_size(struct tep_handle *pevent)
int tep_get_page_size(struct tep_handle *tep)
{
if(pevent)
return pevent->page_size;
if (tep)
return tep->page_size;
return 0;
}
/**
* tep_set_page_size - set the size of a memory page on the current machine
* @pevent: a handle to the tep_handle
* tep_set_page_size - set the size of a memory page on the traced machine
* @tep: a handle to the tep_handle
* @_page_size: size of a memory page, in bytes
*
* This sets the size of a memory page on the current machine
* This sets the size of a memory page on the traced machine
*/
void tep_set_page_size(struct tep_handle *pevent, int _page_size)
void tep_set_page_size(struct tep_handle *tep, int _page_size)
{
if(pevent)
pevent->page_size = _page_size;
if (tep)
tep->page_size = _page_size;
}
/**
* tep_file_bigendian - get if the file is in big endian order
* @pevent: a handle to the tep_handle
* tep_is_file_bigendian - return the endian of the file
* @tep: a handle to the tep_handle
*
* This returns if the file is in big endian order
* If @pevent is NULL, 0 is returned.
* This returns true if the file is in big endian order
* If @tep is NULL, false is returned.
*/
int tep_file_bigendian(struct tep_handle *pevent)
bool tep_is_file_bigendian(struct tep_handle *tep)
{
if(pevent)
return pevent->file_bigendian;
return 0;
if (tep)
return (tep->file_bigendian == TEP_BIG_ENDIAN);
return false;
}
/**
* tep_set_file_bigendian - set if the file is in big endian order
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
* @endian: non zero, if the file is in big endian order
*
* This sets if the file is in big endian order
*/
void tep_set_file_bigendian(struct tep_handle *pevent, enum tep_endian endian)
void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian)
{
if(pevent)
pevent->file_bigendian = endian;
if (tep)
tep->file_bigendian = endian;
}
/**
* tep_is_host_bigendian - get if the order of the current host is big endian
* @pevent: a handle to the tep_handle
* tep_is_local_bigendian - return the endian of the saved local machine
* @tep: a handle to the tep_handle
*
* This gets if the order of the current host is big endian
* If @pevent is NULL, 0 is returned.
* This returns true if the saved local machine in @tep is big endian.
* If @tep is NULL, false is returned.
*/
int tep_is_host_bigendian(struct tep_handle *pevent)
bool tep_is_local_bigendian(struct tep_handle *tep)
{
if(pevent)
return pevent->host_bigendian;
if (tep)
return (tep->host_bigendian == TEP_BIG_ENDIAN);
return 0;
}
/**
* tep_set_host_bigendian - set the order of the local host
* @pevent: a handle to the tep_handle
* tep_set_local_bigendian - set the stored local machine endian order
* @tep: a handle to the tep_handle
* @endian: non zero, if the local host has big endian order
*
* This sets the order of the local host
* This sets the endian order for the local machine.
*/
void tep_set_host_bigendian(struct tep_handle *pevent, enum tep_endian endian)
void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian)
{
if(pevent)
pevent->host_bigendian = endian;
if (tep)
tep->host_bigendian = endian;
}
/**
* tep_is_latency_format - get if the latency output format is configured
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
*
* This gets if the latency output format is configured
* If @pevent is NULL, 0 is returned.
* This returns true if the latency output format is configured
* If @tep is NULL, false is returned.
*/
int tep_is_latency_format(struct tep_handle *pevent)
bool tep_is_latency_format(struct tep_handle *tep)
{
if(pevent)
return pevent->latency_format;
return 0;
if (tep)
return (tep->latency_format);
return false;
}
/**
* tep_set_latency_format - set the latency output format
* @pevent: a handle to the tep_handle
* @tep: a handle to the tep_handle
* @lat: non zero for latency output format
*
* This sets the latency output format
*/
void tep_set_latency_format(struct tep_handle *pevent, int lat)
void tep_set_latency_format(struct tep_handle *tep, int lat)
{
if (tep)
tep->latency_format = lat;
}
/**
* tep_is_old_format - get if an old kernel is used
* @tep: a handle to the tep_handle
*
* This returns true, if an old kernel is used to generate the tracing events or
* false if a new kernel is used. Old kernels did not have header page info.
* If @tep is NULL, false is returned.
*/
bool tep_is_old_format(struct tep_handle *tep)
{
if (tep)
return tep->old_format;
return false;
}
/**
* tep_set_print_raw - set a flag to force print in raw format
* @tep: a handle to the tep_handle
* @print_raw: the new value of the print_raw flag
*
* This sets a flag to force print in raw format
*/
void tep_set_print_raw(struct tep_handle *tep, int print_raw)
{
if (tep)
tep->print_raw = print_raw;
}
/**
* tep_set_test_filters - set a flag to test a filter string
* @tep: a handle to the tep_handle
* @test_filters: the new value of the test_filters flag
*
* This sets a flag to test a filter string. If this flag is set, when
* tep_filter_add_filter_str() API as called,it will print the filter string
* instead of adding it.
*/
void tep_set_test_filters(struct tep_handle *tep, int test_filters)
{
if(pevent)
pevent->latency_format = lat;
if (tep)
tep->test_filters = test_filters;
}
......@@ -92,8 +92,8 @@ struct tep_handle {
void tep_free_event(struct tep_event *event);
void tep_free_format_field(struct tep_format_field *field);
unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data);
unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data);
unsigned long long tep_data2host8(struct tep_handle *pevent, unsigned long long data);
unsigned short tep_data2host2(struct tep_handle *tep, unsigned short data);
unsigned int tep_data2host4(struct tep_handle *tep, unsigned int data);
unsigned long long tep_data2host8(struct tep_handle *tep, unsigned long long data);
#endif /* _PARSE_EVENTS_INT_H */
此差异已折叠。
此差异已折叠。
......@@ -269,7 +269,7 @@ void tep_print_plugins(struct trace_seq *s,
}
static void
load_plugin(struct tep_handle *pevent, const char *path,
load_plugin(struct tep_handle *tep, const char *path,
const char *file, void *data)
{
struct tep_plugin_list **plugin_list = data;
......@@ -316,7 +316,7 @@ load_plugin(struct tep_handle *pevent, const char *path,
*plugin_list = list;
pr_stat("registering plugin: %s", plugin);
func(pevent);
func(tep);
return;
out_free:
......@@ -324,9 +324,9 @@ load_plugin(struct tep_handle *pevent, const char *path,
}
static void
load_plugins_dir(struct tep_handle *pevent, const char *suffix,
load_plugins_dir(struct tep_handle *tep, const char *suffix,
const char *path,
void (*load_plugin)(struct tep_handle *pevent,
void (*load_plugin)(struct tep_handle *tep,
const char *path,
const char *name,
void *data),
......@@ -359,15 +359,15 @@ load_plugins_dir(struct tep_handle *pevent, const char *suffix,
if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
continue;
load_plugin(pevent, path, name, data);
load_plugin(tep, path, name, data);
}
closedir(dir);
}
static void
load_plugins(struct tep_handle *pevent, const char *suffix,
void (*load_plugin)(struct tep_handle *pevent,
load_plugins(struct tep_handle *tep, const char *suffix,
void (*load_plugin)(struct tep_handle *tep,
const char *path,
const char *name,
void *data),
......@@ -378,7 +378,7 @@ load_plugins(struct tep_handle *pevent, const char *suffix,
char *envdir;
int ret;
if (pevent->flags & TEP_DISABLE_PLUGINS)
if (tep->flags & TEP_DISABLE_PLUGINS)
return;
/*
......@@ -386,8 +386,8 @@ load_plugins(struct tep_handle *pevent, const char *suffix,
* check that first.
*/
#ifdef PLUGIN_DIR
if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS))
load_plugins_dir(pevent, suffix, PLUGIN_DIR,
if (!(tep->flags & TEP_DISABLE_SYS_PLUGINS))
load_plugins_dir(tep, suffix, PLUGIN_DIR,
load_plugin, data);
#endif
......@@ -397,7 +397,7 @@ load_plugins(struct tep_handle *pevent, const char *suffix,
*/
envdir = getenv("TRACEEVENT_PLUGIN_DIR");
if (envdir)
load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
load_plugins_dir(tep, suffix, envdir, load_plugin, data);
/*
* Now let the home directory override the environment
......@@ -413,22 +413,22 @@ load_plugins(struct tep_handle *pevent, const char *suffix,
return;
}
load_plugins_dir(pevent, suffix, path, load_plugin, data);
load_plugins_dir(tep, suffix, path, load_plugin, data);
free(path);
}
struct tep_plugin_list*
tep_load_plugins(struct tep_handle *pevent)
tep_load_plugins(struct tep_handle *tep)
{
struct tep_plugin_list *list = NULL;
load_plugins(pevent, ".so", load_plugin, &list);
load_plugins(tep, ".so", load_plugin, &list);
return list;
}
void
tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *pevent)
tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
{
tep_plugin_unload_func func;
struct tep_plugin_list *list;
......@@ -438,7 +438,7 @@ tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *peven
plugin_list = list->next;
func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
if (func)
func(pevent);
func(tep);
dlclose(list->handle);
free(list->name);
free(list);
......
......@@ -727,3 +727,52 @@ int kbuffer_start_of_data(struct kbuffer *kbuf)
{
return kbuf->start;
}
/**
* kbuffer_raw_get - get raw buffer info
* @kbuf: The kbuffer
* @subbuf: Start of mapped subbuffer
* @info: Info descriptor to fill in
*
* For debugging. This can return internals of the ring buffer.
* Expects to have info->next set to what it will read.
* The type, length and timestamp delta will be filled in, and
* @info->next will be updated to the next element.
* The @subbuf is used to know if the info is passed the end of
* data and NULL will be returned if it is.
*/
struct kbuffer_raw_info *
kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf, struct kbuffer_raw_info *info)
{
unsigned long long flags;
unsigned long long delta;
unsigned int type_len;
unsigned int size;
int start;
int length;
void *ptr = info->next;
if (!kbuf || !subbuf)
return NULL;
if (kbuf->flags & KBUFFER_FL_LONG_8)
start = 16;
else
start = 12;
flags = read_long(kbuf, subbuf + 8);
size = (unsigned int)flags & COMMIT_MASK;
if (ptr < subbuf || ptr >= subbuf + start + size)
return NULL;
type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
info->next = ptr + length;
info->type = type_len;
info->delta = delta;
info->length = length;
return info;
}
......@@ -65,4 +65,17 @@ int kbuffer_subbuffer_size(struct kbuffer *kbuf);
void kbuffer_set_old_format(struct kbuffer *kbuf);
int kbuffer_start_of_data(struct kbuffer *kbuf);
/* Debugging */
struct kbuffer_raw_info {
int type;
int length;
unsigned long long delta;
void *next;
};
/* Read raw data */
struct kbuffer_raw_info *kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf,
struct kbuffer_raw_info *info);
#endif /* _K_BUFFER_H */
此差异已折叠。
......@@ -25,9 +25,9 @@ process___le16_to_cpup(struct trace_seq *s, unsigned long long *args)
return val ? (long long) le16toh(*val) : 0;
}
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
{
tep_register_print_function(pevent,
tep_register_print_function(tep,
process___le16_to_cpup,
TEP_FUNC_ARG_INT,
"__le16_to_cpup",
......@@ -36,8 +36,8 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
return 0;
}
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
{
tep_unregister_print_function(pevent, process___le16_to_cpup,
tep_unregister_print_function(tep, process___le16_to_cpup,
"__le16_to_cpup");
}
......@@ -126,7 +126,7 @@ static int add_and_get_index(const char *parent, const char *child, int cpu)
static int function_handler(struct trace_seq *s, struct tep_record *record,
struct tep_event *event, void *context)
{
struct tep_handle *pevent = event->pevent;
struct tep_handle *tep = event->tep;
unsigned long long function;
unsigned long long pfunction;
const char *func;
......@@ -136,12 +136,12 @@ static int function_handler(struct trace_seq *s, struct tep_record *record,
if (tep_get_field_val(s, event, "ip", record, &function, 1))
return trace_seq_putc(s, '!');
func = tep_find_function(pevent, function);
func = tep_find_function(tep, function);
if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
return trace_seq_putc(s, '!');
parent = tep_find_function(pevent, pfunction);
parent = tep_find_function(tep, pfunction);
if (parent && ftrace_indent->set)
index = add_and_get_index(parent, func, record->cpu);
......@@ -164,9 +164,9 @@ static int function_handler(struct trace_seq *s, struct tep_record *record,
return 0;
}
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
{
tep_register_event_handler(pevent, -1, "ftrace", "function",
tep_register_event_handler(tep, -1, "ftrace", "function",
function_handler, NULL);
tep_plugin_add_options("ftrace", plugin_options);
......@@ -174,11 +174,11 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
return 0;
}
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
{
int i, x;
tep_unregister_event_handler(pevent, -1, "ftrace", "function",
tep_unregister_event_handler(tep, -1, "ftrace", "function",
function_handler, NULL);
for (i = 0; i <= cpus; i++) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -87,17 +87,17 @@ static int drv_bss_info_changed(struct trace_seq *s,
return 0;
}
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
{
tep_register_event_handler(pevent, -1, "mac80211",
tep_register_event_handler(tep, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
return 0;
}
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
{
tep_unregister_event_handler(pevent, -1, "mac80211",
tep_unregister_event_handler(tep, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册