Skip to content

Commit 00c4974

Browse files
committed
Rethink things a bit. Store everything in a database and use that to serialise operations
1 parent d38d4ca commit 00c4974

10 files changed

+337
-248
lines changed

Diff for: CMakeLists.txt

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ project(
44
tsp_for_hpc
55
LANGUAGES CXX)
66

7+
find_package(SQLite3 REQUIRED)
8+
79
set(CMAKE_CXX_STANDARD 20)
810
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
911

@@ -14,9 +16,10 @@ set(sources
1416
run_cmd.cpp
1517
status_manager.cpp
1618
output_manager.cpp
17-
proc_manager.cpp
19+
proc_affinity.cpp
1820
tsp.cpp)
1921

2022
add_executable(tsp-hpc ${sources})
2123

22-
target_include_directories(tsp-hpc PUBLIC .)
24+
target_link_libraries(tsp-hpc PUBLIC ${SQLite3_LIBRARIES})
25+
include_directories(. ${SQLite3_INCLUDE_DIRS})

Diff for: functions.cpp

+91-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
#include <cstdlib>
1+
22
#include <string>
3-
#include <stdexcept>
3+
#include <vector>
4+
#include <cstdint>
45
#include <cstring>
6+
#include <sys/types.h>
7+
#include <unistd.h>
8+
#include <sstream>
9+
#include <numeric>
10+
#include <fstream>
11+
#include <filesystem>
12+
13+
#include "functions.hpp"
14+
15+
#define CGROUP_CPUSET_PATH_PREFIX "/sys/fs/cgroup/cpuset"
16+
#define CPUSET_FILE "/cpuset.cpus"
517

618
const char *get_tmp()
719
{
@@ -11,12 +23,86 @@ const char *get_tmp()
1123
out = "/tmp";
1224
}
1325
return out;
14-
}
15-
26+
};
1627
void die_with_err(std::string msg, int status)
1728
{
1829
std::string out(msg);
1930
out.append("\nstat=" + std::to_string(status) + ", errno=" + std::to_string(errno));
2031
out.append(std::string("\n") + strerror(errno));
2132
throw std::runtime_error(out);
22-
}
33+
};
34+
std::vector<uint32_t> parse_cpuset_range(std::string in)
35+
{
36+
std::stringstream ss1(in);
37+
std::string token;
38+
std::vector<std::uint32_t> out;
39+
while (std::getline(ss1, token, ','))
40+
{
41+
if (token.find('-') == std::string::npos)
42+
{
43+
out.push_back(std::stoul(token));
44+
}
45+
else
46+
{
47+
std::stringstream ss2(token);
48+
std::string starts, ends;
49+
std::getline(ss2, starts, '-');
50+
std::getline(ss2, ends, '-');
51+
std::vector<std::uint32_t> tmp(std::stoul(ends) - std::stoul(starts) + 1);
52+
std::iota(tmp.begin(), tmp.end(), std::stoul(starts));
53+
out.insert(out.end(), tmp.begin(), tmp.end());
54+
}
55+
}
56+
return out;
57+
};
58+
std::vector<std::uint32_t> get_cgroup()
59+
{
60+
std::filesystem::path cgroup_fn(std::string("/proc/" + std::to_string(getpid()) + "/cgroup"));
61+
if (!std::filesystem::exists(cgroup_fn))
62+
{
63+
throw std::runtime_error("Cgroup file for process " + std::to_string(getpid()) + " not found");
64+
}
65+
std::string line;
66+
std::filesystem::path cpuset_path;
67+
// get cpuset path
68+
std::ifstream cgroup_file(cgroup_fn);
69+
if (cgroup_file.is_open())
70+
{
71+
while (std::getline(cgroup_file, line))
72+
{
73+
std::vector<std::string> seglist;
74+
std::string segment;
75+
std::stringstream ss(line);
76+
while (std::getline(ss, segment, ':'))
77+
{
78+
seglist.push_back(segment);
79+
};
80+
if (seglist[1] == "cpuset")
81+
{
82+
cpuset_path = CGROUP_CPUSET_PATH_PREFIX;
83+
cpuset_path += seglist[2];
84+
cpuset_path += CPUSET_FILE;
85+
}
86+
if (!cpuset_path.empty())
87+
{
88+
break;
89+
}
90+
}
91+
cgroup_file.close();
92+
}
93+
else
94+
{
95+
throw std::runtime_error("Unable to open cgroup file " + cgroup_fn.string());
96+
}
97+
// read cpuset file
98+
std::ifstream cpuset_file(cpuset_path);
99+
if (cpuset_file.is_open())
100+
{
101+
std::getline(cpuset_file, line);
102+
return parse_cpuset_range(line);
103+
}
104+
else
105+
{
106+
throw std::runtime_error("Unable to open cpuset file " + cpuset_path.string());
107+
}
108+
};

Diff for: functions.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#pragma once
2+
23
#include <string>
4+
#include <vector>
5+
#include <cstdint>
6+
#include <numeric>
37

4-
const char* get_tmp();
5-
void die_with_err(std::string msg, int status);
8+
const char *get_tmp();
9+
void die_with_err(std::string msg, int status);
10+
std::vector<uint32_t> parse_cpuset_range(std::string in);
11+
std::vector<std::uint32_t> get_cgroup();

Diff for: proc_affinity.cpp

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#include <fstream>
2+
#include <algorithm>
3+
#include <numeric>
4+
5+
#include "proc_affinity.hpp"
6+
#include "functions.hpp"
7+
#include "semaphore.hpp"
8+
9+
namespace tsp
10+
{
11+
12+
Proc_affinity::Proc_affinity(uint32_t nslots, pid_t pid) : nslots(nslots), pid(pid), 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+
CPU_ZERO(&mask);
20+
21+
}
22+
23+
std::vector<uint32_t> Proc_affinity::bind()
24+
{
25+
auto sibling_pids = get_siblings();
26+
std::vector<uint32_t> siblings_affinity;
27+
std::vector<uint32_t> out;
28+
for (auto i : sibling_pids)
29+
{
30+
auto tmp = get_sibling_affinity(i);
31+
siblings_affinity.insert(siblings_affinity.end(), tmp.begin(), tmp.end());
32+
}
33+
std::sort(siblings_affinity.begin(), siblings_affinity.end());
34+
std::vector<uint32_t> allowed_cores;
35+
std::set_difference(cpuset_from_cgroup.begin(), cpuset_from_cgroup.end(),
36+
siblings_affinity.begin(), siblings_affinity.end(),
37+
std::inserter(allowed_cores, allowed_cores.begin()));
38+
39+
if (allowed_cores.size() < nslots)
40+
{
41+
// Something has beaten us to the punch, report failed and
42+
// try again the next time
43+
return out;
44+
}
45+
for (uint32_t i = 0; i < nslots; i++)
46+
{
47+
CPU_SET(allowed_cores[i], &mask);
48+
out.push_back(allowed_cores[i]);
49+
}
50+
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1)
51+
{
52+
die_with_err("Unable to set CPU affinity", -1);
53+
}
54+
return out;
55+
}
56+
57+
std::vector<pid_t> Proc_affinity::get_siblings()
58+
{
59+
std::vector<pid_t> out;
60+
// Find all the other versions of this application running
61+
for (const auto &entry : std::filesystem::directory_iterator("/proc"))
62+
{
63+
if (std::find(skip_paths.begin(), skip_paths.end(), entry.path().filename()) != skip_paths.end())
64+
{
65+
continue;
66+
}
67+
if (std::filesystem::exists(entry.path() / "exe"))
68+
{
69+
try
70+
{
71+
if (std::filesystem::read_symlink(entry.path() / "exe") == my_path)
72+
{
73+
out.push_back(std::stoul(entry.path().filename()));
74+
}
75+
}
76+
catch (std::filesystem::filesystem_error &e)
77+
{
78+
// process went away
79+
continue;
80+
}
81+
}
82+
}
83+
return out;
84+
};
85+
86+
std::vector<uint32_t> Proc_affinity::get_sibling_affinity(pid_t pid)
87+
{
88+
std::vector<uint32_t> out;
89+
cpu_set_t mask;
90+
// Just return an empty vector if the semaphore file is present
91+
try
92+
{
93+
for (const auto &entry : std::filesystem::directory_iterator("/proc/" + std::to_string(pid) + "/fd"))
94+
if (std::filesystem::read_symlink(entry).string().find(SEMAPHORE_FILE_TEMPLATE) != std::string::npos)
95+
{
96+
// Semaphore present, ignore
97+
return out;
98+
}
99+
}
100+
101+
catch (std::filesystem::filesystem_error &e)
102+
{
103+
// Process went away
104+
return out;
105+
}
106+
if (sched_getaffinity(pid, sizeof(mask), &mask) == -1)
107+
{
108+
// Process may have been killed - so it isn't taking
109+
// resources any more
110+
return out;
111+
}
112+
for (const auto &i : cpuset_from_cgroup)
113+
{
114+
if (CPU_ISSET(i, &mask))
115+
{
116+
out.push_back(i);
117+
}
118+
}
119+
return out;
120+
};
121+
};

Diff for: proc_manager.hpp renamed to proc_affinity.hpp

+7-12
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,23 @@
88
#include <filesystem>
99
#include <sys/types.h>
1010

11-
#define CGROUP_CPUSET_PATH_PREFIX "/sys/fs/cgroup/cpuset"
12-
#define CPUSET_FILE "/cpuset.cpus"
13-
1411
namespace tsp
1512
{
16-
class Tsp_Proc
13+
class Proc_affinity
1714
{
1815
public:
19-
const pid_t pid;
20-
std::vector<uint32_t> allowed_cores;
21-
Tsp_Proc(uint32_t nslots);
22-
bool allowed_to_run();
23-
void refresh_allowed_cores();
24-
~Tsp_Proc() {};
16+
Proc_affinity(uint32_t nslots, pid_t pid);
17+
~Proc_affinity() {};
18+
std::vector<uint32_t> bind();
2519

2620
private:
2721
const uint32_t nslots;
22+
const pid_t pid;
2823
const std::filesystem::path my_path;
2924
const std::vector<uint32_t> cpuset_from_cgroup;
25+
cpu_set_t mask;
3026
std::vector<pid_t> get_siblings();
31-
std::vector<std::uint32_t> parse_cpuset_range(std::string in);
3227
std::vector<uint32_t> get_sibling_affinity(pid_t pid);
33-
std::vector<uint32_t> get_cgroup();
28+
std::vector<std::string> skip_paths = {std::to_string(pid), "self", "thread-self"};
3429
};
3530
}

0 commit comments

Comments
 (0)