|
5 | 5 | #include <sched.h> |
6 | 6 | #include <unistd.h> |
7 | 7 |
|
| 8 | +#include <filesystem> |
| 9 | +#include <fstream> |
| 10 | +#include <istream> |
| 11 | +#include <sstream> |
| 12 | +#include <string> |
| 13 | + |
8 | 14 | #include "log.h" |
9 | 15 |
|
10 | 16 | using namespace std; |
11 | 17 |
|
12 | 18 | namespace rr { |
13 | 19 |
|
| 20 | +static bool hybrid_cpu_arch_parse_cpus(const filesystem::path& dir, |
| 21 | + CPUGroup* group) { |
| 22 | + ifstream file(dir / "cpus"); |
| 23 | + if (!file.good()) { |
| 24 | + LOG(warn) << "File " << dir.string() << "/cpus not found"; |
| 25 | + return false; |
| 26 | + } |
| 27 | + ostringstream sstr; |
| 28 | + sstr << file.rdbuf(); |
| 29 | + string s = sstr.str(); |
| 30 | + while (!s.empty() && s[s.size() - 1] == '\n') { |
| 31 | + s.resize(s.size() - 1); |
| 32 | + } |
| 33 | + size_t dash = s.find('-'); |
| 34 | + if (dash == string::npos) { |
| 35 | + size_t end; |
| 36 | + group->start_cpu = stoi(s, &end); |
| 37 | + if (end != s.size()) { |
| 38 | + LOG(warn) << "Bad CPU index"; |
| 39 | + return false; |
| 40 | + } |
| 41 | + group->end_cpu = group->start_cpu + 1; |
| 42 | + return true; |
| 43 | + } |
| 44 | + size_t end; |
| 45 | + group->start_cpu = stoi(s.substr(0, dash), &end); |
| 46 | + if (end != dash) { |
| 47 | + LOG(warn) << "Bad CPU index"; |
| 48 | + return false; |
| 49 | + } |
| 50 | + int last_cpu = stoi(s.substr(dash + 1), &end); |
| 51 | + if (end != s.size() - (dash + 1)) { |
| 52 | + LOG(warn) << "Bad end CPU index"; |
| 53 | + return false; |
| 54 | + } |
| 55 | + group->end_cpu = last_cpu + 1; |
| 56 | + return true; |
| 57 | +} |
| 58 | + |
| 59 | +static bool hybrid_cpu_arch_parse_type(const filesystem::path& dir, |
| 60 | + CPUGroup* group) { |
| 61 | + // See https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/intel-hybrid.txt |
| 62 | + ifstream file(dir / "type"); |
| 63 | + if (!file.good()) { |
| 64 | + LOG(warn) << "File " << dir.string() << "/type not found"; |
| 65 | + return false; |
| 66 | + } |
| 67 | + ostringstream sstr; |
| 68 | + sstr << file.rdbuf(); |
| 69 | + string s = sstr.str(); |
| 70 | + while (!s.empty() && s[s.size() - 1] == '\n') { |
| 71 | + s.resize(s.size() - 1); |
| 72 | + } |
| 73 | + size_t end; |
| 74 | + group->type = stoi(s, &end); |
| 75 | + if (end != s.size()) { |
| 76 | + LOG(warn) << "Bad type"; |
| 77 | + return false; |
| 78 | + } |
| 79 | + return true; |
| 80 | +} |
| 81 | + |
| 82 | +// Returns an empty list on many (all?) systems that aren't using hybrid cores. |
| 83 | +// In that case, assume all CPUs have the same microarch. |
| 84 | +static vector<CPUGroup> hybrid_cpu_arch_groups() { |
| 85 | + vector<CPUGroup> result; |
| 86 | + filesystem::path dir_path = "/sys/devices"; |
| 87 | + if (!filesystem::is_directory(dir_path)) { |
| 88 | + return result; |
| 89 | + } |
| 90 | + for (const auto& entry : filesystem::directory_iterator(dir_path)) { |
| 91 | + auto file_name = entry.path().filename().string(); |
| 92 | + if (file_name.find("cpu_") != 0) { |
| 93 | + continue; |
| 94 | + } |
| 95 | + CPUGroup group; |
| 96 | + group.name = file_name.substr(4); |
| 97 | + if (!hybrid_cpu_arch_parse_cpus(entry.path(), &group)) { |
| 98 | + continue; |
| 99 | + } |
| 100 | + if (!hybrid_cpu_arch_parse_type(entry.path(), &group)) { |
| 101 | + continue; |
| 102 | + } |
| 103 | + if (group.name == "core") { |
| 104 | + group.kind = CPUGroup::P_CORE; |
| 105 | + } else if (group.name == "atom" || group.name == "lowpower") { |
| 106 | + group.kind = CPUGroup::E_CORE; |
| 107 | + } else { |
| 108 | + group.kind = CPUGroup::UNKNOWN; |
| 109 | + } |
| 110 | + result.push_back(std::move(group)); |
| 111 | + } |
| 112 | + return result; |
| 113 | +} |
| 114 | + |
14 | 115 | const CPUs& CPUs::get() { |
15 | 116 | static CPUs singleton; |
16 | 117 | return singleton; |
@@ -56,6 +157,7 @@ CPUs::CPUs() { |
56 | 157 | if (ret < 0) { |
57 | 158 | FATAL() << "failed to get initial affinity"; |
58 | 159 | } |
| 160 | + cpu_groups_ = hybrid_cpu_arch_groups(); |
59 | 161 | } |
60 | 162 |
|
61 | 163 | } |
|
0 commit comments