Skip to content

Commit

Permalink
Merge pull request #1658 from ekinanp/master
Browse files Browse the repository at this point in the history
Merge 3.9.x -> master
  • Loading branch information
Sean P McDonald committed Oct 4, 2017
2 parents 126e6e4 + babaaab commit 88b7b46
Show file tree
Hide file tree
Showing 6 changed files with 736 additions and 26 deletions.
32 changes: 32 additions & 0 deletions lib/inc/internal/facts/linux/processor_resolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,44 @@ namespace facter { namespace facts { namespace linux {
struct processor_resolver : posix::processor_resolver
{
protected:
/**
* The architecture type of the linux machine.
*/
enum class ArchitectureType {POWER, X86};

/**
* The check consists of the following.
* (1) Check the previously computed isa fact. If it starts with
* ppc64, then we have a power machine.
*
* (2) If (1) is empty (possible because exec might have failed to obtain
* the isa fact), then we use /proc/cpuinfo by checking whether that file
* contains the "cpu", "clock", and "revision" keys -- these keys are only
* found in Power machines.
*
* @param data The currently collected data
* @param root Path to the root directory of the system
* @return Returns the architecture type of the machine
*/
ArchitectureType architecture_type(data const& data, std::string const& root);

/**
* Adds the cpu-specific data to the currently collected data.
* @param data The currently collected data
* @param root Path to the root directory of the system
*/
void add_cpu_data(data& data, std::string const& root = "");

/**
* Collects the resolver data.
* @param facts The fact collection that is resolving facts.
* @return Returns the resolver data.
*/
virtual data collect_data(collection& facts) override;

private:
void add_x86_cpu_data(data& data, bool have_counts, std::string const& root = "");
void add_power_cpu_data(data& data, bool have_counts, std::string const& root = "");
};

}}} // namespace facter::facts::linux
142 changes: 116 additions & 26 deletions lib/src/facts/linux/processor_resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <facter/facts/scalar_value.hpp>
#include <leatherman/file_util/file.hpp>
#include <leatherman/file_util/directory.hpp>
#include <leatherman/util/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <unordered_set>
Expand All @@ -13,65 +14,154 @@ using namespace std;
using namespace boost::filesystem;

namespace lth_file = leatherman::file_util;
namespace lth_util = leatherman::util;

namespace facter { namespace facts { namespace linux {
static bool split_line(string const& line, string& key, string& value) {
// Split the line on colon
auto pos = line.find(":");
if (pos == string::npos) {
return false;
}
key = line.substr(0, pos);
boost::trim(key);
value = line.substr(pos + 1);
boost::trim(value);

processor_resolver::data processor_resolver::collect_data(collection& facts)
return true;
}

processor_resolver::ArchitectureType processor_resolver::architecture_type(data const& data, std::string const& root)
{
auto result = posix::processor_resolver::collect_data(facts);
if (!data.isa.empty()) {
return (boost::starts_with(data.isa, "ppc64")) ? ArchitectureType::POWER : ArchitectureType::X86;
}

unordered_set<string> cpus;
lth_file::each_subdirectory("/sys/devices/system/cpu", [&](string const& cpu_directory) {
++result.logical_count;
string id = lth_file::read((path(cpu_directory) / "/topology/physical_package_id").string());
boost::trim(id);
if (id.empty() || cpus.emplace(move(id)).second) {
// Haven't seen this processor before
++result.physical_count;
// use /proc/cpuinfo
unordered_set<string> to_be_seen;
bool seen_all = false;
lth_file::each_line(root + "/proc/cpuinfo", [&](string& line) {
// if we already know that we're on a Power machine, we can just skip
// the remaining lines
if (seen_all) {
return false;
}

string key, value;
if (!split_line(line, key, value)) {
return true;
}

if (key == "processor") {
to_be_seen = unordered_set<string>{{"cpu", "clock", "revision"}};
} else if (find(to_be_seen.begin(), to_be_seen.end(), key) != to_be_seen.end()) {
to_be_seen.erase(key);
seen_all = to_be_seen.empty();
}
return true;
}, "^cpu\\d+$");
});

return seen_all ? ArchitectureType::POWER : ArchitectureType::X86;
}

// To determine model information, parse /proc/cpuinfo
bool have_counts = result.logical_count > 0;
void processor_resolver::add_x86_cpu_data(data& data, bool have_counts, std::string const& root)
{
unordered_set<string> cpus;
string id;
lth_file::each_line("/proc/cpuinfo", [&](string& line) {
// Split the line on colon
auto pos = line.find(":");
if (pos == string::npos) {
lth_file::each_line(root + "/proc/cpuinfo", [&](string& line) {
string key, value;
if (!split_line(line, key, value)) {
return true;
}
string key = line.substr(0, pos);
boost::trim(key);
string value = line.substr(pos + 1);
boost::trim(value);

if (key == "processor") {
// Start of a logical processor
id = move(value);
if (!have_counts) {
++result.logical_count;
++data.logical_count;
}
} else if (!id.empty() && key == "model name") {
// Add the model for this logical processor
result.models.emplace_back(move(value));
data.models.emplace_back(move(value));
} else if (!have_counts && key == "physical id" && cpus.emplace(move(value)).second) {
// Couldn't determine physical count from sysfs, but CPU topology is present, so use it
++result.physical_count;
++data.physical_count;
}
return true;
});
}

void processor_resolver::add_power_cpu_data(data& data, bool have_counts, std::string const& root)
{
unordered_set<string> cpus;
string id;
lth_file::each_line(root + "/proc/cpuinfo", [&](string& line) {
string key, value;
if (!split_line(line, key, value)) {
return true;
}

if (key == "processor") {
// Start of a logical processor
id = move(value);
if (!have_counts) {
++data.logical_count;
}
} else if (!id.empty() && key == "cpu") {
// Add the model for this logical processor
data.models.emplace_back(move(value));
} else if (key == "clock" && data.speed == 0) {
// Parse out the processor speed (in MHz)
string speed;
if (lth_util::re_search(value, boost::regex("(\\d+).*MHz"), &speed)) {
data.speed = stoi(speed) * static_cast<int64_t>(1000);
}
}
return true;
});
}

void processor_resolver::add_cpu_data(data& data, std::string const& root)
{
unordered_set<string> cpus;
lth_file::each_subdirectory(root + "/sys/devices/system/cpu", [&](string const& cpu_directory) {
++data.logical_count;
string id = lth_file::read((path(cpu_directory) / "/topology/physical_package_id").string());
boost::trim(id);
if (id.empty() || cpus.emplace(move(id)).second) {
// Haven't seen this processor before
++data.physical_count;
}
return true;
}, "^cpu\\d+$");

bool have_counts = data.logical_count > 0;

if (architecture_type(data, root) == ArchitectureType::X86) {
add_x86_cpu_data(data, have_counts, root);
} else {
add_power_cpu_data(data, have_counts, root);
}

if (data.speed != 0) {
return;
}

// Read in the max speed from the first cpu
// The speed is in kHz
string speed = lth_file::read("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
string speed = lth_file::read(root + "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
if (!speed.empty()) {
try {
result.speed = stoi(speed) * static_cast<int64_t>(1000);
data.speed = stoi(speed) * static_cast<int64_t>(1000);
} catch (invalid_argument&) {
}
}
}

processor_resolver::data processor_resolver::collect_data(collection& facts)
{
auto result = posix::processor_resolver::collect_data(facts);
add_cpu_data(result);
return result;
}

Expand Down
2 changes: 2 additions & 0 deletions lib/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
"facts/linux/dmi_resolver.cc"
"facts/linux/filesystem_resolver.cc"
"facts/linux/virtualization_resolver.cc"
"facts/linux/processor_fixture.cc"
"facts/linux/processor_resolver.cc"
"util/bsd/scoped_ifaddrs.cc"
)
endif()
Expand Down

0 comments on commit 88b7b46

Please sign in to comment.