sparc: Fix single-pcr perf event counter management.
Sasha Levin
maintainerPATCH 1/5 sparc: Fix single-pcr perf event counter management.
From: "David S. Miller" <[email protected]>
[ Upstream commit cfdc3170d214046b9509183fe9b9544dc644d40b ]
It is important to clear the hw->state value for non-stopped events when they are added into the PMU. Otherwise when the event is scheduled out, we won't read the counter because HES_UPTODATE is still set. This breaks 'perf stat' and similar use cases, causing all the events to show zero.
This worked for multi-pcr because we make explicit sparc_pmu_start() calls in calculate_multiple_pcrs(). calculate_single_pcr() doesn't do this because the idea there is to accumulate all of the counter settings into the single pcr value. So we have to add explicit hw->state handling there.
Like x86, we use the PERF_HES_ARCH bit to track truly stopped events so that we don't accidently start them on a reload.
Related to all of this, sparc_pmu_start() is missing a userpage update so add it.
--- arch/sparc/kernel/perf_event.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
arch/sparc/kernel/perf_event.c +13 -4
@@ -919,6 +919,8 @@ static void read_in_all_counters(struct cpu_hw_events *cpuc)sparc_perf_event_update (cp, &cp->hw, cpuc->current_idx[i]); cpuc->current_idx[i] =PIC_NO_INDEX ; +if (cp->hw.state &PERF_HES_STOPPED ) + cp->hw.state |=PERF_HES_ARCH ; } } }
@@ -951,10 +953,12 @@ static void calculate_single_pcr(struct cpu_hw_events *cpuc) enc =perf_event_get_enc (cpuc->events[i]); cpuc->pcr[0 ] &= ~mask_for_index (idx); -if (hwc->state &PERF_HES_STOPPED ) +if (hwc->state &PERF_HES_ARCH ) { cpuc->pcr[0 ] |=nop_for_index (idx); -else + }else { cpuc->pcr[0 ] |=event_encoding (enc, idx); + hwc->state =0 ; + } } out: cpuc->pcr[0 ] |= cpuc->event[0 ]->hw.config_base;
@@ -980,6 +984,9 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc) cpuc->current_idx[i] = idx; +if (cp->hw.state &PERF_HES_ARCH ) +continue ; +sparc_pmu_start (cp,PERF_EF_RELOAD ); } out:
@@ -1071,6 +1078,8 @@ static void sparc_pmu_start(struct perf_event *event, int flags) event->hw.state =0 ;sparc_pmu_enable_event (cpuc, &event->hw, idx); + +perf_event_update_userpage (event); }static void sparc_pmu_stop (struct perf_event *event,int flags)
@@ -1363,9 +1372,9 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags) cpuc->events[n0] = event->hw.event_base; cpuc->current_idx[n0] =PIC_NO_INDEX ; - event->hw.state =PERF_HES_UPTODATE ; + event->hw.state =PERF_HES_UPTODATE |PERF_HES_STOPPED ;if (!(ef_flags &PERF_EF_START )) - event->hw.state |=PERF_HES_STOPPED ; + event->hw.state |=PERF_HES_ARCH ;/* * If group events scheduling transaction was started,
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 2/5 sparc: Throttle perf events properly.
From: "David S. Miller" <[email protected]>
[ Upstream commit 455adb3174d2c8518cef1a61140c211f6ac224d2 ]
Like x86 and arm, call perf_sample_event_took() in perf event NMI interrupt handler.
--- arch/sparc/kernel/perf_event.c | 9 +++++++++ 1 file changed, 9 insertions(+)
arch/sparc/kernel/perf_event.c +9 -0
@@ -23,6 +23,7 @@#include <asm/cpudata.h> #include <asm/uaccess.h> #include <linux/atomic.h> +#include <linux/sched/clock.h> #include <asm/nmi.h> #include <asm/pcr.h> #include <asm/cacheflush.h>
@@ -1586,6 +1587,8 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,struct perf_sample_data data;struct cpu_hw_events *cpuc;struct pt_regs *regs; +u64 finish_clock; +u64 start_clock;int i;if (!atomic_read (&active_events))
@@ -1599,6 +1602,8 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,return NOTIFY_DONE ; } + start_clock =sched_clock (); + regs = args->regs; cpuc =this_cpu_ptr (&cpu_hw_events);
@@ -1637,6 +1642,10 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,sparc_pmu_stop (event,0 ); } + finish_clock =sched_clock (); + +perf_sample_event_took (finish_clock - start_clock); +return NOTIFY_STOP ; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 3/5 net: qla3xxx: Remove overflowing shift statement
In reply to Sasha LevinFrom: Nathan Chancellor <[email protected]>
[ Upstream commit 8c3bf9b62b667456a57aefcf1689e826df146159 ]
Clang currently warns:
drivers/net/ethernet/qlogic/qla3xxx.c:384:24: warning: signed shift result (0xF00000000) requires 37 bits to represent, but 'int' only has 32 bits [-Wshift-overflow]
((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
~~~~~~~~~~~~~~ ^ ~~1 warning generated.
The warning is certainly accurate since ISP_NVRAM_MASK is defined as (0x000F << 16) which is then shifted by 16, resulting in 64424509440, well above UINT_MAX.
Given that this is the only location in this driver where ISP_NVRAM_MASK is shifted again, it seems likely that ISP_NVRAM_MASK was originally defined without a shift and during the move of the shift to the definition, this statement wasn't properly removed (since ISP_NVRAM_MASK is used in the statenent right above this). Only the maintainers can confirm this since this statment has been here since the driver was first added to the kernel.
--- drivers/net/ethernet/qlogic/qla3xxx.c | 2 -- 1 file changed, 2 deletions(-)
drivers/net/ethernet/qlogic/qla3xxx.c +0 -2
@@ -382,8 +382,6 @@ static void fm93c56a_select(struct ql3_adapter *qdev) qdev->eeprom_cmd_data =AUBURN_EEPROM_CS_1 ;ql_write_nvram_reg (qdev, spir,ISP_NVRAM_MASK | qdev->eeprom_cmd_data); -ql_write_nvram_reg (qdev, spir, - ((ISP_NVRAM_MASK <<16 ) | qdev->eeprom_cmd_data)); }/*
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 4/5 r8169: fix NAPI handling under high load
In reply to Sasha LevinFrom: Heiner Kallweit <[email protected]>
[ Upstream commit 6b839b6cf9eada30b086effb51e5d6076bafc761 ]
rtl_rx() and rtl_tx() are called only if the respective bits are set in the interrupt status register. Under high load NAPI may not be able to process all data (work_done == budget) and it will schedule subsequent calls to the poll callback.rtl_ack_events() however resets the bits in the interrupt status register, therefore subsequent calls to rtl8169_poll() won't call rtl_rx() and rtl_tx() - chip interrupts are still disabled.
Fix this by calling rtl_rx() and rtl_tx() independent of the bits set in the interrupt status register. Both functions will detect if there's nothing to do for them.
--- drivers/net/ethernet/realtek/r8169.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/net/ethernet/realtek/r8169.c +3 -5
@@ -7445,17 +7445,15 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);struct net_device *dev = tp->dev;u16 enable_mask =RTL_EVENT_NAPI | tp->event_slow; -int work_done=0 ; +int work_done;u16 status; status =rtl_get_events (tp);rtl_ack_events (tp, status & ~tp->event_slow); -if (status &RTL_EVENT_NAPI_RX ) - work_done =rtl_rx (dev, tp, (u32 ) budget); + work_done =rtl_rx (dev, tp, (u32 ) budget); -if (status &RTL_EVENT_NAPI_TX ) -rtl_tx (dev, tp); +rtl_tx (dev, tp);if (status & tp->event_slow) { enable_mask &= ~tp->event_slow;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 5/5 selftests: ftrace: Add synthetic event syntax testcase
In reply to Sasha LevinFrom: Masami Hiramatsu <[email protected]>
[ Upstream commit ba0e41ca81b935b958006c7120466e2217357827 ]
Add a testcase to check the syntax and field types for synthetic_events interface.
--- .../trigger-synthetic-event-syntax.tc | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-syntax.tc
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-syntax.tc new file +80 -0
@@ -0,0 +1,80 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: event trigger - test synthetic_events syntax parser + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +reset_tracer +do_reset + +echo "Test synthetic_events syntax parser" + +echo > synthetic_events + +# synthetic event must have a field +! echo "myevent" >> synthetic_events +echo "myevent u64 var1" >> synthetic_events + +# synthetic event must be found in synthetic_events +grep "myevent[[:space:]]u64 var1" synthetic_events + +# it is not possible to add same name event +! echo "myevent u64 var2" >> synthetic_events + +# Non-append open will cleanup all events and add new one +echo "myevent u64 var2" > synthetic_events + +# multiple fields with different spaces +echo "myevent u64 var1; u64 var2;" > synthetic_events +grep "myevent[[:space:]]u64 var1; u64 var2" synthetic_events +echo "myevent u64 var1 ; u64 var2 ;" > synthetic_events +grep "myevent[[:space:]]u64 var1; u64 var2" synthetic_events +echo "myevent u64 var1 ;u64 var2" > synthetic_events +grep "myevent[[:space:]]u64 var1; u64 var2" synthetic_events + +# test field types +echo "myevent u32 var" > synthetic_events +echo "myevent u16 var" > synthetic_events +echo "myevent u8 var" > synthetic_events +echo "myevent s64 var" > synthetic_events +echo "myevent s32 var" > synthetic_events +echo "myevent s16 var" > synthetic_events +echo "myevent s8 var" > synthetic_events + +echo "myevent char var" > synthetic_events +echo "myevent int var" > synthetic_events +echo "myevent long var" > synthetic_events +echo "myevent pid_t var" > synthetic_events + +echo "myevent unsigned char var" > synthetic_events +echo "myevent unsigned int var" > synthetic_events +echo "myevent unsigned long var" > synthetic_events +grep "myevent[[:space:]]unsigned long var" synthetic_events + +# test string type +echo "myevent char var[10]" > synthetic_events +grep "myevent[[:space:]]char\[10\] var" synthetic_events + +do_reset + +exit 0
Signature · 1 line
2.17.1