lkml.org 
[lkml]   [2021]   [Apr]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V4 21/25] perf: Introduce PERF_TYPE_HARDWARE_PMU and PERF_TYPE_HW_CACHE_PMU
    Date
    From: Kan Liang <kan.liang@linux.intel.com>

    Current Hardware events and Hardware cache events have special perf
    types, PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE. The two types don't
    pass the PMU type in the user interface. For a hybrid system, the perf
    subsystem doesn't know which PMU the events belong to. The first capable
    PMU will always be assigned to the events. The events never get a chance
    to run on the other capable PMUs.

    Add a PMU aware version PERF_TYPE_HARDWARE_PMU and
    PERF_TYPE_HW_CACHE_PMU. The PMU type ID is stored at attr.config[40:32].
    Support the new types for X86.

    Suggested-by: Andi Kleen <ak@linux.intel.com>
    Reviewed-by: Andi Kleen <ak@linux.intel.com>
    Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
    ---
    arch/x86/events/core.c | 10 ++++++++--
    include/uapi/linux/perf_event.h | 26 ++++++++++++++++++++++++++
    kernel/events/core.c | 14 +++++++++++++-
    3 files changed, 47 insertions(+), 3 deletions(-)

    diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
    index 18b75d6..36cfebad 100644
    --- a/arch/x86/events/core.c
    +++ b/arch/x86/events/core.c
    @@ -488,7 +488,7 @@ int x86_setup_perfctr(struct perf_event *event)
    if (attr->type == event->pmu->type)
    return x86_pmu_extra_regs(event->attr.config, event);

    - if (attr->type == PERF_TYPE_HW_CACHE)
    + if ((attr->type == PERF_TYPE_HW_CACHE) || (attr->type == PERF_TYPE_HW_CACHE_PMU))
    return set_ext_hw_attr(hwc, event);

    if (attr->config >= x86_pmu.max_events)
    @@ -2452,9 +2452,15 @@ static int x86_pmu_event_init(struct perf_event *event)

    if ((event->attr.type != event->pmu->type) &&
    (event->attr.type != PERF_TYPE_HARDWARE) &&
    - (event->attr.type != PERF_TYPE_HW_CACHE))
    + (event->attr.type != PERF_TYPE_HW_CACHE) &&
    + (event->attr.type != PERF_TYPE_HARDWARE_PMU) &&
    + (event->attr.type != PERF_TYPE_HW_CACHE_PMU))
    return -ENOENT;

    + if ((event->attr.type == PERF_TYPE_HARDWARE_PMU) ||
    + (event->attr.type == PERF_TYPE_HW_CACHE_PMU))
    + event->attr.config &= PERF_HW_CACHE_EVENT_MASK;
    +
    if (is_hybrid() && (event->cpu != -1)) {
    pmu = hybrid_pmu(event->pmu);
    if (!cpumask_test_cpu(event->cpu, &pmu->supported_cpus))
    diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
    index ad15e40..c0a511e 100644
    --- a/include/uapi/linux/perf_event.h
    +++ b/include/uapi/linux/perf_event.h
    @@ -33,6 +33,8 @@ enum perf_type_id {
    PERF_TYPE_HW_CACHE = 3,
    PERF_TYPE_RAW = 4,
    PERF_TYPE_BREAKPOINT = 5,
    + PERF_TYPE_HARDWARE_PMU = 6,
    + PERF_TYPE_HW_CACHE_PMU = 7,

    PERF_TYPE_MAX, /* non-ABI */
    };
    @@ -95,6 +97,30 @@ enum perf_hw_cache_op_result_id {
    };

    /*
    + * attr.config layout for type PERF_TYPE_HARDWARE* and PERF_TYPE_HW_CACHE*
    + * PERF_TYPE_HARDWARE: 0xAA
    + * AA: hardware event ID
    + * PERF_TYPE_HW_CACHE: 0xCCBBAA
    + * AA: hardware cache ID
    + * BB: hardware cache op ID
    + * CC: hardware cache op result ID
    + * PERF_TYPE_HARDWARE_PMU: 0xDD000000AA
    + * AA: hardware event ID
    + * DD: PMU type ID
    + * PERF_TYPE_HW_CACHE_PMU: 0xDD00CCBBAA
    + * AA: hardware cache ID
    + * BB: hardware cache op ID
    + * CC: hardware cache op result ID
    + * DD: PMU type ID
    + */
    +#define PERF_HW_CACHE_ID_SHIFT 0
    +#define PERF_HW_CACHE_OP_ID_SHIFT 8
    +#define PERF_HW_CACHE_OP_RESULT_ID_SHIFT 16
    +#define PERF_HW_CACHE_EVENT_MASK 0xffffff
    +
    +#define PERF_PMU_TYPE_SHIFT 32
    +
    +/*
    * Special "software" events provided by the kernel, even if the hardware
    * does not support performance events. These events measure various
    * physical and sw events of the kernel (and allow the profiling of them as
    diff --git a/kernel/events/core.c b/kernel/events/core.c
    index f079431..b8ab756 100644
    --- a/kernel/events/core.c
    +++ b/kernel/events/core.c
    @@ -11093,6 +11093,14 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
    return ret;
    }

    +static bool perf_event_is_hw_pmu_type(struct perf_event *event)
    +{
    + int type = event->attr.type;
    +
    + return type == PERF_TYPE_HARDWARE_PMU ||
    + type == PERF_TYPE_HW_CACHE_PMU;
    +}
    +
    static struct pmu *perf_init_event(struct perf_event *event)
    {
    int idx, type, ret;
    @@ -11116,13 +11124,17 @@ static struct pmu *perf_init_event(struct perf_event *event)
    if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE)
    type = PERF_TYPE_RAW;

    + if (perf_event_is_hw_pmu_type(event))
    + type = event->attr.config >> PERF_PMU_TYPE_SHIFT;
    +
    again:
    rcu_read_lock();
    pmu = idr_find(&pmu_idr, type);
    rcu_read_unlock();
    if (pmu) {
    ret = perf_try_init_event(pmu, event);
    - if (ret == -ENOENT && event->attr.type != type) {
    + if (ret == -ENOENT && event->attr.type != type &&
    + !perf_event_is_hw_pmu_type(event)) {
    type = event->attr.type;
    goto again;
    }
    --
    2.7.4
    \
     
     \ /
      Last update: 2021-04-02 02:19    [W:4.031 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site