summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Russell <gabriel.russell@mongodb.com>2020-08-26 11:42:31 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-10-03 02:12:09 +0000
commit1c3598b62c98a5e33292db4daf81994bef1e7824 (patch)
tree5541b6bc5fe0ead1deaf2b81ebb2335089d1c1d7
parentd8ed47db10e21e648ff7486827a7e779335a35a4 (diff)
downloadmongo-1c3598b62c98a5e33292db4daf81994bef1e7824.tar.gz
SERVER-50123 Record number of physical cores on all platforms
-rw-r--r--src/mongo/util/processinfo.h11
-rw-r--r--src/mongo/util/processinfo_linux.cpp145
-rw-r--r--src/mongo/util/processinfo_windows.cpp135
3 files changed, 194 insertions, 97 deletions
diff --git a/src/mongo/util/processinfo.h b/src/mongo/util/processinfo.h
index 732649d60b8..63f1515050d 100644
--- a/src/mongo/util/processinfo.h
+++ b/src/mongo/util/processinfo.h
@@ -99,13 +99,20 @@ public:
}
/**
- * Get the number of CPUs
+ * Get the number of (logical) CPUs
*/
static unsigned getNumCores() {
return sysInfo().numCores;
}
/**
+ * Get the number of physical CPUs
+ */
+ static unsigned getNumPhysicalCores() {
+ return sysInfo().numPhysicalCores;
+ }
+
+ /**
* Get the number of cores available. Make a best effort to get the cores for this process.
* If that information is not available, get the total number of CPUs.
*/
@@ -196,6 +203,7 @@ private:
unsigned long long memSize;
unsigned long long memLimit;
unsigned numCores;
+ unsigned numPhysicalCores;
unsigned long long pageSize;
std::string cpuArch;
bool hasNuma;
@@ -213,6 +221,7 @@ private:
memSize(0),
memLimit(0),
numCores(0),
+ numPhysicalCores(0),
pageSize(0),
hasNuma(false),
preferMsyncOverFSync(true) {
diff --git a/src/mongo/util/processinfo_linux.cpp b/src/mongo/util/processinfo_linux.cpp
index 639f0f57e82..b4b67c4b91b 100644
--- a/src/mongo/util/processinfo_linux.cpp
+++ b/src/mongo/util/processinfo_linux.cpp
@@ -35,6 +35,7 @@
#include <iostream>
#include <malloc.h>
+#include <pcrecpp.h>
#include <sched.h>
#include <stdio.h>
#include <sys/mman.h>
@@ -53,6 +54,7 @@
#include <boost/filesystem.hpp>
#include <boost/none.hpp>
#include <boost/optional.hpp>
+#include <fmt/format.h>
#include <pcrecpp.h>
#include "mongo/logv2/log.h"
@@ -63,18 +65,16 @@
namespace mongo {
+using namespace fmt::literals;
+
class LinuxProc {
public:
LinuxProc(ProcessId pid) {
- char name[128];
- sprintf(name, "/proc/%d/stat", pid.asUInt32());
-
- FILE* f = fopen(name, "r");
+ auto name = "/proc/{}/stat"_format(pid.asUInt32());
+ FILE* f = fopen(name.c_str(), "r");
if (!f) {
- std::stringstream ss;
- ss << "couldn't open [" << name << "] " << errnoWithDescription();
- std::string s = ss.str();
- msgasserted(13538, s.c_str());
+ auto e = errno;
+ msgasserted(13538, "couldn't open [{}] {}"_format(name, errnoWithDescription(e)));
}
int found = fscanf(f,
"%d %127s %c "
@@ -134,9 +134,7 @@ public:
&_rtprio, &_sched
*/
);
- if (found == 0) {
- LOGV2(677701, "system error: reading proc info");
- }
+ massert(13539, "couldn't parse [{}]"_format(name).c_str(), found != 0);
fclose(f);
}
@@ -313,6 +311,43 @@ void appendMountInfo(BSONObjBuilder& bob) {
}
}
+class CpuInfoParser {
+public:
+ struct LineProcessor {
+ std::string key;
+ std::function<void(const std::string&)> f;
+ };
+ std::vector<LineProcessor> lineProcessors;
+ std::function<void()> recordProcessor;
+ void run() {
+ std::ifstream f("/proc/cpuinfo");
+ if (!f)
+ return;
+
+ bool readSuccess;
+ bool unprocessed = false;
+ static StaticImmortal<pcrecpp::RE> lineRegex(R"re((.*?)\s*:\s*(.*))re");
+ do {
+ std::string fstr;
+ readSuccess = f && std::getline(f, fstr);
+ if (readSuccess && !fstr.empty()) {
+ std::string key;
+ std::string value;
+ if (!lineRegex->FullMatch(fstr, &key, &value))
+ continue;
+ for (auto&& [pk, pf] : lineProcessors) {
+ if (pk == key)
+ pf(value);
+ }
+ unprocessed = true;
+ } else if (unprocessed) {
+ recordProcessor();
+ unprocessed = false;
+ }
+ } while (readSuccess);
+ }
+};
+
} // namespace
class LinuxSysHelper {
@@ -333,30 +368,57 @@ public:
return fstr;
}
+
+ /**
+ * count the number of physical cores
+ */
+ static void getNumPhysicalCores(int& physicalCores) {
+
+ /* In /proc/cpuinfo core ids are only unique within a particular physical unit, AKA a cpu
+ * package, so to count the total cores we need to count the unique pairs of core id and
+ * physical id*/
+ struct CpuId {
+ std::string core;
+ std::string physical;
+ };
+
+ CpuId parsedCpuId;
+
+ auto cmp = [](auto&& a, auto&& b) {
+ auto tupLens = [](auto&& o) { return std::tie(o.core, o.physical); };
+ return tupLens(a) < tupLens(b);
+ };
+ std::set<CpuId, decltype(cmp)> cpuIds(cmp);
+
+ CpuInfoParser cpuInfoParser{
+ {
+ {"physical id", [&](const std::string& value) { parsedCpuId.physical = value; }},
+ {"core id", [&](const std::string& value) { parsedCpuId.core = value; }},
+ },
+ [&]() {
+ cpuIds.insert(parsedCpuId);
+ parsedCpuId = CpuId{};
+ }};
+ cpuInfoParser.run();
+
+ physicalCores = cpuIds.size();
+ }
+
/**
* Get some details about the CPU
*/
static void getCpuInfo(int& procCount, std::string& freq, std::string& features) {
- FILE* f;
- char fstr[1024] = {0};
- procCount = 0;
-
- f = fopen("/proc/cpuinfo", "r");
- if (f == nullptr)
- return;
- while (fgets(fstr, 1023, f) != nullptr && !feof(f)) {
- // until the end of the file
- fstr[strlen(fstr) < 1 ? 0 : strlen(fstr) - 1] = '\0';
- if (strncmp(fstr, "processor ", 10) == 0 || strncmp(fstr, "processor\t:", 11) == 0)
- ++procCount;
- if (strncmp(fstr, "cpu MHz\t\t:", 10) == 0)
- freq = fstr + 11;
- if (strncmp(fstr, "flags\t\t:", 8) == 0)
- features = fstr + 9;
- }
+ procCount = 0;
- fclose(f);
+ CpuInfoParser cpuInfoParser{
+ {
+ {"processor", [&](const std::string& value) { procCount++; }},
+ {"cpu MHz", [&](const std::string& value) { freq = value; }},
+ {"flags", [&](const std::string& value) { features = value; }},
+ },
+ []() {}};
+ cpuInfoParser.run();
}
/**
@@ -581,15 +643,18 @@ void ProcessInfo::SystemInfo::collectSystemInfo() {
std::string distroName, distroVersion;
std::string cpuFreq, cpuFeatures;
int cpuCount;
+ int physicalCores;
std::string verSig = LinuxSysHelper::readLineFromFile("/proc/version_signature");
LinuxSysHelper::getCpuInfo(cpuCount, cpuFreq, cpuFeatures);
+ LinuxSysHelper::getNumPhysicalCores(physicalCores);
LinuxSysHelper::getLinuxDistro(distroName, distroVersion);
if (uname(&unameData) == -1) {
+ auto e = errno;
LOGV2(23339,
- "Unable to collect detailed system information: {strerror_errno}",
- "strerror_errno"_attr = strerror(errno));
+ "Unable to collect detailed system information",
+ "error"_attr = errnoWithDescription(e));
}
osType = "Linux";
@@ -626,6 +691,7 @@ void ProcessInfo::SystemInfo::collectSystemInfo() {
bExtra.append("pageSize", static_cast<long long>(pageSize));
bExtra.append("numPages", static_cast<int>(sysconf(_SC_PHYS_PAGES)));
bExtra.append("maxOpenFiles", static_cast<int>(sysconf(_SC_OPEN_MAX)));
+ bExtra.append("physicalCores", physicalCores);
appendMountInfo(bExtra);
@@ -644,10 +710,9 @@ bool ProcessInfo::checkNumaEnabled() {
hasNumaMaps = boost::filesystem::exists("/proc/self/numa_maps");
} catch (boost::filesystem::filesystem_error& e) {
LOGV2(23340,
- "WARNING: Cannot detect if NUMA interleaving is enabled. Failed to probe "
- "\"{e_path1_string}\": {e_code_message}",
- "e_path1_string"_attr = e.path1().string(),
- "e_code_message"_attr = e.code().message());
+ "WARNING: Cannot detect if NUMA interleaving is enabled. Failed to probe",
+ "path"_attr = e.path1().string(),
+ "reason"_attr = e.code().message());
return false;
}
@@ -673,9 +738,8 @@ bool ProcessInfo::blockCheckSupported() {
bool ProcessInfo::blockInMemory(const void* start) {
unsigned char x = 0;
if (mincore(const_cast<void*>(alignToStartOfPage(start)), getPageSize(), &x)) {
- LOGV2(23341,
- "mincore failed: {errnoWithDescription}",
- "errnoWithDescription"_attr = errnoWithDescription());
+ auto e = errno;
+ LOGV2(23341, "mincore failed", "error"_attr = errnoWithDescription(e));
return 1;
}
return x & 0x1;
@@ -686,9 +750,8 @@ bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, std::vector<
if (mincore(const_cast<void*>(alignToStartOfPage(start)),
numPages * getPageSize(),
reinterpret_cast<unsigned char*>(&out->front()))) {
- LOGV2(23342,
- "mincore failed: {errnoWithDescription}",
- "errnoWithDescription"_attr = errnoWithDescription());
+ auto e = errno;
+ LOGV2(23342, "mincore failed", "error"_attr = errnoWithDescription(e));
return false;
}
for (size_t i = 0; i < numPages; ++i) {
diff --git a/src/mongo/util/processinfo_windows.cpp b/src/mongo/util/processinfo_windows.cpp
index b8a976fabcd..61c72aceca9 100644
--- a/src/mongo/util/processinfo_windows.cpp
+++ b/src/mongo/util/processinfo_windows.cpp
@@ -42,6 +42,65 @@
namespace mongo {
+namespace {
+
+using Slpi = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
+using SlpiBuf = std::aligned_storage_t<sizeof(Slpi)>;
+
+struct LpiRecords {
+ const Slpi* begin() const {
+ return reinterpret_cast<const Slpi*>(slpiRecords.get());
+ }
+
+ const Slpi* end() const {
+ return begin() + count;
+ }
+
+ std::unique_ptr<SlpiBuf[]> slpiRecords;
+ size_t count;
+};
+
+// Both the body of this getLogicalProcessorInformationRecords and the callers of
+// getLogicalProcessorInformationRecords are largely modeled off of the example code at
+// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation
+LpiRecords getLogicalProcessorInformationRecords() {
+
+ DWORD returnLength = 0;
+ LpiRecords lpiRecords{};
+
+ DWORD returnCode = 0;
+ do {
+ returnCode = GetLogicalProcessorInformation(
+ reinterpret_cast<Slpi*>(lpiRecords.slpiRecords.get()), &returnLength);
+ if (returnCode == FALSE) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ lpiRecords.slpiRecords = std::unique_ptr<SlpiBuf[]>(
+ new SlpiBuf[((returnLength - 1) / sizeof(Slpi)) + 1]);
+ } else {
+ DWORD gle = GetLastError();
+ LOGV2_WARNING(23811,
+ "GetLogicalProcessorInformation failed",
+ "error"_attr = errnoWithDescription(gle));
+ return LpiRecords{};
+ }
+ }
+ } while (returnCode == FALSE);
+
+
+ lpiRecords.count = returnLength / sizeof(Slpi);
+ return lpiRecords;
+}
+
+int getPhysicalCores() {
+ int processorCoreCount = 0;
+ for (auto&& lpi : getLogicalProcessorInformationRecords()) {
+ if (lpi.Relationship == RelationProcessorCore)
+ processorCoreCount++;
+ }
+ return processorCoreCount;
+}
+
+} // namespace
int _wconvertmtos(SIZE_T s) {
return (int)(s / (1024 * 1024));
}
@@ -72,9 +131,7 @@ int ProcessInfo::getVirtualMemorySize() {
BOOL status = GlobalMemoryStatusEx(&mse);
if (!status) {
DWORD gle = GetLastError();
- LOGV2_ERROR(23812,
- "GlobalMemoryStatusEx failed with {errnoWithDescription_gle}",
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
+ LOGV2_ERROR(23812, "GlobalMemoryStatusEx failed", "error"_attr = errnoWithDescription(gle));
fassert(28621, status);
}
@@ -88,9 +145,7 @@ int ProcessInfo::getResidentSize() {
BOOL status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
if (!status) {
DWORD gle = GetLastError();
- LOGV2_ERROR(23813,
- "GetProcessMemoryInfo failed with {errnoWithDescription_gle}",
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
+ LOGV2_ERROR(23813, "GetProcessMemoryInfo failed", "error"_attr = errnoWithDescription(gle));
fassert(28622, status);
}
@@ -122,22 +177,20 @@ bool getFileVersion(const char* filePath, DWORD& fileVersionMS, DWORD& fileVersi
DWORD verSize = GetFileVersionInfoSizeA(filePath, NULL);
if (verSize == 0) {
DWORD gle = GetLastError();
- LOGV2_WARNING(
- 23807,
- "GetFileVersionInfoSizeA on {filePath} failed with {errnoWithDescription_gle}",
- "filePath"_attr = filePath,
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
+ LOGV2_WARNING(23807,
+ "GetFileVersionInfoSizeA failed",
+ "path"_attr = filePath,
+ "error"_attr = errnoWithDescription(gle));
return false;
}
std::unique_ptr<char[]> verData(new char[verSize]);
if (GetFileVersionInfoA(filePath, NULL, verSize, verData.get()) == 0) {
DWORD gle = GetLastError();
- LOGV2_WARNING(
- 23808,
- "GetFileVersionInfoSizeA on {filePath} failed with {errnoWithDescription_gle}",
- "filePath"_attr = filePath,
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
+ LOGV2_WARNING(23808,
+ "GetFileVersionInfoSizeA failed",
+ "path"_attr = filePath,
+ "error"_attr = errnoWithDescription(gle));
return false;
}
@@ -146,16 +199,16 @@ bool getFileVersion(const char* filePath, DWORD& fileVersionMS, DWORD& fileVersi
if (VerQueryValueA(verData.get(), "\\", (LPVOID*)&verInfo, &size) == 0) {
DWORD gle = GetLastError();
LOGV2_WARNING(23809,
- "VerQueryValueA on {filePath} failed with {errnoWithDescription_gle}",
- "filePath"_attr = filePath,
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
+ "VerQueryValueA failed",
+ "path"_attr = filePath,
+ "error"_attr = errnoWithDescription(gle));
return false;
}
if (size != sizeof(VS_FIXEDFILEINFO)) {
LOGV2_WARNING(23810,
- "VerQueryValueA on {filePath} returned structure with unexpected size",
- "filePath"_attr = filePath);
+ "VerQueryValueA returned structure with unexpected size",
+ "path"_attr = filePath);
return false;
}
@@ -175,8 +228,10 @@ void ProcessInfo::SystemInfo::collectSystemInfo() {
GetNativeSystemInfo(&ntsysinfo);
addrSize = (ntsysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 64 : 32);
numCores = ntsysinfo.dwNumberOfProcessors;
+ numPhysicalCores = getPhysicalCores();
pageSize = static_cast<unsigned long long>(ntsysinfo.dwPageSize);
bExtra.append("pageSize", static_cast<long long>(pageSize));
+ bExtra.append("physicalCores", static_cast<int>(numPhysicalCores));
// get memory info
mse.dwLength = sizeof(mse);
@@ -270,43 +325,13 @@ void ProcessInfo::SystemInfo::collectSystemInfo() {
_extraStats = bExtra.obj();
}
-bool ProcessInfo::checkNumaEnabled() {
- typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
- DWORD returnLength = 0;
+bool ProcessInfo::checkNumaEnabled() {
DWORD numaNodeCount = 0;
- std::unique_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> buffer;
-
- DWORD returnCode = 0;
- do {
- returnCode = GetLogicalProcessorInformation(buffer.get(), &returnLength);
-
- if (returnCode == FALSE) {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- buffer.reset(reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>(
- new BYTE[returnLength]));
- } else {
- DWORD gle = GetLastError();
- LOGV2_WARNING(
- 23811,
- "GetLogicalProcessorInformation failed with {errnoWithDescription_gle}",
- "errnoWithDescription_gle"_attr = errnoWithDescription(gle));
- return false;
- }
- }
- } while (returnCode == FALSE);
-
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer.get();
-
- unsigned int byteOffset = 0;
- while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
- if (ptr->Relationship == RelationNumaNode) {
+ for (auto&& lpi : getLogicalProcessorInformationRecords()) {
+ if (lpi.Relationship == RelationNumaNode)
// Non-NUMA systems report a single record of this type.
- numaNodeCount++;
- }
-
- byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
- ptr++;
+ ++numaNodeCount;
}
// For non-NUMA machines, the count is 1