diff options
author | Gabriel Russell <gabriel.russell@mongodb.com> | 2020-08-26 11:42:31 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-10-03 02:12:09 +0000 |
commit | 1c3598b62c98a5e33292db4daf81994bef1e7824 (patch) | |
tree | 5541b6bc5fe0ead1deaf2b81ebb2335089d1c1d7 | |
parent | d8ed47db10e21e648ff7486827a7e779335a35a4 (diff) | |
download | mongo-1c3598b62c98a5e33292db4daf81994bef1e7824.tar.gz |
SERVER-50123 Record number of physical cores on all platforms
-rw-r--r-- | src/mongo/util/processinfo.h | 11 | ||||
-rw-r--r-- | src/mongo/util/processinfo_linux.cpp | 145 | ||||
-rw-r--r-- | src/mongo/util/processinfo_windows.cpp | 135 |
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 |