Add a new function perf_event_topdown_metrics(). This new function is
quite familiar with function perf_event_period(), but it updates slots
count and metrics raw data instead of sample period into perf system.
When guest restores FIXED_CTR3 and PERF_METRICS MSRs in sched-in process,
KVM needs to capture the MSR writing trap and set the MSR values of guest
into corresponding perf events just like function perf_event_period()
does.
Initially we tried to reuse the function perf_event_period() to set the
slots/metrics value, but we found it was quite hard. The function
perf_event_period() only works on sampling events but unfortunately
slots event and metric events in topdown mode are all non-sampling
events. There are sampling event check and lots of sampling period
related check and setting in the function perf_event_period()
call-chain. If we want to reuse the function perf_event_period(), we
have to add lots of if-else changes on the entire function-chain and
even modify the function name. This would totally mess up the function
perf_event_period().
Thus, we select to create a new function perf_event_topdown_metrics() to
set the slots/metrics values. This makes logic and code both be clearer.
Signed-off-by: Dapeng Mi <[email protected]>
---
include/linux/perf_event.h | 13 ++++++++
kernel/events/core.c | 62 ++++++++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index e95152531f4c..fe12a2ea10d9 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1661,6 +1661,11 @@ perf_event_addr_filters(struct perf_event *event)
return ifh;
}
+struct td_metrics {
+ u64 slots;
+ u64 metric;
+};
+
extern void perf_event_addr_filters_sync(struct perf_event *event);
extern void perf_report_aux_output_id(struct perf_event *event, u64 hw_id);
@@ -1695,6 +1700,8 @@ extern void perf_event_task_tick(void);
extern int perf_event_account_interrupt(struct perf_event *event);
extern int perf_event_period(struct perf_event *event, u64 value);
extern u64 perf_event_pause(struct perf_event *event, bool reset);
+extern int perf_event_topdown_metrics(struct perf_event *event,
+ struct td_metrics *value);
#else /* !CONFIG_PERF_EVENTS: */
static inline void *
perf_aux_output_begin(struct perf_output_handle *handle,
@@ -1781,6 +1788,12 @@ static inline u64 perf_event_pause(struct perf_event *event, bool reset)
{
return 0;
}
+
+static inline int perf_event_topdown_metrics(struct perf_event *event,
+ struct td_metrics *value)
+{
+ return 0;
+}
#endif
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1877171e9590..6fa86e8bfb89 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5776,6 +5776,68 @@ int perf_event_period(struct perf_event *event, u64 value)
}
EXPORT_SYMBOL_GPL(perf_event_period);
+static void __perf_event_topdown_metrics(struct perf_event *event,
+ struct perf_cpu_context *cpuctx,
+ struct perf_event_context *ctx,
+ void *info)
+{
+ struct td_metrics *td_metrics = (struct td_metrics *)info;
+ bool active;
+
+ active = (event->state == PERF_EVENT_STATE_ACTIVE);
+ if (active) {
+ perf_pmu_disable(event->pmu);
+ /*
+ * We could be throttled; unthrottle now to avoid the tick
+ * trying to unthrottle while we already re-started the event.
+ */
+ if (event->hw.interrupts == MAX_INTERRUPTS) {
+ event->hw.interrupts = 0;
+ perf_log_throttle(event, 1);
+ }
+ event->pmu->stop(event, PERF_EF_UPDATE);
+ }
+
+ event->hw.saved_slots = td_metrics->slots;
+ event->hw.saved_metric = td_metrics->metric;
+
+ if (active) {
+ event->pmu->start(event, PERF_EF_RELOAD);
+ perf_pmu_enable(event->pmu);
+ }
+}
+
+static int _perf_event_topdown_metrics(struct perf_event *event,
+ struct td_metrics *value)
+{
+ /*
+ * Slots event in topdown metrics scenario
+ * must be non-sampling event.
+ */
+ if (is_sampling_event(event))
+ return -EINVAL;
+
+ if (!value)
+ return -EINVAL;
+
+ event_function_call(event, __perf_event_topdown_metrics, value);
+
+ return 0;
+}
+
+int perf_event_topdown_metrics(struct perf_event *event, struct td_metrics *value)
+{
+ struct perf_event_context *ctx;
+ int ret;
+
+ ctx = perf_event_ctx_lock(event);
+ ret = _perf_event_topdown_metrics(event, value);
+ perf_event_ctx_unlock(event, ctx);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(perf_event_topdown_metrics);
+
static const struct file_operations perf_fops;
static inline int perf_fget_light(int fd, struct fd *p)
--
2.34.1
Hi Dapeng,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20230808]
[cannot apply to kvm/queue acme/perf/core tip/perf/core kvm/linux-next v6.5-rc5 v6.5-rc4 v6.5-rc3 linus/master v6.5-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dapeng-Mi/KVM-x86-pmu-Support-PMU-fixed-counter-3/20230809-030457
base: next-20230808
patch link: https://lore.kernel.org/r/20230808063111.1870070-9-dapeng1.mi%40linux.intel.com
patch subject: [PATCH RFV v2 08/13] perf/core: Add new function perf_event_topdown_metrics()
config: arm-randconfig-r046-20230808 (https://download.01.org/0day-ci/archive/20230809/[email protected]/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project.git f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce: (https://download.01.org/0day-ci/archive/20230809/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
In file included from kernel/sched/build_policy.c:34:
In file included from kernel/sched/sched.h:61:
In file included from include/linux/syscalls_api.h:1:
In file included from include/linux/syscalls.h:90:
In file included from include/trace/syscall.h:7:
In file included from include/linux/trace_events.h:10:
>> include/linux/perf_event.h:1793:18: warning: declaration of 'struct td_metrics' will not be visible outside of this function [-Wvisibility]
struct td_metrics *value)
^
1 warning generated.
--
In file included from kernel/sched/fair.c:56:
In file included from kernel/sched/sched.h:61:
In file included from include/linux/syscalls_api.h:1:
In file included from include/linux/syscalls.h:90:
In file included from include/trace/syscall.h:7:
In file included from include/linux/trace_events.h:10:
>> include/linux/perf_event.h:1793:18: warning: declaration of 'struct td_metrics' will not be visible outside of this function [-Wvisibility]
struct td_metrics *value)
^
kernel/sched/fair.c:702:6: warning: no previous prototype for function 'update_entity_lag' [-Wmissing-prototypes]
void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
^
kernel/sched/fair.c:702:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
^
static
kernel/sched/fair.c:12732:6: warning: no previous prototype for function 'free_fair_sched_group' [-Wmissing-prototypes]
void free_fair_sched_group(struct task_group *tg) { }
^
kernel/sched/fair.c:12732:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void free_fair_sched_group(struct task_group *tg) { }
^
static
kernel/sched/fair.c:12734:5: warning: no previous prototype for function 'alloc_fair_sched_group' [-Wmissing-prototypes]
int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
^
kernel/sched/fair.c:12734:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
^
static
kernel/sched/fair.c:12739:6: warning: no previous prototype for function 'online_fair_sched_group' [-Wmissing-prototypes]
void online_fair_sched_group(struct task_group *tg) { }
^
kernel/sched/fair.c:12739:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void online_fair_sched_group(struct task_group *tg) { }
^
static
kernel/sched/fair.c:12741:6: warning: no previous prototype for function 'unregister_fair_sched_group' [-Wmissing-prototypes]
void unregister_fair_sched_group(struct task_group *tg) { }
^
kernel/sched/fair.c:12741:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void unregister_fair_sched_group(struct task_group *tg) { }
^
static
kernel/sched/fair.c:503:20: warning: unused function 'list_del_leaf_cfs_rq' [-Wunused-function]
static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
^
kernel/sched/fair.c:524:19: warning: unused function 'tg_is_idle' [-Wunused-function]
static inline int tg_is_idle(struct task_group *tg)
^
kernel/sched/fair.c:548:19: warning: unused function 'max_vruntime' [-Wunused-function]
static inline u64 max_vruntime(u64 max_vruntime, u64 vruntime)
^
kernel/sched/fair.c:1262:20: warning: unused function 'is_core_idle' [-Wunused-function]
static inline bool is_core_idle(int cpu)
^
kernel/sched/fair.c:3452:20: warning: unused function 'account_numa_enqueue' [-Wunused-function]
static inline void account_numa_enqueue(struct rq *rq, struct task_struct *p)
^
kernel/sched/fair.c:3456:20: warning: unused function 'account_numa_dequeue' [-Wunused-function]
static inline void account_numa_dequeue(struct rq *rq, struct task_struct *p)
^
kernel/sched/fair.c:3460:20: warning: unused function 'update_scan_period' [-Wunused-function]
static inline void update_scan_period(struct task_struct *p, int new_cpu)
^
kernel/sched/fair.c:4872:20: warning: unused function 'cfs_rq_is_decayed' [-Wunused-function]
static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
^
kernel/sched/fair.c:4887:20: warning: unused function 'remove_entity_load_avg' [-Wunused-function]
static inline void remove_entity_load_avg(struct sched_entity *se) {}
^
kernel/sched/fair.c:6259:20: warning: unused function 'cfs_bandwidth_used' [-Wunused-function]
static inline bool cfs_bandwidth_used(void)
^
kernel/sched/fair.c:6267:20: warning: unused function 'sync_throttle' [-Wunused-function]
static inline void sync_throttle(struct task_group *tg, int cpu) {}
^
kernel/sched/fair.c:6280:19: warning: unused function 'throttled_lb_pair' [-Wunused-function]
static inline int throttled_lb_pair(struct task_group *tg,
^
kernel/sched/fair.c:6291:37: warning: unused function 'tg_cfs_bandwidth' [-Wunused-function]
static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
^
kernel/sched/fair.c:6295:20: warning: unused function 'destroy_cfs_bandwidth' [-Wunused-function]
static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
^
kernel/sched/fair.c:6296:20: warning: unused function 'update_runtime_enabled' [-Wunused-function]
static inline void update_runtime_enabled(struct rq *rq) {}
^
kernel/sched/fair.c:6297:20: warning: unused function 'unthrottle_offline_cfs_rqs' [-Wunused-function]
static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
^
22 warnings generated.
--
In file included from kernel/sched/core.c:13:
In file included from include/linux/syscalls_api.h:1:
In file included from include/linux/syscalls.h:90:
In file included from include/trace/syscall.h:7:
In file included from include/linux/trace_events.h:10:
>> include/linux/perf_event.h:1793:18: warning: declaration of 'struct td_metrics' will not be visible outside of this function [-Wvisibility]
struct td_metrics *value)
^
kernel/sched/core.c:3695:20: warning: unused function 'rq_has_pinned_tasks' [-Wunused-function]
static inline bool rq_has_pinned_tasks(struct rq *rq)
^
kernel/sched/core.c:5822:20: warning: unused function 'sched_tick_start' [-Wunused-function]
static inline void sched_tick_start(int cpu) { }
^
kernel/sched/core.c:5823:20: warning: unused function 'sched_tick_stop' [-Wunused-function]
static inline void sched_tick_stop(int cpu) { }
^
kernel/sched/core.c:6523:20: warning: unused function 'sched_core_cpu_starting' [-Wunused-function]
static inline void sched_core_cpu_starting(unsigned int cpu) {}
^
kernel/sched/core.c:6524:20: warning: unused function 'sched_core_cpu_deactivate' [-Wunused-function]
static inline void sched_core_cpu_deactivate(unsigned int cpu) {}
^
kernel/sched/core.c:6525:20: warning: unused function 'sched_core_cpu_dying' [-Wunused-function]
static inline void sched_core_cpu_dying(unsigned int cpu) {}
^
7 warnings generated.
vim +1793 include/linux/perf_event.h
1791
1792 static inline int perf_event_topdown_metrics(struct perf_event *event,
> 1793 struct td_metrics *value)
1794 {
1795 return 0;
1796 }
1797 #endif
1798
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Dapeng,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20230808]
[cannot apply to kvm/queue acme/perf/core tip/perf/core kvm/linux-next v6.5-rc5 v6.5-rc4 v6.5-rc3 linus/master v6.5-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dapeng-Mi/KVM-x86-pmu-Support-PMU-fixed-counter-3/20230809-030457
base: next-20230808
patch link: https://lore.kernel.org/r/20230808063111.1870070-9-dapeng1.mi%40linux.intel.com
patch subject: [PATCH RFV v2 08/13] perf/core: Add new function perf_event_topdown_metrics()
config: loongarch-allnoconfig (https://download.01.org/0day-ci/archive/20230809/[email protected]/config)
compiler: loongarch64-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230809/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
In file included from include/linux/trace_events.h:10,
from include/trace/syscall.h:7,
from include/linux/syscalls.h:90,
from arch/loongarch/mm/cache.c:17:
>> include/linux/perf_event.h:1793:53: warning: 'struct td_metrics' declared inside parameter list will not be visible outside of this definition or declaration
1793 | struct td_metrics *value)
| ^~~~~~~~~~
--
In file included from include/linux/trace_events.h:10,
from include/trace/syscall.h:7,
from include/linux/syscalls.h:90,
from include/linux/entry-common.h:7,
from arch/loongarch/mm/fault.c:13:
>> include/linux/perf_event.h:1793:53: warning: 'struct td_metrics' declared inside parameter list will not be visible outside of this definition or declaration
1793 | struct td_metrics *value)
| ^~~~~~~~~~
arch/loongarch/mm/fault.c:256:27: warning: no previous prototype for 'do_page_fault' [-Wmissing-prototypes]
256 | asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
| ^~~~~~~~~~~~~
vim +1793 include/linux/perf_event.h
1791
1792 static inline int perf_event_topdown_metrics(struct perf_event *event,
> 1793 struct td_metrics *value)
1794 {
1795 return 0;
1796 }
1797 #endif
1798
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki