perfmon: new perfmon plugin
[vpp.git] / src / plugins / perfmon / intel / uncore.c
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 #include <vnet/vnet.h>
17 #include <vppinfra/linux/sysfs.h>
18 #include <perfmon/perfmon.h>
19 #include <perfmon/intel/core.h>
20 #include <perfmon/intel/uncore.h>
21
22 VLIB_REGISTER_LOG_CLASS (if_intel_uncore_log, static) = {
23   .class_name = "perfmon",
24   .subclass_name = "intel-uncore",
25 };
26
27 #define log_debug(fmt, ...)                                                   \
28   vlib_log_debug (if_intel_uncore_log.class, fmt, __VA_ARGS__)
29 #define log_warn(fmt, ...)                                                    \
30   vlib_log_warn (if_intel_uncore_log.class, fmt, __VA_ARGS__)
31 #define log_err(fmt, ...)                                                     \
32   vlib_log_err (if_intel_uncore_log.class, fmt, __VA_ARGS__)
33
34 #define PERF_INTEL_CODE(event, umask, edge, any, inv, cmask)                  \
35   ((event) | (umask) << 8 | (edge) << 18 | (any) << 21 | (inv) << 23 |        \
36    (cmask) << 24)
37
38 static perfmon_event_t intel_uncore_events[] = {
39 #define _(unit, event, umask, n, suffix, desc)                                \
40   [INTEL_UNCORE_E_##unit##_##n##_##suffix] = {                                \
41     .config = (event) | (umask) << 8,                                         \
42     .name = #n "." #suffix,                                                   \
43     .description = desc,                                                      \
44     .type_from_instance = 1,                                                  \
45     .instance_type = INTEL_UNCORE_UNIT_##unit,                                \
46   },
47
48   foreach_intel_uncore_event
49 #undef _
50 };
51
52 static int
53 intel_uncore_instance_name_cmp (void *v1, void *v2)
54 {
55   perfmon_instance_t *i1 = v1;
56   perfmon_instance_t *i2 = v2;
57   return strcmp (i1->name, i2->name);
58 }
59
60 static void
61 intel_uncore_add_unit (perfmon_source_t *src, intel_uncore_unit_type_t u,
62                        char *name, char *type_str, char *fmt,
63                        int *socket_by_cpu_id)
64 {
65   static char *base_path = "/sys/bus/event_source/devices/uncore";
66   clib_error_t *err;
67   clib_bitmap_t *cpumask = 0;
68   perfmon_instance_t *in;
69   perfmon_instance_type_t *it;
70   u8 *s = 0;
71   int i = 0, j;
72   u32 perf_type;
73
74   vec_validate (src->instances_by_type, u);
75   it = vec_elt_at_index (src->instances_by_type, u);
76   it->name = type_str;
77
78   while (1)
79     {
80       s = format (s, "%s_%s_%u/type%c", base_path, name, i, 0);
81       if ((err = clib_sysfs_read ((char *) s, "%u", &perf_type)))
82         break;
83       vec_reset_length (s);
84
85       s = format (s, "%s_%s_%u/cpumask%c", base_path, name, i, 0);
86       if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
87                                   &cpumask)))
88         break;
89       vec_reset_length (s);
90
91       clib_bitmap_foreach (j, cpumask)
92         {
93           vec_add2 (it->instances, in, 1);
94           in->type = perf_type;
95           in->cpu = j;
96           in->pid = -1;
97           in->name = (char *) format (0, fmt, socket_by_cpu_id[j], i);
98           vec_terminate_c_string (in->name);
99           log_debug ("found %s %s", type_str, in->name);
100         }
101       i++;
102     };
103   clib_error_free (err);
104   clib_bitmap_free (cpumask);
105   vec_free (s);
106 }
107
108 static clib_error_t *
109 intel_uncore_init (vlib_main_t *vm, perfmon_source_t *src)
110 {
111   clib_error_t *err = 0;
112   clib_bitmap_t *node_bitmap = 0, *cpumask = 0;
113   int *numa_by_cpu_id = 0;
114   u32 i, j;
115   u8 *s = 0;
116
117   if ((err = clib_sysfs_read ("/sys/devices/system/node/has_cpu", "%U",
118                               unformat_bitmap_list, &node_bitmap)))
119     {
120       clib_error_free (err);
121       return clib_error_return (0, "failed to discover numa topology");
122     }
123
124   clib_bitmap_foreach (i, node_bitmap)
125     {
126       s = format (s, "/sys/devices/system/node/node%u/cpulist%c", i, 0);
127       if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
128                                   &cpumask)))
129         {
130           clib_error_free (err);
131           err = clib_error_return (0, "failed to discover numa topology");
132           goto done;
133         }
134
135       clib_bitmap_foreach (j, cpumask)
136         {
137           vec_validate_init_empty (numa_by_cpu_id, j, -1);
138           numa_by_cpu_id[j] = i;
139         }
140       clib_bitmap_free (cpumask);
141       vec_reset_length (s);
142     }
143
144 #define _(t, n, name, fmt)                                                    \
145   intel_uncore_add_unit (src, INTEL_UNCORE_UNIT_##t, n, name, fmt,            \
146                          numa_by_cpu_id);
147   foreach_intel_uncore_unit_type;
148 #undef _
149
150   for (i = 0, j = 0; i < vec_len (src->instances_by_type); i++)
151     {
152       perfmon_instance_type_t *it;
153
154       it = vec_elt_at_index (src->instances_by_type, i);
155       vec_sort_with_function (it->instances, intel_uncore_instance_name_cmp);
156       j += vec_len (it->instances);
157     }
158
159   if (j == 0)
160     {
161       vec_free (src->instances_by_type);
162       return clib_error_return (0, "no uncore units found");
163     }
164
165 done:
166   vec_free (s);
167   vec_free (cpumask);
168   vec_free (node_bitmap);
169   vec_free (numa_by_cpu_id);
170   return err;
171 }
172
173 format_function_t format_intel_core_config;
174
175 PERFMON_REGISTER_SOURCE (intel_uncore) = {
176   .name = "intel-uncore",
177   .description = "intel uncore events",
178   .events = intel_uncore_events,
179   .n_events = INTEL_UNCORE_N_EVENTS,
180   .init_fn = intel_uncore_init,
181   .format_config = format_intel_core_config,
182 };