/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuCpuId.Linux.cpp Date: 2022-1-25 Author: Reece ***/ #include #include "AuHWInfo.hpp" #include "AuCpuInfo.hpp" #include "AuCpuInfo.Linux.hpp" #include #include #include namespace Aurora::HWInfo { static AuUInt32 ReadUInt(const AuString &path) { AuString contents; if (!AuIOFS::ReadString(path, contents)) { return 0; } char *endPtr; auto word = strtoll(contents.c_str(), &endPtr, 10); if (errno == ERANGE) { return 0; } return word; } static AuString ReadString(const AuString &path) { AuString contents; AuIOFS::ReadString(path, contents); return contents; } static void SetCaches() { gCpuInfo.dwCacheLine = ReadUInt("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size"); gCpuInfo.dwCacheL1 = ReadUInt("/sys/devices/system/cpu/cpu0/cache/index1/size"); gCpuInfo.dwCacheL2 = ReadUInt("/sys/devices/system/cpu/cpu0/cache/index2/size"); gCpuInfo.dwCacheL3 = ReadUInt("/sys/devices/system/cpu/cpu0/cache/index3/size"); } static void SetCpuA() { static const AuString kBasePath = "/sys/devices/system/cpu/"; AuList files; if (!AuIOFS::DirsInDirectory(kBasePath, files)) { return; } AuList> cpuThreads; cpuThreads.reserve(files.size()); std::sort(files.begin(), files.end()); for (auto & file : files) { if (AuStartsWith(file, "cpu")) { char *endPtr; auto word = strtoll(file.c_str() + 3, &endPtr, 10); if (errno == ERANGE) continue; if (*endPtr != '\x00') continue; cpuThreads.push_back(AuMakeTuple(word, file)); } } bool bIsHyperThreaded {}; for (auto &[threadId, coreStr] : cpuThreads) { auto cpuId = CpuBitId(threadId); auto coreID = ReadUInt(kBasePath + coreStr + "/topology/core_id"); auto cpuList = ReadString(kBasePath + coreStr + "/topology/core_cpus_list"); auto isHVCore = AuStringContains(cpuList, ","); if (!bIsHyperThreaded && isHVCore) { bIsHyperThreaded = true; } if (bIsHyperThreaded && !isHVCore) { gCpuInfo.maskECores.Add(cpuId); } else { gCpuInfo.maskPCores.Add(cpuId); gCpuInfo.pCoreTopology.push_back(cpuId); } if (coreID == threadId) { auto children = CpuBitId(); auto cores = AuSplitString(cpuList, ","); for (const auto core : cores) { char *endPtr; auto word = strtoll(core.data(), &endPtr, 10); if (errno == ERANGE) continue; children.Add(CpuBitId(word)); } gCpuInfo.uCores++; gCpuInfo.coreTopology.push_back(children); gCpuInfo.threadTopology.push_back(children.lower); } gCpuInfo.uThreads++; gCpuInfo.maskAllCores.Add(cpuId); } } void SetCpuTopologyLinux() { SetCaches(); SetCpuA(); gCpuInfo.uSocket = AuMax(gCpuInfo.uSocket, AuUInt8(1)); gCpuInfo.uCores = AuMax(gCpuInfo.uCores, AuUInt8(1)); gCpuInfo.uThreads = gCpuInfo.uThreads ? gCpuInfo.uThreads : get_nprocs(); } }