cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
worker_affinity.h
Go to the documentation of this file.
1#ifndef CWIST_APP_WORKER_AFFINITY_H
2#define CWIST_APP_WORKER_AFFINITY_H
3
4/* Private Linux startup helper; callers must enable GNU affinity APIs. */
5#include <errno.h>
6#include <sched.h>
7#include <stddef.h>
8
9#include <stdio.h>
10
11#ifndef CWIST_APP_CPU_SYSFS
12#define CWIST_APP_CPU_SYSFS "/sys/devices/system/cpu"
13#endif
14
15/* Parse a sysfs cpulist ("0,6" or "0-1,8-9") into @p out. Returns 0, or -1
16 * on an unreadable or malformed file. */
17static inline int cwist_app_read_cpulist(const char *path, cpu_set_t *out) {
18 FILE *f = fopen(path, "re");
19 if (!f) return -1;
20 CPU_ZERO(out);
21 int rc = -1, lo, hi;
22 char sep;
23 for (;;) {
24 if (fscanf(f, "%d", &lo) != 1) break;
25 hi = lo;
26 int n = fscanf(f, "%c", &sep);
27 if (n == 1 && sep == '-') {
28 if (fscanf(f, "%d", &hi) != 1) break;
29 n = fscanf(f, "%c", &sep);
30 }
31 if (lo < 0 || hi < lo || hi >= CPU_SETSIZE) break;
32 for (int cpu = lo; cpu <= hi; cpu++) CPU_SET(cpu, out);
33 if (n != 1 || sep == '\n') {
34 rc = 0;
35 break;
36 }
37 if (sep != ',') break;
38 }
39 fclose(f);
40 return rc;
41}
42
43/* SMT siblings of @p cpu, @p cpu included. Falls back to {cpu} when the
44 * topology is not exposed (containers without sysfs, odd kernels), which
45 * keeps the plain ascending order. */
46static inline void cwist_app_cpu_siblings(int cpu, cpu_set_t *out) {
47 char path[512];
48 snprintf(path, sizeof(path), "%s/cpu%d/topology/core_cpus_list", CWIST_APP_CPU_SYSFS, cpu);
49 if (cwist_app_read_cpulist(path, out) == 0 && CPU_ISSET(cpu, out)) return;
50 snprintf(path, sizeof(path), "%s/cpu%d/topology/thread_siblings_list", CWIST_APP_CPU_SYSFS,
51 cpu);
52 if (cwist_app_read_cpulist(path, out) == 0 && CPU_ISSET(cpu, out)) return;
53 CPU_ZERO(out);
54 CPU_SET(cpu, out);
55}
56
76static inline int cwist_app_pin_worker(size_t worker_index) {
78 if (sched_getaffinity(0, sizeof(allowed), &allowed) < 0) return -1;
79 int count = CPU_COUNT(&allowed);
80 if (count == 0) {
81 errno = EINVAL;
82 return -1;
83 }
84 size_t ordinal = worker_index % (size_t)count;
85 /* rank[cpu]: allowed siblings below cpu. Only allowed CPUs are filled. */
86 unsigned short rank[CPU_SETSIZE];
87 int max_rank = 0;
88 for (int cpu = 0; cpu < CPU_SETSIZE; cpu++) {
89 if (!CPU_ISSET(cpu, &allowed)) continue;
91 cwist_app_cpu_siblings(cpu, &sib);
92 CPU_AND(&sib, &sib, &allowed);
93 int r = 0;
94 for (int other = 0; other < cpu; other++)
95 if (CPU_ISSET(other, &sib)) r++;
96 rank[cpu] = (unsigned short)r;
97 if (r > max_rank) max_rank = r;
98 }
99 for (int r = 0; r <= max_rank; r++) {
100 for (int cpu = 0; cpu < CPU_SETSIZE; cpu++) {
101 if (!CPU_ISSET(cpu, &allowed) || rank[cpu] != r) continue;
102 if (ordinal != 0) {
103 ordinal--;
104 continue;
105 }
109 return sched_setaffinity(0, sizeof(selected), &selected);
110 }
111 }
112 errno = EINVAL;
113 return -1;
114}
115
116#endif
size_t count
Definition otel.c:58
size_t cap
Definition otel.c:56
#define CWIST_APP_CPU_SYSFS