perfmon: enable perfmon plugin for Arm
[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 intel_uncore_unit_type_names_t uncore_unit_names[] = {
39   { INTEL_UNCORE_UNIT_IIO,
40     PERFMON_STRINGS ("PCIe0", "PCIe1", "MCP", "PCIe2", "PCIe3", "CBDMA/DMI") }
41 };
42
43 static perfmon_event_t intel_uncore_events[] = {
44 #define _(unit, event, umask, ch_mask, fc_mask, n, suffix, desc)              \
45   [INTEL_UNCORE_E_##unit##_##n##_##suffix] = {                                \
46     .config =                                                                 \
47       (event) | (umask) << 8 | (u64) (ch_mask) << 36 | (u64) (fc_mask) << 48, \
48     .name = #n "." #suffix,                                                   \
49     .description = desc,                                                      \
50     .type_from_instance = 1,                                                  \
51     .instance_type = INTEL_UNCORE_UNIT_##unit,                                \
52     .implemented = 1,                                                         \
53   },
54
55   foreach_intel_uncore_event
56 #undef _
57 };
58
59 static int
60 intel_uncore_instance_name_cmp (void *v1, void *v2)
61 {
62   perfmon_instance_t *i1 = v1;
63   perfmon_instance_t *i2 = v2;
64   return strcmp (i1->name, i2->name);
65 }
66
67 static u8 *
68 format_instance_name (intel_uncore_unit_type_t u, char *unit_fmt, u8 socket_id,
69                       u8 ubox)
70 {
71   u8 *s = 0;
72
73   /* uncore ubox may have specific names */
74   for (u8 i = 0; i < ARRAY_LEN (uncore_unit_names); i++)
75     {
76       intel_uncore_unit_type_names_t *n = &uncore_unit_names[i];
77
78       if (n->unit_type == u)
79         {
80           u8 *fmt = 0;
81
82           fmt = format (0, "%s (%s)%c", unit_fmt, (n->unit_names[ubox]), 0);
83           s = format (0, (char *) fmt, socket_id, ubox);
84           vec_free (fmt);
85
86           return s;
87         }
88     }
89
90   return format (0, unit_fmt, socket_id, ubox);
91 }
92
93 static void
94 intel_uncore_add_unit (perfmon_source_t *src, intel_uncore_unit_type_t u,
95                        char *name, char *type_str, char *fmt,
96                        int *socket_by_cpu_id)
97 {
98   static char *base_path = "/sys/bus/event_source/devices/uncore";
99   clib_error_t *err;
100   clib_bitmap_t *cpumask = 0;
101   perfmon_instance_t *in;
102   perfmon_instance_type_t *it;
103   u8 *s = 0;
104   int i = 0, j;
105   u32 perf_type;
106
107   vec_validate (src->instances_by_type, u);
108   it = vec_elt_at_index (src->instances_by_type, u);
109   it->name = type_str;
110
111   while (1)
112     {
113       s = format (s, "%s_%s_%u/type%c", base_path, name, i, 0);
114       if ((err = clib_sysfs_read ((char *) s, "%u", &perf_type)))
115         break;
116       vec_reset_length (s);
117
118       s = format (s, "%s_%s_%u/cpumask%c", base_path, name, i, 0);
119       if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
120                                   &cpumask)))
121         break;
122       vec_reset_length (s);
123
124       clib_bitmap_foreach (j, cpumask)
125         {
126           vec_add2 (it->instances, in, 1);
127           in->type = perf_type;
128           in->cpu = j;
129           in->pid = -1;
130           in->name =
131             (char *) format_instance_name (u, fmt, socket_by_cpu_id[j], i);
132           vec_terminate_c_string (in->name);
133           log_debug ("found %s %s", type_str, in->name);
134         }
135       i++;
136     };
137   clib_error_free (err);
138   clib_bitmap_free (cpumask);
139   vec_free (s);
140 }
141
142 static clib_error_t *
143 intel_uncore_init (vlib_main_t *vm, perfmon_source_t *src)
144 {
145   clib_error_t *err = 0;
146   clib_bitmap_t *node_bitmap = 0, *cpumask = 0;
147   int *numa_by_cpu_id = 0;
148   u32 i, j;
149   u8 *s = 0;
150
151   if ((err = clib_sysfs_read ("/sys/devices/system/node/online", "%U",
152                               unformat_bitmap_list, &node_bitmap)))
153     {
154       clib_error_free (err);
155       return clib_error_return (0, "failed to discover numa topology");
156     }
157
158   clib_bitmap_foreach (i, node_bitmap)
159     {
160       s = format (s, "/sys/devices/system/node/node%u/cpulist%c", i, 0);
161       if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
162                                   &cpumask)))
163         {
164           clib_error_free (err);
165           err = clib_error_return (0, "failed to discover numa topology");
166           goto done;
167         }
168
169       if (!cpumask)
170         {
171           clib_error_free (err);
172           err = clib_error_return (
173             0, "while discovering numa topology: cpumask unexpectedly NULL");
174           goto done;
175         }
176
177       clib_bitmap_foreach (j, cpumask)
178         {
179           vec_validate_init_empty (numa_by_cpu_id, j, -1);
180           numa_by_cpu_id[j] = i;
181         }
182       clib_bitmap_free (cpumask);
183       vec_reset_length (s);
184     }
185
186 #define _(t, n, name, fmt)                                                    \
187   intel_uncore_add_unit (src, INTEL_UNCORE_UNIT_##t, n, name, fmt,            \
188                          numa_by_cpu_id);
189   foreach_intel_uncore_unit_type;
190 #undef _
191
192   for (i = 0, j = 0; i < vec_len (src->instances_by_type); i++)
193     {
194       perfmon_instance_type_t *it;
195
196       it = vec_elt_at_index (src->instances_by_type, i);
197       vec_sort_with_function (it->instances, intel_uncore_instance_name_cmp);
198       j += vec_len (it->instances);
199     }
200
201   if (j == 0)
202     {
203       vec_free (src->instances_by_type);
204       return clib_error_return (0, "no uncore units found");
205     }
206
207 done:
208   vec_free (s);
209   vec_free (cpumask);
210   vec_free (node_bitmap);
211   vec_free (numa_by_cpu_id);
212   return err;
213 }
214
215 format_function_t format_intel_core_config;
216
217 PERFMON_REGISTER_SOURCE (intel_uncore) = {
218   .name = "intel-uncore",
219   .description = "intel uncore events",
220   .events = intel_uncore_events,
221   .n_events = INTEL_UNCORE_N_EVENTS,
222   .init_fn = intel_uncore_init,
223   .format_config = format_intel_core_config,
224   .bundle_support = intel_bundle_supported,
225 };