perfmon: refactor perf metric support
[vpp.git] / src / plugins / perfmon / perfmon.h
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef __perfmon_perfmon_h
17 #define __perfmon_perfmon_h
18
19 #include <linux/perf_event.h>
20 #include <vppinfra/clib.h>
21 #include <vppinfra/format.h>
22 #include <vppinfra/error.h>
23 #include <vppinfra/cpu.h>
24 #include <vlib/vlib.h>
25
26 #define PERF_MAX_EVENTS 12 /* 4 fixed and 8 programable on ICX */
27
28 typedef enum
29 {
30   PERFMON_BUNDLE_TYPE_UNKNOWN,
31   PERFMON_BUNDLE_TYPE_NODE,
32   PERFMON_BUNDLE_TYPE_THREAD,
33   PERFMON_BUNDLE_TYPE_SYSTEM,
34   PERFMON_BUNDLE_TYPE_MAX,
35   PERFMON_BUNDLE_TYPE_NODE_OR_THREAD,
36 } perfmon_bundle_type_t;
37
38 #define foreach_perfmon_bundle_type                                           \
39   _ (PERFMON_BUNDLE_TYPE_UNKNOWN, "not supported")                            \
40   _ (PERFMON_BUNDLE_TYPE_NODE, "node")                                        \
41   _ (PERFMON_BUNDLE_TYPE_THREAD, "thread")                                    \
42   _ (PERFMON_BUNDLE_TYPE_SYSTEM, "system")
43
44 typedef enum
45 {
46 #define _(e, str) e##_FLAG = 1 << e,
47   foreach_perfmon_bundle_type
48 #undef _
49
50 } perfmon_bundle_type_flag_t;
51
52 typedef struct
53 {
54   u32 type_from_instance : 1;
55   u32 exclude_kernel : 1;
56   union
57   {
58     u32 type;
59     u32 instance_type;
60   };
61   u64 config;
62   char *name;
63   char *description;
64 } perfmon_event_t;
65
66 typedef struct
67 {
68   u32 type;
69   int cpu;
70   pid_t pid;
71   char *name;
72 } perfmon_instance_t;
73
74 typedef struct
75 {
76   char *name;
77   perfmon_instance_t *instances;
78 } perfmon_instance_type_t;
79
80 struct perfmon_source;
81 vlib_node_function_t perfmon_dispatch_wrapper;
82
83 typedef clib_error_t *(perfmon_source_init_fn_t) (vlib_main_t *vm,
84                                                   struct perfmon_source *);
85 typedef struct perfmon_source
86 {
87   char *name;
88   char *description;
89   struct perfmon_source *next;
90   perfmon_event_t *events;
91   u32 n_events;
92   perfmon_instance_type_t *instances_by_type;
93   format_function_t *format_config;
94   perfmon_source_init_fn_t *init_fn;
95 } perfmon_source_t;
96
97 struct perfmon_bundle;
98
99 typedef clib_error_t *(perfmon_bundle_init_fn_t) (vlib_main_t *vm,
100                                                   struct perfmon_bundle *);
101
102 typedef struct
103 {
104   clib_cpu_supports_func_t cpu_supports;
105   perfmon_bundle_type_t bundle_type;
106 } perfmon_cpu_supports_t;
107
108 typedef struct perfmon_bundle
109 {
110   char *name;
111   char *description;
112   char *source;
113   char *footer;
114
115   union
116   {
117     perfmon_bundle_type_flag_t type_flags;
118     perfmon_bundle_type_t type;
119   };
120   perfmon_bundle_type_t active_type;
121
122   u32 events[PERF_MAX_EVENTS];
123   u32 n_events;
124
125   u16 preserve_samples;
126
127   perfmon_cpu_supports_t *cpu_supports;
128   u32 n_cpu_supports;
129
130   perfmon_bundle_init_fn_t *init_fn;
131
132   char **column_headers;
133   format_function_t *format_fn;
134
135   /* do not set manually */
136   perfmon_source_t *src;
137   struct perfmon_bundle *next;
138 } perfmon_bundle_t;
139
140 typedef struct
141 {
142   u64 nr;
143   u64 time_enabled;
144   u64 time_running;
145   u64 value[PERF_MAX_EVENTS];
146 } perfmon_reading_t;
147
148 typedef struct
149 {
150   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
151   u64 n_calls;
152   u64 n_packets;
153   union
154   {
155     struct
156     {
157       u64 value[PERF_MAX_EVENTS];
158     } t[2];
159     u64 value[PERF_MAX_EVENTS * 2];
160   };
161 } perfmon_node_stats_t;
162
163 typedef struct
164 {
165   u8 n_events;
166   u16 n_nodes;
167   perfmon_node_stats_t *node_stats;
168   perfmon_bundle_t *bundle;
169   u32 indexes[PERF_MAX_EVENTS];
170   u16 preserve_samples;
171   struct perf_event_mmap_page *mmap_pages[PERF_MAX_EVENTS];
172 } perfmon_thread_runtime_t;
173
174 typedef struct
175 {
176   perfmon_thread_runtime_t *thread_runtimes;
177   perfmon_bundle_t *bundles;
178   uword *bundle_by_name;
179   perfmon_source_t *sources;
180   uword *source_by_name;
181   perfmon_bundle_t *active_bundle;
182   int is_running;
183   f64 sample_time;
184   int *group_fds;
185   int *fds_to_close;
186   perfmon_instance_type_t *default_instance_type;
187   perfmon_instance_type_t *active_instance_type;
188 } perfmon_main_t;
189
190 extern perfmon_main_t perfmon_main;
191
192 #define PERFMON_BUNDLE_TYPE_TO_FLAGS(type)                                    \
193   ({                                                                          \
194     uword rtype = 0;                                                          \
195     if (type == PERFMON_BUNDLE_TYPE_NODE_OR_THREAD)                           \
196       rtype =                                                                 \
197         1 << PERFMON_BUNDLE_TYPE_THREAD | 1 << PERFMON_BUNDLE_TYPE_NODE;      \
198     else                                                                      \
199       rtype = 1 << type;                                                      \
200     rtype;                                                                    \
201   })
202
203 always_inline uword
204 perfmon_cpu_update_bundle_type (perfmon_bundle_t *b)
205 {
206   perfmon_cpu_supports_t *supports = b->cpu_supports;
207   uword type = 0;
208
209   /* either supports or b->type should be set, but not both */
210   ASSERT (!!supports ^ !!b->type);
211
212   /* if nothing specific for this bundle, go with the defaults */
213   if (!supports)
214     type = PERFMON_BUNDLE_TYPE_TO_FLAGS (b->type);
215   else
216     {
217       /* more than one type may be supported by a given bundle */
218       for (int i = 0; i < b->n_cpu_supports; ++i)
219         if (supports[i].cpu_supports ())
220           type |= PERFMON_BUNDLE_TYPE_TO_FLAGS (supports[i].bundle_type);
221     }
222
223   return type;
224 }
225 #undef PERFMON_BUNDLE_TYPE_TO_FLAGS
226
227 #define PERFMON_REGISTER_SOURCE(x)                                            \
228   perfmon_source_t __perfmon_source_##x;                                      \
229   static void __clib_constructor __perfmon_source_registration_##x (void)     \
230   {                                                                           \
231     perfmon_main_t *pm = &perfmon_main;                                       \
232     __perfmon_source_##x.next = pm->sources;                                  \
233     pm->sources = &__perfmon_source_##x;                                      \
234   }                                                                           \
235   perfmon_source_t __perfmon_source_##x
236
237 #define PERFMON_REGISTER_BUNDLE(x)                                            \
238   perfmon_bundle_t __perfmon_bundle_##x;                                      \
239   static void __clib_constructor __perfmon_bundle_registration_##x (void)     \
240   {                                                                           \
241     perfmon_main_t *pm = &perfmon_main;                                       \
242     __perfmon_bundle_##x.next = pm->bundles;                                  \
243     __perfmon_bundle_##x.type_flags =                                         \
244       perfmon_cpu_update_bundle_type (&__perfmon_bundle_##x);                 \
245     pm->bundles = &__perfmon_bundle_##x;                                      \
246   }                                                                           \
247   perfmon_bundle_t __perfmon_bundle_##x
248
249 void perfmon_reset (vlib_main_t *vm);
250 clib_error_t *perfmon_start (vlib_main_t *vm, perfmon_bundle_t *);
251 clib_error_t *perfmon_stop (vlib_main_t *vm);
252
253 #define PERFMON_STRINGS(...)                                                  \
254   (char *[]) { __VA_ARGS__, 0 }
255
256 #endif