SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
SSHScheduler.cpp
Go to the documentation of this file.
1 #include "SSHScheduler.h"
2 
3 #ifdef BENCHMAX_SSH
4 
5 #include <atomic>
6 #include <chrono>
7 #include <functional>
8 #include <regex>
9 #include <string>
10 #include <sys/stat.h>
11 #include <thread>
12 
13 #include <libssh/callbacks.h>
14 
15 #include "Node.h"
16 #include "SSHConnection.h"
17 #include "SSHSettings.h"
18 #include <benchmax/logging.h>
19 
20 namespace benchmax {
21 namespace ssh {
22 
23 /**
24  * Parses a node identifier of the format `server[:port]@[numberOfCores]@user@password`
25  * @param _nodeAsString
26  * @return
27  */
28 Node getNode(const std::string& _nodeAsString)
29 {
30  std::regex noderegex("([^:@]+)(?::([^@]+))?@([^:@]+)(?::(\\d+))?(?:@(\\d+))?(?:#(\\d+))?");
31  std::smatch matches;
32  if (std::regex_match(_nodeAsString, matches, noderegex)) {
33  std::string username = matches[1];
34  std::string password = matches[2];
35  std::string hostname = matches[3];
36  unsigned long port = 22;
37  unsigned long cores = 1;
38  std::size_t connections = 1;
39  try {
40  if (matches[4] != "") port = std::stoul(matches[4]);
41  if (matches[5] != "") cores = std::stoul(matches[5]);
42  if (matches[6] != "") connections = std::stoul(matches[6]);
43  } catch (const std::out_of_range&) {
44  BENCHMAX_LOG_ERROR("benchmax", "Value for port or number of cores is out of range.");
45  BENCHMAX_LOG_ERROR("benchmax", "\tPort: " << matches[4]);
46  BENCHMAX_LOG_ERROR("benchmax", "\tCores: " << matches[5]);
47  }
48  return {hostname, username, password, (unsigned short)port, cores, connections};
49  } else {
50  BENCHMAX_LOG_ERROR("benchmax", "Invalid format for node specification. Use the following format:");
51  BENCHMAX_LOG_ERROR("benchmax", "\t<user>[:<password>]@<hostname>[:<port = 22>][@<cores = 1>][#<connections = 1>]");
52  exit(1);
53  }
54 }
55 
56 const std::unique_ptr<SSHConnection>& SSHScheduler::get() {
57  std::lock_guard<std::mutex> lock(mMutex);
58  while (true) {
59  for (auto& c: mConnections) {
60  if (c->jobFree()) {
61  c->newJob();
62  return c;
63  }
64  }
65  std::this_thread::yield();
66  std::this_thread::sleep_for(std::chrono::milliseconds(100));
67  }
68 }
69 std::string SSHScheduler::tmpDirName(const Tool* tool, const fs::path& file) const {
70  return "benchmax-" + std::to_string(settings_core().start_time) + "-" + std::to_string(std::size_t(tool)) + "-" + std::to_string(std::hash<std::string>()(file.native()));
71 }
72 std::string SSHScheduler::tmpDirName(const Tool* tool) const {
73  return "benchmax-" + std::to_string(settings_core().start_time) + "-" + std::to_string(std::size_t(tool));
74 }
75 SSHScheduler::SSHScheduler(): mWorkerCount(0), mRunningJobs(0) {
76  ssh_threads_set_callbacks(ssh_threads_get_pthread());
77  ssh_init();
78  for (const auto& s: settings_ssh().nodes) {
79  Node n = getNode(s);
80  for (std::size_t i = 0; i < n.connections; i++) {
81  mConnections.emplace_back(std::make_unique<SSHConnection>(n));
82  }
83  mWorkerCount += n.connections * n.cores;
84  }
85 }
86 
87 void SSHScheduler::uploadTool(const Tool* tool) {
88  std::lock_guard<std::mutex> lock(mMutex);
89  BENCHMAX_LOG_DEBUG("benchmax.ssh", "Uploading " << tool);
90 
91  std::vector<std::filesystem::path> filesToUpload;
92  filesToUpload.emplace_back(tool->binary());
93 
94  if (settings_ssh().resolve_deps) {
95  auto deps = tool->resolveDependencies();
96  for (const auto& dep : deps) {
97  filesToUpload.emplace_back(dep);
98  }
99  }
100 
101  std::set<std::string> nodes;
102  for (const auto& c: mConnections) {
103  // Check if we have already uploaded to this host
104  if (!nodes.insert(c->getNode().hostname).second) continue;
105  while (!c->jobFree()) {
106  std::this_thread::sleep_for(std::chrono::milliseconds(10));
107  }
108  assert(mRemoteToolLocations.count(std::make_pair(tool, c->getNode().hostname)) == 0);
109  std::string folder = c->createTmpDir(tmpDirName(tool));
110  mRemoteToolLocations.emplace(std::make_pair(tool, c->getNode().hostname), folder);
111  for (const auto& f : filesToUpload) {
112  c->uploadFile(f.native(), folder, f.filename().native(), S_IRWXU);
113  }
114  }
115 }
116 
117 void SSHScheduler::cleanupTools() {
118  BENCHMAX_LOG_DEBUG("benchmax.ssh", "Cleaning up tools");
119  for (const auto& c: mConnections) {
120  for (auto it = mRemoteToolLocations.cbegin(); it != mRemoteToolLocations.cend(); ) {
121  if (it->first.second == c->getNode().hostname) {
122  c->removeDir(it->second);
123  it = mRemoteToolLocations.erase(it);
124  }
125  else {
126  ++it;
127  }
128  }
129  }
130 }
131 
132 bool SSHScheduler::executeJob(const Tool* tool, const fs::path& file, Backend* backend) {
133  mRunningJobs++;
134  const auto& c = get();
135  BENCHMAX_LOG_DEBUG("benchmax.ssh", "Executing " << remove_prefix(file, settings_benchmarks().input_directories_common_prefix));
136  // Create temporary directory
137  std::string folder = c->createTmpDir(tmpDirName(tool,file));
138  // Upload benchmark file
139  c->uploadFile(file, folder, file.filename().native());
140  // Execute benchmark run
141  BenchmarkResult result;
142  assert(mRemoteToolLocations.find(std::make_pair(tool, c->getNode().hostname)) != mRemoteToolLocations.end());
143  std::string toolFolder = mRemoteToolLocations.at(std::make_pair(tool, c->getNode().hostname));
144  std::string cmdLine = tool->getCommandline(folder + file.filename().native(), toolFolder + tool->binary().filename().native());
145  if (settings_ssh().resolve_deps) {
146  cmdLine = "LD_LIBRARY_PATH=. " + cmdLine;
147  }
148  if (!c->executeCommand(cmdLine, result)) {
149  BENCHMAX_LOG_ERROR("benchmax.ssh", "Failed to execute command.");
150  }
151  // Remove temporary directory
152  c->removeDir(folder);
153  // Store result
154  backend->addResult(tool, file, std::move(result));
155  c->finishJob();
156  mRunningJobs--;
157  return true;
158 }
159 
160 }
161 }
162 
163 #endif
#define BENCHMAX_LOG_DEBUG(channel, msg)
Log debug messages.
Definition: logging.h:55
#define BENCHMAX_LOG_ERROR(channel, msg)
Log errors.
Definition: logging.h:49
const auto & settings_ssh()
Return the SSH settings.
Definition: SSHSettings.h:27
const auto & settings_core()
Retrieved core settings.
Definition: Settings.h:81
const auto & settings_benchmarks()
Return the benchmark settings.
Definition: benchmarks.h:41
std::filesystem::path remove_prefix(const std::filesystem::path &s, const std::filesystem::path &prefix)
Remove a prefix from a path.
Definition: filesystem.h:54
auto get(const It &it, level)