File indexing completed on 2025-01-18 10:17:37
0001
0002
0003
0004
0005 #include "JProcessorMapping.h"
0006
0007 #include <JANA/Utils/JTablePrinter.h>
0008 #include <iomanip>
0009 #include <unistd.h>
0010 #include <sys/wait.h>
0011 #include <algorithm>
0012
0013 void JProcessorMapping::initialize(AffinityStrategy affinity, LocalityStrategy locality) {
0014
0015 m_affinity_strategy = affinity;
0016 m_locality_strategy = locality;
0017
0018 if (affinity == AffinityStrategy::None && locality == LocalityStrategy::Global) {
0019
0020 m_error_msg = "";
0021 return;
0022 }
0023
0024
0025
0026 int pipe_fd[2];
0027 if (pipe(pipe_fd) == -1) {
0028 m_error_msg = "Unable to open pipe";
0029 return;
0030 }
0031 pid_t pid = fork();
0032 if (pid == -1) {
0033 m_error_msg = "Unable to fork";
0034 close(pipe_fd[0]);
0035 close(pipe_fd[1]);
0036 return;
0037 }
0038 else if (pid == 0) {
0039 dup2(pipe_fd[1], 1);
0040 close(pipe_fd[0]);
0041 close(pipe_fd[1]);
0042 execlp("lscpu", "lscpu", "-b", "-pcpu,core,node,socket", (char*) nullptr);
0043
0044 exit(-1);
0045 }
0046 else {
0047 close(pipe_fd[1]);
0048 }
0049
0050
0051 m_loc_count = 1;
0052 m_mapping.clear();
0053
0054
0055 FILE* infile = fdopen(pipe_fd[0], "r");
0056
0057 const size_t buffer_size = 300;
0058 char buffer[buffer_size];
0059
0060 while (fgets(buffer, buffer_size, infile) != nullptr) {
0061 if (buffer[0] == '#') continue;
0062 Row row;
0063 int count = sscanf(buffer, "%zu,%zu,%zu,%zu", &row.cpu_id, &row.core_id, &row.numa_domain_id, &row.socket_id);
0064 if (count == 4) {
0065 switch (m_locality_strategy) {
0066 case LocalityStrategy::CpuLocal: row.location_id = row.cpu_id; break;
0067 case LocalityStrategy::CoreLocal: row.location_id = row.core_id; break;
0068 case LocalityStrategy::NumaDomainLocal: row.location_id = row.numa_domain_id; break;
0069 case LocalityStrategy::SocketLocal: row.location_id = row.socket_id; break;
0070 case LocalityStrategy::Global:
0071 default: row.location_id = 0; break;
0072 }
0073 if (row.location_id >= m_loc_count) {
0074
0075 m_loc_count = row.location_id + 1;
0076 }
0077 m_mapping.push_back(row);
0078 }
0079 else {
0080
0081 int count = sscanf(buffer, "%zu,%zu,,%zu", &row.cpu_id, &row.core_id, &row.socket_id);
0082 row.numa_domain_id = row.socket_id;
0083 if (count == 3) {
0084 switch (m_locality_strategy) {
0085 case LocalityStrategy::CpuLocal: row.location_id = row.cpu_id; break;
0086 case LocalityStrategy::CoreLocal: row.location_id = row.core_id; break;
0087 case LocalityStrategy::NumaDomainLocal: row.location_id = row.numa_domain_id; break;
0088 case LocalityStrategy::SocketLocal: row.location_id = row.socket_id; break;
0089 case LocalityStrategy::Global:
0090 default: row.location_id = 0; break;
0091 }
0092 if (row.location_id >= m_loc_count) {
0093
0094 m_loc_count = row.location_id + 1;
0095 }
0096 m_mapping.push_back(row);
0097 }
0098
0099 }
0100 }
0101 fclose(infile);
0102 int status = 0;
0103 waitpid(pid, &status, 0);
0104
0105 if (!WIFEXITED(status)) {
0106 m_error_msg = "lscpu child process returned abnormally";
0107 return;
0108 }
0109 else if (WEXITSTATUS(status) != 0) {
0110 m_error_msg = "lscpu child process returned with an exit code of " + std::to_string(WEXITSTATUS(status));
0111 return;
0112 }
0113 else if (m_mapping.empty()){
0114 m_error_msg = "Unable to parse lscpu output";
0115 return;
0116 }
0117
0118
0119 switch (m_affinity_strategy) {
0120
0121 case AffinityStrategy::ComputeBound:
0122
0123 std::stable_sort(m_mapping.begin(), m_mapping.end(),
0124 [](const Row& lhs, const Row& rhs) -> bool { return lhs.cpu_id < rhs.cpu_id; });
0125 break;
0126
0127 case AffinityStrategy::MemoryBound:
0128
0129 std::stable_sort(m_mapping.begin(), m_mapping.end(),
0130 [](const Row& lhs, const Row& rhs) -> bool { return lhs.cpu_id < rhs.cpu_id; });
0131
0132 std::stable_sort(m_mapping.begin(), m_mapping.end(),
0133 [](const Row& lhs, const Row& rhs) -> bool { return lhs.numa_domain_id < rhs.numa_domain_id; });
0134 break;
0135
0136 default:
0137 break;
0138 }
0139
0140
0141 m_initialized = true;
0142 }
0143
0144 std::ostream& operator<<(std::ostream& os, const JProcessorMapping::AffinityStrategy& s) {
0145 switch (s) {
0146 case JProcessorMapping::AffinityStrategy::ComputeBound: os << "compute-bound (favor fewer hyperthreads)"; break;
0147 case JProcessorMapping::AffinityStrategy::MemoryBound: os << "memory-bound (favor fewer NUMA domains)"; break;
0148 case JProcessorMapping::AffinityStrategy::None: os << "none"; break;
0149 }
0150 return os;
0151 }
0152
0153
0154 std::ostream& operator<<(std::ostream& os, const JProcessorMapping::LocalityStrategy& s) {
0155 switch (s) {
0156 case JProcessorMapping::LocalityStrategy::CpuLocal: os << "cpu-local"; break;
0157 case JProcessorMapping::LocalityStrategy::CoreLocal: os << "core-local"; break;
0158 case JProcessorMapping::LocalityStrategy::NumaDomainLocal: os << "numa-domain-local"; break;
0159 case JProcessorMapping::LocalityStrategy::SocketLocal: os << "socket-local"; break;
0160 case JProcessorMapping::LocalityStrategy::Global: os << "global"; break;
0161 }
0162 return os;
0163 }
0164
0165
0166 std::ostream& operator<<(std::ostream& os, const JProcessorMapping& m) {
0167
0168 os << "NUMA Configuration: " << "affinity=" << m.m_affinity_strategy << ", locality=" << m.m_locality_strategy;
0169 if (m.m_locality_strategy != JProcessorMapping::LocalityStrategy::Global) {
0170 os << " (" << m.m_loc_count << " locations)";
0171 }
0172
0173 if (m.m_initialized) {
0174 os << std::endl;
0175 JTablePrinter table;
0176 table.AddColumn("worker", JTablePrinter::Justify::Right);
0177 table.AddColumn("location", JTablePrinter::Justify::Right);
0178 table.AddColumn("cpu", JTablePrinter::Justify::Right);
0179 table.AddColumn("core", JTablePrinter::Justify::Right);
0180 table.AddColumn("numa node", JTablePrinter::Justify::Right);
0181 table.AddColumn("socket", JTablePrinter::Justify::Right);
0182
0183 size_t worker_id = 0;
0184 for (const JProcessorMapping::Row& row : m.m_mapping) {
0185 table | worker_id++ | row.location_id | row.cpu_id | row.core_id | row.numa_domain_id | row.socket_id;
0186 }
0187 table.Render(os);
0188 }
0189 else if (!m.m_error_msg.empty()) {
0190 os << std::endl << " Error: " << m.m_error_msg << std::endl;
0191 }
0192 return os;
0193 }