/*
- * perfmon.h - performance monitor
- *
- * Copyright (c) 2018 Cisco Systems and/or its affiliates
+ * Copyright (c) 2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef __included_perfmon_h__
-#define __included_perfmon_h__
-
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vlib/log.h>
-#include <vppinfra/hash.h>
-#include <vppinfra/error.h>
+#ifndef __perfmon_perfmon_h
+#define __perfmon_perfmon_h
#include <linux/perf_event.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+#include <vppinfra/cpu.h>
+#include <vlib/vlib.h>
-#define foreach_perfmon_event \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, "cpu-cycles") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, "instructions") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, \
- "cache-references") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "cache-misses") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branches") \
- _(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES, "bus-cycles") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, \
- "stall-frontend") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND, \
- "stall-backend") \
-_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES, "ref-cpu-cycles") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS, "page-faults") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES, "context-switches") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS, "cpu-migrations") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN, "minor-pagefaults") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ, "major-pagefaults") \
-_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS, "emulation-faults")
-
-typedef struct
-{
- char *name;
- int pe_type;
- int pe_config;
-} perfmon_event_config_t;
+#define PERF_MAX_EVENTS 7 /* 3 fixed and 4 programmable */
typedef enum
{
- PERFMON_STATE_OFF = 0,
- PERFMON_STATE_RUNNING,
-} perfmon_state_t;
+ PERFMON_BUNDLE_TYPE_UNKNOWN,
+ PERFMON_BUNDLE_TYPE_NODE,
+ PERFMON_BUNDLE_TYPE_THREAD,
+ PERFMON_BUNDLE_TYPE_SYSTEM,
+} perfmon_bundle_type_t;
-typedef struct
+typedef enum
{
- u8 *thread_and_node_name;
- u8 **counter_names;
- u64 *counter_values;
- u64 *vectors_this_counter;
-} perfmon_capture_t;
+ PERFMON_OFFSET_TYPE_MMAP,
+ PERFMON_OFFSET_TYPE_METRICS,
+ PERFMON_OFFSET_TYPE_MAX,
+} perfmon_offset_type_t;
typedef struct
{
- u32 cpuid;
- const char **table;
-} perfmon_cpuid_and_table_t;
+ u32 type_from_instance : 1;
+ u32 exclude_kernel : 1;
+ union
+ {
+ u32 type;
+ u32 instance_type;
+ };
+ u64 config;
+ char *name;
+ char *description;
+} perfmon_event_t;
typedef struct
{
- u8 *name;
- u8 *value;
-} name_value_pair_t;
+ u32 type;
+ int cpu;
+ pid_t pid;
+ char *name;
+} perfmon_instance_t;
typedef struct
{
- /* API message ID base */
- u16 msg_id_base;
-
- /* on/off switch for the periodic function */
- volatile u8 state;
-
- /* capture pool, hash table */
- perfmon_capture_t *capture_pool;
- uword *capture_by_thread_and_node_name;
+ char *name;
+ perfmon_instance_t *instances;
+} perfmon_instance_type_t;
- /* CPU-specific event tables, hash table of selected table (if any) */
- perfmon_cpuid_and_table_t *perfmon_tables;
- uword *perfmon_table;
+struct perfmon_source;
+vlib_node_function_t perfmon_dispatch_wrapper_mmap;
+vlib_node_function_t perfmon_dispatch_wrapper_metrics;
- /* vector of single events to collect */
- perfmon_event_config_t *single_events_to_collect;
+#define foreach_permon_offset_type \
+ _ (PERFMON_OFFSET_TYPE_MMAP, perfmon_dispatch_wrapper_mmap) \
+ _ (PERFMON_OFFSET_TYPE_METRICS, perfmon_dispatch_wrapper_metrics)
- /* vector of paired events to collect */
- perfmon_event_config_t *paired_events_to_collect;
+typedef clib_error_t *(perfmon_source_init_fn_t) (vlib_main_t *vm,
+ struct perfmon_source *);
+typedef struct perfmon_source
+{
+ char *name;
+ char *description;
+ struct perfmon_source *next;
+ perfmon_event_t *events;
+ u32 n_events;
+ perfmon_instance_type_t *instances_by_type;
+ format_function_t *format_config;
+ perfmon_source_init_fn_t *init_fn;
+} perfmon_source_t;
- /* Base indices of synthetic event tuples */
- u32 ipc_event_index;
- u32 mispredict_event_index;
+struct perfmon_bundle;
- /* Length of time to capture a single event */
- f64 timeout_interval;
+typedef clib_error_t *(perfmon_bundle_init_fn_t) (vlib_main_t *vm,
+ struct perfmon_bundle *);
- /* Current event (index) being collected */
- u32 current_event;
- int n_active;
- u32 **rdpmc_indices;
- /* mmap base / size of (mapped) struct perf_event_mmap_page */
- u8 ***perf_event_pages;
- u32 page_size;
+typedef struct perfmon_bundle
+{
+ char *name;
+ char *description;
+ char *source;
+ char *footer;
+ perfmon_bundle_type_t type;
+ perfmon_offset_type_t offset_type;
+ u32 events[PERF_MAX_EVENTS];
+ u32 metrics[PERF_MAX_EVENTS];
+ u32 n_events;
+
+ perfmon_bundle_init_fn_t *init_fn;
+
+ char **column_headers;
+ char **raw_column_headers;
+ format_function_t *format_fn;
+ clib_cpu_supports_func_t cpu_supports;
+
+ /* do not set manually */
+ perfmon_source_t *src;
+ struct perfmon_bundle *next;
+} perfmon_bundle_t;
- /* Current perf_event file descriptors, per thread */
- int **pm_fds;
+typedef struct
+{
+ u64 nr;
+ u64 time_enabled;
+ u64 time_running;
+ u64 value[PERF_MAX_EVENTS];
+} perfmon_reading_t;
- /* thread bitmap */
- uword *thread_bitmap;
+typedef struct
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ u64 n_calls;
+ u64 n_packets;
+ union
+ {
+ struct
+ {
+ u64 value[PERF_MAX_EVENTS];
+ } t[2];
+ u64 value[PERF_MAX_EVENTS * 2];
+ };
+} perfmon_node_stats_t;
- /* Logging */
- vlib_log_class_t log_class;
+typedef struct
+{
+ u8 n_events;
+ u16 n_nodes;
+ perfmon_node_stats_t *node_stats;
+ perfmon_bundle_t *bundle;
+ struct perf_event_mmap_page *mmap_pages[PERF_MAX_EVENTS];
+} perfmon_thread_runtime_t;
- /* convenience */
- vlib_main_t *vlib_main;
- vnet_main_t *vnet_main;
- ethernet_main_t *ethernet_main;
+typedef struct
+{
+ perfmon_thread_runtime_t *thread_runtimes;
+ perfmon_bundle_t *bundles;
+ uword *bundle_by_name;
+ perfmon_source_t *sources;
+ uword *source_by_name;
+ perfmon_bundle_t *active_bundle;
+ int is_running;
+ f64 sample_time;
+ int *group_fds;
+ int *fds_to_close;
+ perfmon_instance_type_t *default_instance_type;
+ perfmon_instance_type_t *active_instance_type;
} perfmon_main_t;
extern perfmon_main_t perfmon_main;
-extern vlib_node_registration_t perfmon_periodic_node;
-uword *perfmon_parse_table (perfmon_main_t * pm, char *path, char *filename);
-
-/* Periodic function events */
-#define PERFMON_START 1
-
-#endif /* __included_perfmon_h__ */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
+#define PERFMON_REGISTER_SOURCE(x) \
+ perfmon_source_t __perfmon_source_##x; \
+ static void __clib_constructor __perfmon_source_registration_##x (void) \
+ { \
+ perfmon_main_t *pm = &perfmon_main; \
+ __perfmon_source_##x.next = pm->sources; \
+ pm->sources = &__perfmon_source_##x; \
+ } \
+ perfmon_source_t __perfmon_source_##x
+
+#define PERFMON_REGISTER_BUNDLE(x) \
+ perfmon_bundle_t __perfmon_bundle_##x; \
+ static void __clib_constructor __perfmon_bundle_registration_##x (void) \
+ { \
+ perfmon_main_t *pm = &perfmon_main; \
+ __perfmon_bundle_##x.next = pm->bundles; \
+ pm->bundles = &__perfmon_bundle_##x; \
+ } \
+ perfmon_bundle_t __perfmon_bundle_##x
+
+void perfmon_reset (vlib_main_t *vm);
+clib_error_t *perfmon_start (vlib_main_t *vm, perfmon_bundle_t *);
+clib_error_t *perfmon_stop (vlib_main_t *vm);
+
+#define PERFMON_STRINGS(...) \
+ (char *[]) { __VA_ARGS__, 0 }
+
+#endif