• Matt Redfearn's avatar
    MIPS: perf: Fix perf with MT counting other threads · 84002c88
    Matt Redfearn authored
    When perf is used in non-system mode, i.e. without specifying CPUs to
    count on, check_and_calc_range falls into the case when it sets
    M_TC_EN_ALL in the counter config_base. This has the impact of always
    counting for all of the threads in a core, even when the user has not
    requested it. For example this can be seen with a test program which
    executes 30002 instructions and 10000 branches running on one VPE and a
    busy load on the other VPE in the core. Without this commit, the
    expected count is not returned:
    
    taskset 4 dd if=/dev/zero of=/dev/null count=100000 & taskset 8 perf
    stat -e instructions:u,branches:u ./test_prog
    
     Performance counter stats for './test_prog':
    
                103235      instructions:u
                 17015      branches:u
    
    In order to fix this, remove check_and_calc_range entirely and perform
    all of the logic in mipsxx_pmu_enable_event. Since
    mipsxx_pmu_enable_event now requires the range of the event, ensure that
    it is set by mipspmu_perf_event_encode in the same circumstances as
    before (i.e. #ifdef CONFIG_MIPS_MT_SMP && num_possible_cpus() > 1).
    
    The logic of mipsxx_pmu_enable_event now becomes:
    If the CPU is a BMIPS5000, then use the special vpe_id() implementation
    to select which VPE to count.
    If the counter has a range greater than a single VPE, i.e. it is a
    core-wide counter, then ensure that the counter is set up to count
    events from all TCs (though, since this is true by definition, is this
    necessary? Just enabling a core-wide counter in the per-VPE case appears
    experimentally to return the same counts. This is left in for now as the
    logic was present before).
    If the event is set up to count a particular CPU (i.e. system mode),
    then the VPE ID of that CPU is used for the counter.
    Otherwise, the event should be counted on the CPU scheduling this thread
    (this was the critical bit missing from the previous implementation) so
    the VPE ID of this CPU is used for the counter.
    
    With this commit, the same test as before returns the counts expected:
    
    taskset 4 dd if=/dev/zero of=/dev/null count=100000 & taskset 8 perf
    stat -e instructions:u,branches:u ./test_prog
    
     Performance counter stats for './test_prog':
    
                 30002      instructions:u
                 10000      branches:u
    Signed-off-by: default avatarMatt Redfearn <matt.redfearn@mips.com>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: Florian Fainelli <f.fainelli@gmail.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
    Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    Cc: Jiri Olsa <jolsa@redhat.com>
    Cc: Namhyung Kim <namhyung@kernel.org>
    Cc: linux-mips@linux-mips.org
    Patchwork: https://patchwork.linux-mips.org/patch/19138/Signed-off-by: default avatarJames Hogan <jhogan@kernel.org>
    84002c88
perf_event_mipsxx.c 47.1 KB