1
+ #include < fstream>
2
+ #include < algorithm>
3
+ #include < numeric>
4
+
5
+ #include " proc_manager.hpp"
6
+ #include " functions.hpp"
7
+ #include " semaphore.hpp"
8
+
9
+ namespace tsp
10
+ {
11
+
12
+ Tsp_Proc::Tsp_Proc (uint32_t np) : pid(getpid()), nslots(np), my_path(std::filesystem::read_symlink(" /proc/self/exe" )), cpuset_from_cgroup(get_cgroup())
13
+ {
14
+ // Open cgroups file
15
+ if (nslots > cpuset_from_cgroup.size ())
16
+ {
17
+ die_with_err (" More slots requested than available on the system, this process can never run." , -1 );
18
+ }
19
+ refresh_allowed_cores ();
20
+ }
21
+
22
+ bool Tsp_Proc::allowed_to_run ()
23
+ {
24
+ return allowed_cores.size () > nslots;
25
+ }
26
+
27
+ void Tsp_Proc::refresh_allowed_cores ()
28
+ {
29
+ auto sibling_pids = get_siblings ();
30
+ std::vector<uint32_t > siblings_affinity;
31
+ for (auto i : sibling_pids)
32
+ {
33
+ auto tmp = get_sibling_affinity (i);
34
+ siblings_affinity.insert (siblings_affinity.end (), tmp.begin (), tmp.end ());
35
+ }
36
+ std::sort (siblings_affinity.begin (), siblings_affinity.end ());
37
+ allowed_cores.clear ();
38
+ std::set_difference (cpuset_from_cgroup.begin (), cpuset_from_cgroup.end (),
39
+ siblings_affinity.begin (), siblings_affinity.end (),
40
+ std::inserter (allowed_cores, allowed_cores.begin ()));
41
+ }
42
+
43
+ std::vector<pid_t > Tsp_Proc::get_siblings ()
44
+ {
45
+ std::vector<pid_t > out;
46
+ std::vector<std::string> skip_paths = {std::to_string (pid), " self" , " thread-self" };
47
+ // Find all the other versions of this application running
48
+ for (const auto &entry : std::filesystem::directory_iterator (" /proc" ))
49
+ {
50
+ if (std::find (skip_paths.begin (), skip_paths.end (), entry.path ().filename ()) != skip_paths.end ())
51
+ {
52
+ continue ;
53
+ }
54
+ if (std::filesystem::exists (entry.path () / " exe" ))
55
+ {
56
+ try
57
+ {
58
+ if (std::filesystem::read_symlink (entry.path () / " exe" ) == my_path)
59
+ {
60
+ out.push_back (std::stoul (entry.path ().filename ()));
61
+ }
62
+ }
63
+ catch (std::filesystem::filesystem_error &e)
64
+ {
65
+ // process went away
66
+ continue ;
67
+ }
68
+ }
69
+ }
70
+ return out;
71
+ };
72
+
73
+ std::vector<std::uint32_t > Tsp_Proc::parse_cpuset_range (std::string in)
74
+ {
75
+ std::stringstream ss1 (in);
76
+ std::string token;
77
+ std::vector<std::uint32_t > out;
78
+ while (std::getline (ss1, token, ' ,' ))
79
+ {
80
+ if (token.find (' -' ) == std::string::npos)
81
+ {
82
+ out.push_back (std::stoul (token));
83
+ }
84
+ else
85
+ {
86
+ std::stringstream ss2 (token);
87
+ std::string starts, ends;
88
+ std::getline (ss2, starts, ' -' );
89
+ std::getline (ss2, ends, ' -' );
90
+ std::vector<std::uint32_t > tmp (std::stoul (ends) - std::stoul (starts) + 1 );
91
+ std::iota (tmp.begin (), tmp.end (), std::stoul (starts));
92
+ out.insert (out.end (), tmp.begin (), tmp.end ());
93
+ }
94
+ }
95
+ return out;
96
+ };
97
+
98
+ std::vector<uint32_t > Tsp_Proc::get_sibling_affinity (pid_t pid)
99
+ {
100
+ std::vector<uint32_t > out;
101
+ cpu_set_t mask;
102
+ // Just return an empty vector if the semaphore file is present
103
+ try
104
+ {
105
+ for (const auto &entry : std::filesystem::directory_iterator (" /proc/" + std::to_string (pid) + " /fd" ))
106
+ if (std::filesystem::read_symlink (entry).string ().find (SEMAPHORE_FILE_TEMPLATE) != std::string::npos)
107
+ {
108
+ // Semaphore present, ignore
109
+ return out;
110
+ }
111
+ }
112
+
113
+ catch (std::filesystem::filesystem_error &e)
114
+ {
115
+ // Process went away
116
+ return out;
117
+ }
118
+ if (sched_getaffinity (pid, sizeof (mask), &mask) == -1 )
119
+ {
120
+ // Process may have been killed - so it isn't taking
121
+ // resources any more
122
+ return out;
123
+ }
124
+ for (const auto &i : cpuset_from_cgroup)
125
+ {
126
+ if (CPU_ISSET (i, &mask))
127
+ {
128
+ out.push_back (i);
129
+ }
130
+ }
131
+ return out;
132
+ };
133
+
134
+ std::vector<uint32_t > Tsp_Proc::get_cgroup ()
135
+ {
136
+ std::filesystem::path cgroup_fn (std::string (" /proc/" + std::to_string (pid) + " /cgroup" ));
137
+ if (!std::filesystem::exists (cgroup_fn))
138
+ {
139
+ throw std::runtime_error (" Cgroup file for process " + std::to_string (pid) + " not found" );
140
+ }
141
+ std::string line;
142
+ std::filesystem::path cpuset_path;
143
+ // get cpuset path
144
+ std::ifstream cgroup_file (cgroup_fn);
145
+ if (cgroup_file.is_open ())
146
+ {
147
+ while (std::getline (cgroup_file, line))
148
+ {
149
+ std::vector<std::string> seglist;
150
+ std::string segment;
151
+ std::stringstream ss (line);
152
+ while (std::getline (ss, segment, ' :' ))
153
+ {
154
+ seglist.push_back (segment);
155
+ };
156
+ if (seglist[1 ] == " cpuset" )
157
+ {
158
+ cpuset_path = CGROUP_CPUSET_PATH_PREFIX;
159
+ cpuset_path += seglist[2 ];
160
+ cpuset_path += CPUSET_FILE;
161
+ }
162
+ if (!cpuset_path.empty ())
163
+ {
164
+ break ;
165
+ }
166
+ }
167
+ cgroup_file.close ();
168
+ }
169
+ else
170
+ {
171
+ throw std::runtime_error (" Unable to open cgroup file " + cgroup_fn.string ());
172
+ }
173
+ // read cpuset file
174
+ std::ifstream cpuset_file (cpuset_path);
175
+ if (cpuset_file.is_open ())
176
+ {
177
+ std::getline (cpuset_file, line);
178
+ return parse_cpuset_range (line);
179
+ }
180
+ else
181
+ {
182
+ throw std::runtime_error (" Unable to open cpuset file " + cpuset_path.string ());
183
+ }
184
+ }
185
+ };
0 commit comments