Line data Source code
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 559 : 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 35217 : intel_uncore_instance_name_cmp (void *v1, void *v2)
61 : {
62 35217 : perfmon_instance_t *i1 = v1;
63 35217 : perfmon_instance_t *i2 = v2;
64 35217 : return strcmp (i1->name, i2->name);
65 : }
66 :
67 : static u8 *
68 16770 : format_instance_name (intel_uncore_unit_type_t u, char *unit_fmt, u8 socket_id,
69 : u8 ubox)
70 : {
71 16770 : u8 *s = 0;
72 :
73 : /* uncore ubox may have specific names */
74 26832 : for (u8 i = 0; i < ARRAY_LEN (uncore_unit_names); i++)
75 : {
76 16770 : intel_uncore_unit_type_names_t *n = &uncore_unit_names[i];
77 :
78 16770 : if (n->unit_type == u)
79 : {
80 6708 : u8 *fmt = 0;
81 :
82 6708 : fmt = format (0, "%s (%s)%c", unit_fmt, (n->unit_names[ubox]), 0);
83 6708 : s = format (0, (char *) fmt, socket_id, ubox);
84 6708 : vec_free (fmt);
85 :
86 6708 : return s;
87 : }
88 : }
89 :
90 10062 : return format (0, unit_fmt, socket_id, ubox);
91 : }
92 :
93 : static void
94 1677 : 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 1677 : clib_bitmap_t *cpumask = 0;
101 : perfmon_instance_t *in;
102 : perfmon_instance_type_t *it;
103 1677 : u8 *s = 0;
104 1677 : int i = 0, j;
105 : u32 perf_type;
106 :
107 1677 : vec_validate (src->instances_by_type, u);
108 1677 : it = vec_elt_at_index (src->instances_by_type, u);
109 1677 : it->name = type_str;
110 :
111 : while (1)
112 : {
113 10062 : s = format (s, "%s_%s_%u/type%c", base_path, name, i, 0);
114 10062 : if ((err = clib_sysfs_read ((char *) s, "%u", &perf_type)))
115 1677 : break;
116 8385 : vec_reset_length (s);
117 :
118 8385 : s = format (s, "%s_%s_%u/cpumask%c", base_path, name, i, 0);
119 8385 : if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
120 : &cpumask)))
121 0 : break;
122 8385 : vec_reset_length (s);
123 :
124 25155 : clib_bitmap_foreach (j, cpumask)
125 : {
126 16770 : vec_add2 (it->instances, in, 1);
127 16770 : in->type = perf_type;
128 16770 : in->cpu = j;
129 16770 : in->pid = -1;
130 33540 : in->name =
131 16770 : (char *) format_instance_name (u, fmt, socket_by_cpu_id[j], i);
132 16770 : vec_terminate_c_string (in->name);
133 16770 : log_debug ("found %s %s", type_str, in->name);
134 : }
135 8385 : i++;
136 : };
137 1677 : clib_error_free (err);
138 1677 : clib_bitmap_free (cpumask);
139 1677 : vec_free (s);
140 1677 : }
141 :
142 : static clib_error_t *
143 559 : intel_uncore_init (vlib_main_t *vm, perfmon_source_t *src)
144 : {
145 559 : clib_error_t *err = 0;
146 559 : clib_bitmap_t *node_bitmap = 0, *cpumask = 0;
147 559 : int *numa_by_cpu_id = 0;
148 : u32 i, j;
149 559 : u8 *s = 0;
150 :
151 559 : if ((err = clib_sysfs_read ("/sys/devices/system/node/online", "%U",
152 : unformat_bitmap_list, &node_bitmap)))
153 : {
154 0 : clib_error_free (err);
155 0 : return clib_error_return (0, "failed to discover numa topology");
156 : }
157 :
158 1677 : clib_bitmap_foreach (i, node_bitmap)
159 : {
160 1118 : s = format (s, "/sys/devices/system/node/node%u/cpulist%c", i, 0);
161 1118 : if ((err = clib_sysfs_read ((char *) s, "%U", unformat_bitmap_list,
162 : &cpumask)))
163 : {
164 0 : clib_error_free (err);
165 0 : err = clib_error_return (0, "failed to discover numa topology");
166 0 : goto done;
167 : }
168 :
169 1118 : if (!cpumask)
170 : {
171 0 : clib_error_free (err);
172 0 : err = clib_error_return (
173 : 0, "while discovering numa topology: cpumask unexpectedly NULL");
174 0 : goto done;
175 : }
176 :
177 63726 : clib_bitmap_foreach (j, cpumask)
178 : {
179 125216 : vec_validate_init_empty (numa_by_cpu_id, j, -1);
180 62608 : numa_by_cpu_id[j] = i;
181 : }
182 1118 : clib_bitmap_free (cpumask);
183 1118 : 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 559 : foreach_intel_uncore_unit_type;
190 : #undef _
191 :
192 2236 : for (i = 0, j = 0; i < vec_len (src->instances_by_type); i++)
193 : {
194 : perfmon_instance_type_t *it;
195 :
196 1677 : it = vec_elt_at_index (src->instances_by_type, i);
197 1677 : vec_sort_with_function (it->instances, intel_uncore_instance_name_cmp);
198 1677 : j += vec_len (it->instances);
199 : }
200 :
201 559 : if (j == 0)
202 : {
203 0 : vec_free (src->instances_by_type);
204 0 : return clib_error_return (0, "no uncore units found");
205 : }
206 :
207 559 : done:
208 559 : vec_free (s);
209 559 : vec_free (cpumask);
210 559 : vec_free (node_bitmap);
211 559 : vec_free (numa_by_cpu_id);
212 559 : return err;
213 : }
214 :
215 : format_function_t format_intel_core_config;
216 :
217 559 : 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 : };
|