]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2016 Intel Corporation | |
7c673cae FG |
3 | */ |
4 | ||
5 | #include <getopt.h> | |
6 | #include <inttypes.h> | |
7 | #include <limits.h> | |
8 | #include <sched.h> | |
9 | #include <signal.h> | |
10 | #include <stdio.h> | |
11 | ||
12 | #include <rte_common.h> | |
13 | #include <rte_memcpy.h> | |
14 | ||
15 | #include <pqos.h> | |
16 | ||
17 | #include "cat.h" | |
18 | ||
19 | #define BITS_PER_HEX 4 | |
20 | #define PQOS_MAX_SOCKETS 8 | |
21 | #define PQOS_MAX_SOCKET_CORES 64 | |
22 | #define PQOS_MAX_CORES (PQOS_MAX_SOCKET_CORES * PQOS_MAX_SOCKETS) | |
23 | ||
24 | static const struct pqos_cap *m_cap; | |
25 | static const struct pqos_cpuinfo *m_cpu; | |
26 | static const struct pqos_capability *m_cap_l3ca; | |
9f95a23c | 27 | #if PQOS_VERSION <= 103 |
7c673cae | 28 | static unsigned m_sockets[PQOS_MAX_SOCKETS]; |
9f95a23c TL |
29 | #else |
30 | static unsigned int *m_sockets; | |
31 | #endif | |
7c673cae FG |
32 | static unsigned m_sock_count; |
33 | static struct cat_config m_config[PQOS_MAX_CORES]; | |
34 | static unsigned m_config_count; | |
35 | ||
36 | static unsigned | |
37 | bits_count(uint64_t bitmask) | |
38 | { | |
39 | unsigned count = 0; | |
40 | ||
41 | for (; bitmask != 0; count++) | |
42 | bitmask &= bitmask - 1; | |
43 | ||
44 | return count; | |
45 | } | |
46 | ||
47 | /* | |
48 | * Parse elem, the elem could be single number/range or '(' ')' group | |
49 | * 1) A single number elem, it's just a simple digit. e.g. 9 | |
50 | * 2) A single range elem, two digits with a '-' between. e.g. 2-6 | |
51 | * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6) | |
52 | * Within group elem, '-' used for a range separator; | |
53 | * ',' used for a single number. | |
54 | */ | |
55 | static int | |
56 | parse_set(const char *input, rte_cpuset_t *cpusetp) | |
57 | { | |
58 | unsigned idx; | |
59 | const char *str = input; | |
60 | char *end = NULL; | |
61 | unsigned min, max; | |
62 | const unsigned num = PQOS_MAX_CORES; | |
63 | ||
64 | CPU_ZERO(cpusetp); | |
65 | ||
66 | while (isblank(*str)) | |
67 | str++; | |
68 | ||
69 | /* only digit or left bracket is qualify for start point */ | |
70 | if ((!isdigit(*str) && *str != '(') || *str == '\0') | |
71 | return -1; | |
72 | ||
73 | /* process single number or single range of number */ | |
74 | if (*str != '(') { | |
75 | errno = 0; | |
76 | idx = strtoul(str, &end, 10); | |
77 | ||
78 | if (errno || end == NULL || idx >= num) | |
79 | return -1; | |
80 | ||
81 | while (isblank(*end)) | |
82 | end++; | |
83 | ||
84 | min = idx; | |
85 | max = idx; | |
86 | if (*end == '-') { | |
87 | /* process single <number>-<number> */ | |
88 | end++; | |
89 | while (isblank(*end)) | |
90 | end++; | |
91 | if (!isdigit(*end)) | |
92 | return -1; | |
93 | ||
94 | errno = 0; | |
95 | idx = strtoul(end, &end, 10); | |
96 | if (errno || end == NULL || idx >= num) | |
97 | return -1; | |
98 | max = idx; | |
99 | while (isblank(*end)) | |
100 | end++; | |
101 | if (*end != ',' && *end != '\0') | |
102 | return -1; | |
103 | } | |
104 | ||
105 | if (*end != ',' && *end != '\0' && *end != '@') | |
106 | return -1; | |
107 | ||
108 | for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max); | |
109 | idx++) | |
110 | CPU_SET(idx, cpusetp); | |
111 | ||
112 | return end - input; | |
113 | } | |
114 | ||
115 | /* process set within bracket */ | |
116 | str++; | |
117 | while (isblank(*str)) | |
118 | str++; | |
119 | if (*str == '\0') | |
120 | return -1; | |
121 | ||
122 | min = PQOS_MAX_CORES; | |
123 | do { | |
124 | ||
125 | /* go ahead to the first digit */ | |
126 | while (isblank(*str)) | |
127 | str++; | |
128 | if (!isdigit(*str)) | |
129 | return -1; | |
130 | ||
131 | /* get the digit value */ | |
132 | errno = 0; | |
133 | idx = strtoul(str, &end, 10); | |
134 | if (errno || end == NULL || idx >= num) | |
135 | return -1; | |
136 | ||
137 | /* go ahead to separator '-',',' and ')' */ | |
138 | while (isblank(*end)) | |
139 | end++; | |
140 | if (*end == '-') { | |
141 | if (min == PQOS_MAX_CORES) | |
142 | min = idx; | |
143 | else /* avoid continuous '-' */ | |
144 | return -1; | |
145 | } else if ((*end == ',') || (*end == ')')) { | |
146 | max = idx; | |
147 | if (min == PQOS_MAX_CORES) | |
148 | min = idx; | |
149 | for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max); | |
150 | idx++) | |
151 | CPU_SET(idx, cpusetp); | |
152 | ||
153 | min = PQOS_MAX_CORES; | |
154 | } else | |
155 | return -1; | |
156 | ||
157 | str = end + 1; | |
158 | } while (*end != '\0' && *end != ')'); | |
159 | ||
160 | return str - input; | |
161 | } | |
162 | ||
163 | /* Test if bitmask is contiguous */ | |
164 | static int | |
165 | is_contiguous(uint64_t bitmask) | |
166 | { | |
167 | /* check if bitmask is contiguous */ | |
168 | unsigned i = 0; | |
169 | unsigned j = 0; | |
170 | const unsigned max_idx = (sizeof(bitmask) * CHAR_BIT); | |
171 | ||
172 | if (bitmask == 0) | |
173 | return 0; | |
174 | ||
175 | for (i = 0; i < max_idx; i++) { | |
176 | if (((1ULL << i) & bitmask) != 0) | |
177 | j++; | |
178 | else if (j > 0) | |
179 | break; | |
180 | } | |
181 | ||
182 | if (bits_count(bitmask) != j) { | |
183 | printf("PQOS: mask 0x%llx is not contiguous.\n", | |
184 | (unsigned long long)bitmask); | |
185 | return 0; | |
186 | } | |
187 | ||
188 | return 1; | |
189 | } | |
190 | ||
191 | /* | |
192 | * The format pattern: --l3ca='<cbm@cpus>[,<(ccbm,dcbm)@cpus>...]' | |
193 | * cbm could be a single mask or for a CDP enabled system, a group of two masks | |
194 | * ("code cbm" and "data cbm") | |
195 | * '(' and ')' are necessary if it's a group. | |
196 | * cpus could be a single digit/range or a group. | |
197 | * '(' and ')' are necessary if it's a group. | |
198 | * | |
199 | * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7' | |
200 | * - CPUs 1 and 3 share its 4 ways with CPUs 4, 5 and 6; | |
201 | * - CPUs 4,5 and 6 share half (4 out of 8 ways) of its L3 with 1 and 3; | |
202 | * - CPUs 4,5 and 6 have exclusive access to 4 out of 8 ways; | |
203 | * - CPU 7 has exclusive access to all of its 4 ways; | |
204 | * | |
205 | * e.g. '(0x00C00,0x00300)@(1,3)' for a CDP enabled system | |
206 | * - cpus 1 and 3 have access to 2 ways for code and 2 ways for data, | |
207 | * code and data ways are not overlapping.; | |
208 | */ | |
209 | static int | |
210 | parse_l3ca(const char *l3ca) | |
211 | { | |
212 | unsigned idx = 0; | |
213 | const char *cbm_start = NULL; | |
214 | char *cbm_end = NULL; | |
215 | const char *end = NULL; | |
216 | int offset; | |
217 | rte_cpuset_t cpuset; | |
218 | uint64_t mask = 0; | |
219 | uint64_t cmask = 0; | |
220 | ||
221 | if (l3ca == NULL) | |
222 | goto err; | |
223 | ||
224 | /* Get cbm */ | |
225 | do { | |
226 | CPU_ZERO(&cpuset); | |
227 | mask = 0; | |
228 | cmask = 0; | |
229 | ||
230 | while (isblank(*l3ca)) | |
231 | l3ca++; | |
232 | ||
233 | if (*l3ca == '\0') | |
234 | goto err; | |
235 | ||
236 | /* record mask_set start point */ | |
237 | cbm_start = l3ca; | |
238 | ||
239 | /* go across a complete bracket */ | |
240 | if (*cbm_start == '(') { | |
241 | l3ca += strcspn(l3ca, ")"); | |
242 | if (*l3ca++ == '\0') | |
243 | goto err; | |
244 | } | |
245 | ||
246 | /* scan the separator '@', ','(next) or '\0'(finish) */ | |
247 | l3ca += strcspn(l3ca, "@,"); | |
248 | ||
9f95a23c TL |
249 | if (*l3ca != '@') |
250 | goto err; | |
7c673cae | 251 | |
9f95a23c TL |
252 | /* explicit assign cpu_set */ |
253 | offset = parse_set(l3ca + 1, &cpuset); | |
254 | if (offset < 0 || CPU_COUNT(&cpuset) == 0) | |
7c673cae FG |
255 | goto err; |
256 | ||
9f95a23c TL |
257 | end = l3ca + 1 + offset; |
258 | ||
7c673cae FG |
259 | if (*end != ',' && *end != '\0') |
260 | goto err; | |
261 | ||
262 | /* parse mask_set from start point */ | |
263 | if (*cbm_start == '(') { | |
264 | cbm_start++; | |
265 | ||
266 | while (isblank(*cbm_start)) | |
267 | cbm_start++; | |
268 | ||
269 | if (!isxdigit(*cbm_start)) | |
270 | goto err; | |
271 | ||
272 | errno = 0; | |
273 | cmask = strtoul(cbm_start, &cbm_end, 16); | |
274 | if (errno != 0 || cbm_end == NULL || cmask == 0) | |
275 | goto err; | |
276 | ||
277 | while (isblank(*cbm_end)) | |
278 | cbm_end++; | |
279 | ||
280 | if (*cbm_end != ',') | |
281 | goto err; | |
282 | ||
283 | cbm_end++; | |
284 | ||
285 | while (isblank(*cbm_end)) | |
286 | cbm_end++; | |
287 | ||
288 | if (!isxdigit(*cbm_end)) | |
289 | goto err; | |
290 | ||
291 | errno = 0; | |
292 | mask = strtoul(cbm_end, &cbm_end, 16); | |
293 | if (errno != 0 || cbm_end == NULL || mask == 0) | |
294 | goto err; | |
295 | } else { | |
296 | while (isblank(*cbm_start)) | |
297 | cbm_start++; | |
298 | ||
299 | if (!isxdigit(*cbm_start)) | |
300 | goto err; | |
301 | ||
302 | errno = 0; | |
303 | mask = strtoul(cbm_start, &cbm_end, 16); | |
304 | if (errno != 0 || cbm_end == NULL || mask == 0) | |
305 | goto err; | |
306 | ||
307 | } | |
308 | ||
309 | if (mask == 0 || is_contiguous(mask) == 0) | |
310 | goto err; | |
311 | ||
312 | if (cmask != 0 && is_contiguous(cmask) == 0) | |
313 | goto err; | |
314 | ||
315 | rte_memcpy(&m_config[idx].cpumask, | |
316 | &cpuset, sizeof(rte_cpuset_t)); | |
317 | ||
318 | if (cmask != 0) { | |
319 | m_config[idx].cdp = 1; | |
320 | m_config[idx].code_mask = cmask; | |
321 | m_config[idx].data_mask = mask; | |
322 | } else | |
323 | m_config[idx].mask = mask; | |
324 | ||
325 | m_config_count++; | |
326 | ||
327 | l3ca = end + 1; | |
328 | idx++; | |
329 | } while (*end != '\0' && idx < PQOS_MAX_CORES); | |
330 | ||
7c673cae FG |
331 | return 0; |
332 | ||
333 | err: | |
334 | return -EINVAL; | |
335 | } | |
336 | ||
337 | static int | |
338 | check_cpus_overlapping(void) | |
339 | { | |
340 | unsigned i = 0; | |
341 | unsigned j = 0; | |
342 | rte_cpuset_t mask; | |
343 | ||
344 | CPU_ZERO(&mask); | |
345 | ||
346 | for (i = 0; i < m_config_count; i++) { | |
347 | for (j = i + 1; j < m_config_count; j++) { | |
9f95a23c | 348 | RTE_CPU_AND(&mask, |
7c673cae FG |
349 | &m_config[i].cpumask, |
350 | &m_config[j].cpumask); | |
351 | ||
352 | if (CPU_COUNT(&mask) != 0) { | |
353 | printf("PQOS: Requested CPUs sets are " | |
354 | "overlapping.\n"); | |
355 | return -EINVAL; | |
356 | } | |
357 | } | |
358 | } | |
359 | ||
360 | return 0; | |
361 | } | |
362 | ||
363 | static int | |
364 | check_cpus(void) | |
365 | { | |
366 | unsigned i = 0; | |
367 | unsigned cpu_id = 0; | |
368 | unsigned cos_id = 0; | |
369 | int ret = 0; | |
370 | ||
371 | for (i = 0; i < m_config_count; i++) { | |
372 | for (cpu_id = 0; cpu_id < PQOS_MAX_CORES; cpu_id++) { | |
373 | if (CPU_ISSET(cpu_id, &m_config[i].cpumask) != 0) { | |
374 | ||
375 | ret = pqos_cpu_check_core(m_cpu, cpu_id); | |
376 | if (ret != PQOS_RETVAL_OK) { | |
377 | printf("PQOS: %u is not a valid " | |
378 | "logical core id.\n", cpu_id); | |
379 | ret = -ENODEV; | |
380 | goto exit; | |
381 | } | |
382 | ||
9f95a23c | 383 | #if PQOS_VERSION <= 103 |
7c673cae | 384 | ret = pqos_l3ca_assoc_get(cpu_id, &cos_id); |
9f95a23c TL |
385 | #else |
386 | ret = pqos_alloc_assoc_get(cpu_id, &cos_id); | |
387 | #endif | |
7c673cae FG |
388 | if (ret != PQOS_RETVAL_OK) { |
389 | printf("PQOS: Failed to read COS " | |
390 | "associated to cpu %u.\n", | |
391 | cpu_id); | |
392 | ret = -EFAULT; | |
393 | goto exit; | |
394 | } | |
395 | ||
396 | /* | |
397 | * Check if COS assigned to lcore is different | |
398 | * then default one (#0) | |
399 | */ | |
400 | if (cos_id != 0) { | |
401 | printf("PQOS: cpu %u has already " | |
402 | "associated COS#%u. " | |
403 | "Please reset L3CA.\n", | |
404 | cpu_id, cos_id); | |
405 | ret = -EBUSY; | |
406 | goto exit; | |
407 | } | |
408 | } | |
409 | } | |
410 | } | |
411 | ||
412 | exit: | |
413 | return ret; | |
414 | } | |
415 | ||
416 | static int | |
417 | check_cdp(void) | |
418 | { | |
419 | unsigned i = 0; | |
420 | ||
421 | for (i = 0; i < m_config_count; i++) { | |
422 | if (m_config[i].cdp == 1 && m_cap_l3ca->u.l3ca->cdp_on == 0) { | |
423 | if (m_cap_l3ca->u.l3ca->cdp == 0) { | |
424 | printf("PQOS: CDP requested but not " | |
425 | "supported.\n"); | |
426 | } else { | |
427 | printf("PQOS: CDP requested but not enabled. " | |
428 | "Please enable CDP.\n"); | |
429 | } | |
430 | return -ENOTSUP; | |
431 | } | |
432 | } | |
433 | ||
434 | return 0; | |
435 | } | |
436 | ||
437 | static int | |
438 | check_cbm_len_and_contention(void) | |
439 | { | |
440 | unsigned i = 0; | |
441 | uint64_t mask = 0; | |
442 | const uint64_t not_cbm = (UINT64_MAX << (m_cap_l3ca->u.l3ca->num_ways)); | |
443 | const uint64_t cbm_contention_mask = m_cap_l3ca->u.l3ca->way_contention; | |
444 | int ret = 0; | |
445 | ||
446 | for (i = 0; i < m_config_count; i++) { | |
447 | if (m_config[i].cdp == 1) | |
448 | mask = m_config[i].code_mask | m_config[i].data_mask; | |
449 | else | |
450 | mask = m_config[i].mask; | |
451 | ||
452 | if ((mask & not_cbm) != 0) { | |
453 | printf("PQOS: One or more of requested CBM masks not " | |
454 | "supported by system (too long).\n"); | |
455 | ret = -ENOTSUP; | |
456 | break; | |
457 | } | |
458 | ||
459 | /* Just a warning */ | |
460 | if ((mask & cbm_contention_mask) != 0) { | |
461 | printf("PQOS: One or more of requested CBM masks " | |
462 | "overlap CBM contention mask.\n"); | |
463 | break; | |
464 | } | |
465 | ||
466 | } | |
467 | ||
468 | return ret; | |
469 | } | |
470 | ||
471 | static int | |
472 | check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS]) | |
473 | { | |
474 | unsigned i = 0; | |
475 | unsigned j = 0; | |
476 | unsigned phy_pkg_id = 0; | |
477 | unsigned cos_id = 0; | |
478 | unsigned cpu_id = 0; | |
479 | unsigned phy_pkg_lcores[PQOS_MAX_SOCKETS][m_config_count]; | |
480 | const unsigned cos_num = m_cap_l3ca->u.l3ca->num_classes; | |
481 | unsigned used_cos_table[PQOS_MAX_SOCKETS][cos_num]; | |
482 | int ret = 0; | |
483 | ||
484 | memset(phy_pkg_lcores, 0, sizeof(phy_pkg_lcores)); | |
485 | memset(used_cos_table, 0, sizeof(used_cos_table)); | |
486 | ||
487 | /* detect currently used COS */ | |
488 | for (j = 0; j < m_cpu->num_cores; j++) { | |
489 | cpu_id = m_cpu->cores[j].lcore; | |
490 | ||
9f95a23c | 491 | #if PQOS_VERSION <= 103 |
7c673cae | 492 | ret = pqos_l3ca_assoc_get(cpu_id, &cos_id); |
9f95a23c TL |
493 | #else |
494 | ret = pqos_alloc_assoc_get(cpu_id, &cos_id); | |
495 | #endif | |
7c673cae FG |
496 | if (ret != PQOS_RETVAL_OK) { |
497 | printf("PQOS: Failed to read COS associated to " | |
498 | "cpu %u on phy_pkg %u.\n", cpu_id, phy_pkg_id); | |
499 | ret = -EFAULT; | |
500 | goto exit; | |
501 | } | |
502 | ||
503 | ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); | |
504 | if (ret != PQOS_RETVAL_OK) { | |
505 | printf("PQOS: Failed to get socket for cpu %u\n", | |
506 | cpu_id); | |
507 | ret = -EFAULT; | |
508 | goto exit; | |
509 | } | |
510 | ||
511 | /* Mark COS as used */ | |
512 | if (used_cos_table[phy_pkg_id][cos_id] == 0) | |
513 | used_cos_table[phy_pkg_id][cos_id]++; | |
514 | } | |
515 | ||
516 | /* look for avail. COS to fulfill requested config */ | |
517 | for (i = 0; i < m_config_count; i++) { | |
518 | for (j = 0; j < m_cpu->num_cores; j++) { | |
519 | cpu_id = m_cpu->cores[j].lcore; | |
520 | if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) | |
521 | continue; | |
522 | ||
523 | ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); | |
524 | if (ret != PQOS_RETVAL_OK) { | |
525 | printf("PQOS: Failed to get socket for " | |
526 | "cpu %u\n", cpu_id); | |
527 | ret = -EFAULT; | |
528 | goto exit; | |
529 | } | |
530 | ||
531 | /* | |
532 | * Check if we already have COS selected | |
533 | * to be used for that group on that socket | |
534 | */ | |
535 | if (phy_pkg_lcores[phy_pkg_id][i] != 0) | |
536 | continue; | |
537 | ||
538 | phy_pkg_lcores[phy_pkg_id][i]++; | |
539 | ||
540 | /* Search for avail. COS to be used on that socket */ | |
541 | for (cos_id = 0; cos_id < cos_num; cos_id++) { | |
542 | if (used_cos_table[phy_pkg_id][cos_id] == 0) { | |
543 | used_cos_table[phy_pkg_id][cos_id]++; | |
544 | cos_id_map[i][phy_pkg_id] = cos_id; | |
545 | break; | |
546 | } | |
547 | } | |
548 | ||
549 | /* If there is no COS available ...*/ | |
550 | if (cos_id == cos_num) { | |
551 | ret = -E2BIG; | |
552 | goto exit; | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | exit: | |
558 | if (ret != 0) | |
559 | printf("PQOS: Not enough available COS to configure " | |
560 | "requested configuration.\n"); | |
561 | ||
562 | return ret; | |
563 | } | |
564 | ||
565 | static int | |
566 | configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS]) | |
567 | { | |
568 | unsigned phy_pkg_id = 0; | |
569 | unsigned cpu_id = 0; | |
570 | unsigned cos_id = 0; | |
571 | unsigned i = 0; | |
572 | unsigned j = 0; | |
573 | struct pqos_l3ca l3ca = {0}; | |
574 | int ret = 0; | |
575 | ||
576 | for (i = 0; i < m_config_count; i++) { | |
577 | memset(&l3ca, 0, sizeof(l3ca)); | |
578 | ||
579 | l3ca.cdp = m_config[i].cdp; | |
580 | if (m_config[i].cdp == 1) { | |
9f95a23c | 581 | #if PQOS_VERSION <= 103 |
7c673cae FG |
582 | l3ca.code_mask = m_config[i].code_mask; |
583 | l3ca.data_mask = m_config[i].data_mask; | |
9f95a23c TL |
584 | #else |
585 | l3ca.u.s.code_mask = m_config[i].code_mask; | |
586 | l3ca.u.s.data_mask = m_config[i].data_mask; | |
587 | #endif | |
7c673cae | 588 | } else |
9f95a23c | 589 | #if PQOS_VERSION <= 103 |
7c673cae | 590 | l3ca.ways_mask = m_config[i].mask; |
9f95a23c TL |
591 | #else |
592 | l3ca.u.ways_mask = m_config[i].mask; | |
593 | #endif | |
7c673cae FG |
594 | |
595 | for (j = 0; j < m_sock_count; j++) { | |
596 | phy_pkg_id = m_sockets[j]; | |
597 | if (cos_id_map[i][phy_pkg_id] == 0) | |
598 | continue; | |
599 | ||
600 | l3ca.class_id = cos_id_map[i][phy_pkg_id]; | |
601 | ||
602 | ret = pqos_l3ca_set(phy_pkg_id, 1, &l3ca); | |
603 | if (ret != PQOS_RETVAL_OK) { | |
604 | printf("PQOS: Failed to set COS %u on " | |
605 | "phy_pkg %u.\n", l3ca.class_id, | |
606 | phy_pkg_id); | |
607 | ret = -EFAULT; | |
608 | goto exit; | |
609 | } | |
610 | } | |
611 | } | |
612 | ||
613 | for (i = 0; i < m_config_count; i++) { | |
614 | for (j = 0; j < m_cpu->num_cores; j++) { | |
615 | cpu_id = m_cpu->cores[j].lcore; | |
616 | if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) | |
617 | continue; | |
618 | ||
619 | ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); | |
620 | if (ret != PQOS_RETVAL_OK) { | |
621 | printf("PQOS: Failed to get socket for " | |
622 | "cpu %u\n", cpu_id); | |
623 | ret = -EFAULT; | |
624 | goto exit; | |
625 | } | |
626 | ||
627 | cos_id = cos_id_map[i][phy_pkg_id]; | |
628 | ||
9f95a23c | 629 | #if PQOS_VERSION <= 103 |
7c673cae | 630 | ret = pqos_l3ca_assoc_set(cpu_id, cos_id); |
9f95a23c TL |
631 | #else |
632 | ret = pqos_alloc_assoc_set(cpu_id, cos_id); | |
633 | #endif | |
7c673cae FG |
634 | if (ret != PQOS_RETVAL_OK) { |
635 | printf("PQOS: Failed to associate COS %u to " | |
636 | "cpu %u\n", cos_id, cpu_id); | |
637 | ret = -EFAULT; | |
638 | goto exit; | |
639 | } | |
640 | } | |
641 | } | |
642 | ||
643 | exit: | |
644 | return ret; | |
645 | } | |
646 | ||
647 | ||
648 | /* Parse the argument given in the command line of the application */ | |
649 | static int | |
650 | parse_args(int argc, char **argv) | |
651 | { | |
652 | int opt = 0; | |
653 | int retval = 0; | |
654 | int oldopterr = 0; | |
655 | char **argvopt = argv; | |
656 | char *prgname = argv[0]; | |
657 | ||
658 | static struct option lgopts[] = { | |
659 | { "l3ca", required_argument, 0, 0 }, | |
660 | { NULL, 0, 0, 0 } | |
661 | }; | |
662 | ||
663 | /* Disable printing messages within getopt() */ | |
664 | oldopterr = opterr; | |
665 | opterr = 0; | |
666 | ||
667 | opt = getopt_long(argc, argvopt, "", lgopts, NULL); | |
668 | if (opt == 0) { | |
669 | retval = parse_l3ca(optarg); | |
670 | if (retval != 0) { | |
671 | printf("PQOS: Invalid L3CA parameters!\n"); | |
672 | goto exit; | |
673 | } | |
674 | ||
675 | argv[optind - 1] = prgname; | |
676 | retval = optind - 1; | |
677 | } else | |
678 | retval = 0; | |
679 | ||
680 | exit: | |
681 | /* reset getopt lib */ | |
11fdf7f2 | 682 | optind = 1; |
7c673cae FG |
683 | |
684 | /* Restore opterr value */ | |
685 | opterr = oldopterr; | |
686 | ||
687 | return retval; | |
688 | } | |
689 | ||
690 | static void | |
691 | print_cmd_line_config(void) | |
692 | { | |
693 | char cpustr[PQOS_MAX_CORES * 3] = {0}; | |
694 | unsigned i = 0; | |
695 | unsigned j = 0; | |
696 | ||
697 | for (i = 0; i < m_config_count; i++) { | |
698 | unsigned len = 0; | |
699 | memset(cpustr, 0, sizeof(cpustr)); | |
700 | ||
701 | /* Generate CPU list */ | |
702 | for (j = 0; j < PQOS_MAX_CORES; j++) { | |
703 | if (CPU_ISSET(j, &m_config[i].cpumask) != 1) | |
704 | continue; | |
705 | ||
706 | len += snprintf(cpustr + len, sizeof(cpustr) - len - 1, | |
707 | "%u,", j); | |
708 | ||
709 | if (len >= sizeof(cpustr) - 1) | |
710 | break; | |
711 | } | |
712 | ||
713 | if (m_config[i].cdp == 1) { | |
714 | printf("PQOS: CPUs: %s cMASK: 0x%llx, dMASK: " | |
715 | "0x%llx\n", cpustr, | |
716 | (unsigned long long)m_config[i].code_mask, | |
717 | (unsigned long long)m_config[i].data_mask); | |
718 | } else { | |
719 | printf("PQOS: CPUs: %s MASK: 0x%llx\n", cpustr, | |
720 | (unsigned long long)m_config[i].mask); | |
721 | } | |
722 | } | |
723 | } | |
724 | ||
725 | /** | |
726 | * @brief Prints CAT configuration | |
727 | */ | |
728 | static void | |
729 | print_cat_config(void) | |
730 | { | |
731 | int ret = PQOS_RETVAL_OK; | |
732 | unsigned i = 0; | |
733 | ||
734 | for (i = 0; i < m_sock_count; i++) { | |
735 | struct pqos_l3ca tab[PQOS_MAX_L3CA_COS] = {{0} }; | |
736 | unsigned num = 0; | |
737 | unsigned n = 0; | |
738 | ||
739 | ret = pqos_l3ca_get(m_sockets[i], PQOS_MAX_L3CA_COS, &num, tab); | |
740 | if (ret != PQOS_RETVAL_OK) { | |
741 | printf("PQOS: Error retrieving COS!\n"); | |
742 | return; | |
743 | } | |
744 | ||
745 | printf("PQOS: COS definitions for Socket %u:\n", m_sockets[i]); | |
746 | for (n = 0; n < num; n++) { | |
747 | if (tab[n].cdp == 1) { | |
748 | printf("PQOS: COS: %u, cMASK: 0x%llx, " | |
749 | "dMASK: 0x%llx\n", tab[n].class_id, | |
9f95a23c | 750 | #if PQOS_VERSION <= 103 |
7c673cae FG |
751 | (unsigned long long)tab[n].code_mask, |
752 | (unsigned long long)tab[n].data_mask); | |
9f95a23c TL |
753 | #else |
754 | (unsigned long long)tab[n].u.s.code_mask, | |
755 | (unsigned long long)tab[n].u.s.data_mask); | |
756 | #endif | |
7c673cae FG |
757 | } else { |
758 | printf("PQOS: COS: %u, MASK: 0x%llx\n", | |
759 | tab[n].class_id, | |
9f95a23c | 760 | #if PQOS_VERSION <= 103 |
7c673cae | 761 | (unsigned long long)tab[n].ways_mask); |
9f95a23c TL |
762 | #else |
763 | (unsigned long long)tab[n].u.ways_mask); | |
764 | #endif | |
7c673cae FG |
765 | } |
766 | } | |
767 | } | |
768 | ||
769 | for (i = 0; i < m_sock_count; i++) { | |
9f95a23c | 770 | #if PQOS_VERSION <= 103 |
7c673cae | 771 | unsigned lcores[PQOS_MAX_SOCKET_CORES] = {0}; |
9f95a23c TL |
772 | #else |
773 | unsigned int *lcores = NULL; | |
774 | #endif | |
7c673cae FG |
775 | unsigned lcount = 0; |
776 | unsigned n = 0; | |
777 | ||
9f95a23c | 778 | #if PQOS_VERSION <= 103 |
7c673cae FG |
779 | ret = pqos_cpu_get_cores(m_cpu, m_sockets[i], |
780 | PQOS_MAX_SOCKET_CORES, &lcount, &lcores[0]); | |
781 | if (ret != PQOS_RETVAL_OK) { | |
9f95a23c TL |
782 | #else |
783 | lcores = pqos_cpu_get_cores(m_cpu, m_sockets[i], | |
784 | &lcount); | |
785 | if (lcores == NULL || lcount == 0) { | |
786 | #endif | |
7c673cae FG |
787 | printf("PQOS: Error retrieving core information!\n"); |
788 | return; | |
789 | } | |
790 | ||
791 | printf("PQOS: CPU information for socket %u:\n", m_sockets[i]); | |
792 | for (n = 0; n < lcount; n++) { | |
793 | unsigned class_id = 0; | |
794 | ||
9f95a23c | 795 | #if PQOS_VERSION <= 103 |
7c673cae | 796 | ret = pqos_l3ca_assoc_get(lcores[n], &class_id); |
9f95a23c TL |
797 | #else |
798 | ret = pqos_alloc_assoc_get(lcores[n], &class_id); | |
799 | #endif | |
7c673cae FG |
800 | if (ret == PQOS_RETVAL_OK) |
801 | printf("PQOS: CPU: %u, COS: %u\n", lcores[n], | |
802 | class_id); | |
803 | else | |
804 | printf("PQOS: CPU: %u, ERROR\n", lcores[n]); | |
805 | } | |
9f95a23c TL |
806 | |
807 | #if PQOS_VERSION > 103 | |
808 | free(lcores); | |
809 | #endif | |
7c673cae FG |
810 | } |
811 | ||
812 | } | |
813 | ||
814 | static int | |
815 | cat_validate(void) | |
816 | { | |
817 | int ret = 0; | |
818 | ||
819 | ret = check_cpus(); | |
820 | if (ret != 0) | |
821 | return ret; | |
822 | ||
823 | ret = check_cdp(); | |
824 | if (ret != 0) | |
825 | return ret; | |
826 | ||
827 | ret = check_cbm_len_and_contention(); | |
828 | if (ret != 0) | |
829 | return ret; | |
830 | ||
831 | ret = check_cpus_overlapping(); | |
832 | if (ret != 0) | |
833 | return ret; | |
834 | ||
835 | return 0; | |
836 | } | |
837 | ||
838 | static int | |
839 | cat_set(void) | |
840 | { | |
841 | int ret = 0; | |
842 | unsigned cos_id_map[m_config_count][PQOS_MAX_SOCKETS]; | |
843 | ||
844 | memset(cos_id_map, 0, sizeof(cos_id_map)); | |
845 | ||
846 | ret = check_and_select_classes(cos_id_map); | |
847 | if (ret != 0) | |
848 | return ret; | |
849 | ||
850 | ret = configure_cat(cos_id_map); | |
851 | if (ret != 0) | |
852 | return ret; | |
853 | ||
854 | return 0; | |
855 | } | |
856 | ||
857 | static void | |
858 | cat_fini(void) | |
859 | { | |
860 | int ret = 0; | |
861 | ||
862 | printf("PQOS: Shutting down PQoS library...\n"); | |
863 | ||
864 | /* deallocate all the resources */ | |
865 | ret = pqos_fini(); | |
866 | if (ret != PQOS_RETVAL_OK && ret != PQOS_RETVAL_INIT) | |
867 | printf("PQOS: Error shutting down PQoS library!\n"); | |
868 | ||
869 | m_cap = NULL; | |
870 | m_cpu = NULL; | |
871 | m_cap_l3ca = NULL; | |
9f95a23c | 872 | #if PQOS_VERSION <= 103 |
7c673cae | 873 | memset(m_sockets, 0, sizeof(m_sockets)); |
9f95a23c TL |
874 | #else |
875 | if (m_sockets != NULL) | |
876 | free(m_sockets); | |
877 | #endif | |
7c673cae FG |
878 | m_sock_count = 0; |
879 | memset(m_config, 0, sizeof(m_config)); | |
880 | m_config_count = 0; | |
881 | } | |
882 | ||
883 | void | |
884 | cat_exit(void) | |
885 | { | |
886 | unsigned i = 0; | |
887 | unsigned j = 0; | |
888 | unsigned cpu_id = 0; | |
889 | int ret = 0; | |
890 | ||
891 | /* if lib is not initialized, do nothing */ | |
892 | if (m_cap == NULL && m_cpu == NULL) | |
893 | return; | |
894 | ||
895 | printf("PQOS: Reverting CAT configuration...\n"); | |
896 | ||
897 | for (i = 0; i < m_config_count; i++) { | |
898 | for (j = 0; j < m_cpu->num_cores; j++) { | |
899 | cpu_id = m_cpu->cores[j].lcore; | |
900 | if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) | |
901 | continue; | |
902 | ||
9f95a23c | 903 | #if PQOS_VERSION <= 103 |
7c673cae | 904 | ret = pqos_l3ca_assoc_set(cpu_id, 0); |
9f95a23c TL |
905 | #else |
906 | ret = pqos_alloc_assoc_set(cpu_id, 0); | |
907 | #endif | |
7c673cae FG |
908 | if (ret != PQOS_RETVAL_OK) { |
909 | printf("PQOS: Failed to associate COS 0 to " | |
910 | "cpu %u\n", cpu_id); | |
911 | } | |
912 | } | |
913 | } | |
914 | ||
915 | cat_fini(); | |
916 | } | |
917 | ||
918 | static void | |
919 | signal_handler(int signum) | |
920 | { | |
921 | if (signum == SIGINT || signum == SIGTERM) { | |
922 | printf("\nPQOS: Signal %d received, preparing to exit...\n", | |
923 | signum); | |
924 | ||
925 | cat_exit(); | |
926 | ||
927 | /* exit with the expected status */ | |
928 | signal(signum, SIG_DFL); | |
929 | kill(getpid(), signum); | |
930 | } | |
931 | } | |
932 | ||
933 | int | |
934 | cat_init(int argc, char **argv) | |
935 | { | |
936 | int ret = 0; | |
937 | int args_num = 0; | |
938 | struct pqos_config cfg = {0}; | |
939 | ||
940 | if (m_cap != NULL || m_cpu != NULL) { | |
941 | printf("PQOS: CAT module already initialized!\n"); | |
942 | return -EEXIST; | |
943 | } | |
944 | ||
945 | /* Parse cmd line args */ | |
946 | ret = parse_args(argc, argv); | |
947 | ||
948 | if (ret <= 0) | |
949 | goto err; | |
950 | ||
951 | args_num = ret; | |
952 | ||
953 | /* Print cmd line configuration */ | |
954 | print_cmd_line_config(); | |
955 | ||
956 | /* PQoS Initialization - Check and initialize CAT capability */ | |
957 | cfg.fd_log = STDOUT_FILENO; | |
958 | cfg.verbose = 0; | |
9f95a23c | 959 | #if PQOS_VERSION <= 103 |
7c673cae | 960 | cfg.cdp_cfg = PQOS_REQUIRE_CDP_ANY; |
9f95a23c | 961 | #endif |
7c673cae FG |
962 | ret = pqos_init(&cfg); |
963 | if (ret != PQOS_RETVAL_OK) { | |
964 | printf("PQOS: Error initializing PQoS library!\n"); | |
965 | ret = -EFAULT; | |
966 | goto err; | |
967 | } | |
968 | ||
969 | /* Get capability and CPU info pointer */ | |
970 | ret = pqos_cap_get(&m_cap, &m_cpu); | |
971 | if (ret != PQOS_RETVAL_OK || m_cap == NULL || m_cpu == NULL) { | |
972 | printf("PQOS: Error retrieving PQoS capabilities!\n"); | |
973 | ret = -EFAULT; | |
974 | goto err; | |
975 | } | |
976 | ||
977 | /* Get L3CA capabilities */ | |
978 | ret = pqos_cap_get_type(m_cap, PQOS_CAP_TYPE_L3CA, &m_cap_l3ca); | |
979 | if (ret != PQOS_RETVAL_OK || m_cap_l3ca == NULL) { | |
980 | printf("PQOS: Error retrieving PQOS_CAP_TYPE_L3CA " | |
981 | "capabilities!\n"); | |
982 | ret = -EFAULT; | |
983 | goto err; | |
984 | } | |
985 | ||
986 | /* Get CPU socket information */ | |
9f95a23c | 987 | #if PQOS_VERSION <= 103 |
7c673cae FG |
988 | ret = pqos_cpu_get_sockets(m_cpu, PQOS_MAX_SOCKETS, &m_sock_count, |
989 | m_sockets); | |
990 | if (ret != PQOS_RETVAL_OK) { | |
9f95a23c TL |
991 | #else |
992 | m_sockets = pqos_cpu_get_sockets(m_cpu, &m_sock_count); | |
993 | if (m_sockets == NULL) { | |
994 | #endif | |
7c673cae FG |
995 | printf("PQOS: Error retrieving CPU socket information!\n"); |
996 | ret = -EFAULT; | |
997 | goto err; | |
998 | } | |
999 | ||
1000 | /* Validate cmd line configuration */ | |
1001 | ret = cat_validate(); | |
1002 | if (ret != 0) { | |
1003 | printf("PQOS: Requested CAT configuration is not valid!\n"); | |
1004 | goto err; | |
1005 | } | |
1006 | ||
1007 | /* configure system */ | |
1008 | ret = cat_set(); | |
1009 | if (ret != 0) { | |
1010 | printf("PQOS: Failed to configure CAT!\n"); | |
1011 | goto err; | |
1012 | } | |
1013 | ||
1014 | signal(SIGINT, signal_handler); | |
1015 | signal(SIGTERM, signal_handler); | |
1016 | ||
1017 | ret = atexit(cat_exit); | |
1018 | if (ret != 0) { | |
1019 | printf("PQOS: Cannot set exit function\n"); | |
1020 | goto err; | |
1021 | } | |
1022 | ||
1023 | /* Print CAT configuration */ | |
1024 | print_cat_config(); | |
1025 | ||
1026 | return args_num; | |
1027 | ||
1028 | err: | |
1029 | /* deallocate all the resources */ | |
1030 | cat_fini(); | |
1031 | return ret; | |
1032 | } |