Commit 45e42f63 authored by Sean McBride's avatar Sean McBride Committed by Brad King
Browse files

SystemInformation: Improve ParseSysCtl error checking

- ensure the return value of every sysctlbyname call is checked.
  On Apple Silicon aka arm64 some of them do return an error,
  for example hw.cpufrequency, and we were getting nonsense values.
- when sysctlbyname returns an error, always provide a fallback value
- be a bit more paranoid about leaving space for null termination in temp buf
- corrected "machdep.cpu.model" and "machdep.cpu.stepping" from int64 to int32,
  as documented.
- added Apple to the Manufacturer enum
parent c672435e
......@@ -448,6 +448,7 @@ public:
HP,
Hygon,
Zhaoxin,
Apple,
UnknownManufacturer
};
......@@ -1752,6 +1753,8 @@ const char* SystemInformationImplementation::GetVendorID()
return "Chengdu Haiguang IC Design Co., Ltd.";
case Zhaoxin:
return "Shanghai Zhaoxin Semiconductor Co., Ltd.";
case Apple:
return "Apple";
case UnknownManufacturer:
default:
return "Unknown Manufacturer";
......@@ -2135,6 +2138,8 @@ void SystemInformationImplementation::FindManufacturer(
this->ChipManufacturer = Motorola; // Motorola Microelectronics
else if (family.compare(0, 7, "PA-RISC") == 0)
this->ChipManufacturer = HP; // Hewlett-Packard
else if (this->ChipID.Vendor == "Apple")
this->ChipManufacturer = Apple; // Apple
else
this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
}
......@@ -4503,33 +4508,62 @@ unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() const
return this->NumberOfPhysicalCPU;
}
/** For Mac use sysctlbyname calls to find system info */
#if defined(__APPLE__)
static int kw_sysctlbyname_int32(const char* name, int32_t* value)
{
size_t len = sizeof(int32_t);
int err = sysctlbyname(name, value, &len, nullptr, 0);
if (err == 0) {
assert(len == sizeof(int32_t));
}
return err;
}
static int kw_sysctlbyname_int64(const char* name, int64_t* value)
{
size_t len = sizeof(int64_t);
int err = sysctlbyname(name, value, &len, nullptr, 0);
if (err == 0) {
assert(len == sizeof(int64_t));
}
return err;
}
#endif
/** For Apple use sysctlbyname calls to find system info */
bool SystemInformationImplementation::ParseSysCtl()
{
#if defined(__APPLE__)
char retBuf[128];
char tempBuff[128];
int32_t tempInt32 = 0;
int64_t tempInt64 = 0;
int err = 0;
uint64_t value = 0;
size_t len = sizeof(value);
sysctlbyname("hw.memsize", &value, &len, nullptr, 0);
this->TotalPhysicalMemory = static_cast<size_t>(value / 1048576);
size_t len;
this->TotalPhysicalMemory = 0;
err = kw_sysctlbyname_int64("hw.memsize", &tempInt64);
if (err == 0) {
this->TotalPhysicalMemory = static_cast<size_t>(tempInt64 / 1024 / 1024);
}
// Parse values for Mac
this->AvailablePhysicalMemory = 0;
vm_statistics_data_t vmstat;
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat,
&count) == KERN_SUCCESS) {
len = sizeof(value);
err = sysctlbyname("hw.pagesize", &value, &len, nullptr, 0);
int64_t available_memory =
(vmstat.free_count + vmstat.inactive_count) * value;
this->AvailablePhysicalMemory =
static_cast<size_t>(available_memory / 1048576);
err = kw_sysctlbyname_int64("hw.pagesize", &tempInt64);
if (err == 0) {
int64_t available_memory =
(vmstat.free_count + vmstat.inactive_count) * tempInt64;
this->AvailablePhysicalMemory =
static_cast<size_t>(available_memory / 1024 / 1024);
}
}
# ifdef VM_SWAPUSAGE
// Virtual memory.
this->AvailableVirtualMemory = 0;
this->TotalVirtualMemory = 0;
# ifdef VM_SWAPUSAGE
int mib[2] = { CTL_VM, VM_SWAPUSAGE };
unsigned int miblen =
static_cast<unsigned int>(sizeof(mib) / sizeof(mib[0]));
......@@ -4538,78 +4572,98 @@ bool SystemInformationImplementation::ParseSysCtl()
err = sysctl(mib, miblen, &swap, &len, nullptr, 0);
if (err == 0) {
this->AvailableVirtualMemory =
static_cast<size_t>(swap.xsu_avail / 1048576);
this->TotalVirtualMemory = static_cast<size_t>(swap.xsu_total / 1048576);
static_cast<size_t>(swap.xsu_avail / 1024 / 1024);
this->TotalVirtualMemory =
static_cast<size_t>(swap.xsu_total / 1024 / 1024);
}
# else
this->AvailableVirtualMemory = 0;
this->TotalVirtualMemory = 0;
# endif
// CPU Info
len = sizeof(this->NumberOfPhysicalCPU);
sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, nullptr, 0);
len = sizeof(this->NumberOfLogicalCPU);
sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, nullptr, 0);
int cores_per_package = 0;
len = sizeof(cores_per_package);
err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len,
nullptr, 0);
// That name was not found, default to 1
this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
err != 0 ? 1 : static_cast<unsigned char>(cores_per_package);
this->NumberOfPhysicalCPU = 1;
err = kw_sysctlbyname_int32("hw.physicalcpu", &tempInt32);
if (err == 0) {
this->NumberOfPhysicalCPU = tempInt32;
}
len = sizeof(value);
sysctlbyname("hw.cpufrequency", &value, &len, nullptr, 0);
this->CPUSpeedInMHz = static_cast<float>(value) / 1000000;
this->NumberOfLogicalCPU = 1;
err = kw_sysctlbyname_int32("hw.logicalcpu", &tempInt32);
if (err == 0) {
this->NumberOfLogicalCPU = tempInt32;
}
this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = 1;
err = kw_sysctlbyname_int32("machdep.cpu.cores_per_package", &tempInt32);
if (err == 0) {
this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = tempInt32;
}
this->CPUSpeedInMHz = 0;
err = kw_sysctlbyname_int64("hw.cpufrequency", &tempInt64);
if (err == 0) {
this->CPUSpeedInMHz = static_cast<float>(tempInt64) / 1000000.0f;
}
// Chip family
len = sizeof(this->ChipID.Family);
// Seems only the intel chips will have this name so if this fails it is
// probably a PPC machine
err =
sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, nullptr, 0);
// Seems only the Intel chips will have this name so if this fails it is
// a PowerPC or ARM, or something unknown
this->ChipID.Vendor = "";
this->ChipID.Family = 0;
this->ChipID.Model = 0;
this->ChipID.Revision = 0;
err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
if (err != 0) // Go back to names we know but are less descriptive
{
this->ChipID.Family = 0;
::memset(retBuf, 0, 128);
len = 32;
err = sysctlbyname("hw.machine", &retBuf, &len, nullptr, 0);
std::string machineBuf(retBuf);
if (machineBuf.find_first_of("Power") != std::string::npos) {
this->ChipID.Vendor = "IBM";
len = sizeof(this->ChipID.Family);
err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, nullptr, 0);
len = sizeof(this->ChipID.Model);
err =
sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, nullptr, 0);
this->FindManufacturer();
::memset(tempBuff, 0, sizeof(tempBuff));
len = sizeof(tempBuff) - 1; // leave a byte for null termination
err = sysctlbyname("hw.machine", &tempBuff, &len, nullptr, 0);
if (err == 0) {
std::string machineBuf(tempBuff);
if (machineBuf.find_first_of("Power") != std::string::npos) {
this->ChipID.Vendor = "IBM";
err = kw_sysctlbyname_int32("hw.cputype", &tempInt32);
if (err == 0) {
this->ChipID.Family = tempInt32;
}
err = kw_sysctlbyname_int32("hw.cpusubtype", &tempInt32);
if (err == 0) {
this->ChipID.Model = tempInt32;
}
this->FindManufacturer();
} else if (machineBuf.find_first_of("arm64") != std::string::npos) {
this->ChipID.Vendor = "Apple";
this->FindManufacturer();
}
}
} else {
// Should be an Intel Chip.
err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
if (err == 0) {
this->ChipID.Family = tempInt32;
}
} else // Should be an Intel Chip.
{
len = sizeof(this->ChipID.Family);
err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len,
nullptr, 0);
::memset(retBuf, 0, 128);
len = 128;
err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, nullptr, 0);
// Chip Vendor
this->ChipID.Vendor = retBuf;
::memset(tempBuff, 0, sizeof(tempBuff));
len = sizeof(tempBuff) - 1; // leave a byte for null termination
err = sysctlbyname("machdep.cpu.vendor", tempBuff, &len, nullptr, 0);
if (err == 0) {
this->ChipID.Vendor = tempBuff;
}
this->FindManufacturer();
// Chip Model
len = sizeof(value);
err = sysctlbyname("machdep.cpu.model", &value, &len, nullptr, 0);
this->ChipID.Model = static_cast<int>(value);
err = kw_sysctlbyname_int32("machdep.cpu.model", &tempInt32);
if (err == 0) {
this->ChipID.Model = tempInt32;
}
// Chip Stepping
len = sizeof(value);
value = 0;
err = sysctlbyname("machdep.cpu.stepping", &value, &len, nullptr, 0);
if (!err) {
this->ChipID.Revision = static_cast<int>(value);
err = kw_sysctlbyname_int32("machdep.cpu.stepping", &tempInt32);
if (err == 0) {
this->ChipID.Revision = tempInt32;
}
// feature string
......@@ -4632,36 +4686,36 @@ bool SystemInformationImplementation::ParseSysCtl()
len = allocSize - 2; // keep space for leading and trailing space
err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0);
}
if (!err && buf && len) {
if (err == 0 && buf && len) {
// now we can match every flags as space + flag + space
buf[len + 1] = ' ';
std::string cpuflags(buf, len + 2);
if ((cpuflags.find(" FPU ") != std::string::npos)) {
if (cpuflags.find(" FPU ") != std::string::npos) {
this->Features.HasFPU = true;
}
if ((cpuflags.find(" TSC ") != std::string::npos)) {
if (cpuflags.find(" TSC ") != std::string::npos) {
this->Features.HasTSC = true;
}
if ((cpuflags.find(" MMX ") != std::string::npos)) {
if (cpuflags.find(" MMX ") != std::string::npos) {
this->Features.HasMMX = true;
}
if ((cpuflags.find(" SSE ") != std::string::npos)) {
if (cpuflags.find(" SSE ") != std::string::npos) {
this->Features.HasSSE = true;
}
if ((cpuflags.find(" SSE2 ") != std::string::npos)) {
if (cpuflags.find(" SSE2 ") != std::string::npos) {
this->Features.HasSSE2 = true;
}
if ((cpuflags.find(" APIC ") != std::string::npos)) {
if (cpuflags.find(" APIC ") != std::string::npos) {
this->Features.HasAPIC = true;
}
if ((cpuflags.find(" CMOV ") != std::string::npos)) {
if (cpuflags.find(" CMOV ") != std::string::npos) {
this->Features.HasCMOV = true;
}
if ((cpuflags.find(" MTRR ") != std::string::npos)) {
if (cpuflags.find(" MTRR ") != std::string::npos) {
this->Features.HasMTRR = true;
}
if ((cpuflags.find(" ACPI ") != std::string::npos)) {
if (cpuflags.find(" ACPI ") != std::string::npos) {
this->Features.HasACPI = true;
}
}
......@@ -4669,21 +4723,29 @@ bool SystemInformationImplementation::ParseSysCtl()
}
// brand string
::memset(retBuf, 0, sizeof(retBuf));
len = sizeof(retBuf);
err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, nullptr, 0);
if (!err) {
this->ChipID.ProcessorName = retBuf;
this->ChipID.ModelName = retBuf;
this->ChipID.ProcessorName = "";
this->ChipID.ModelName = "";
::memset(tempBuff, 0, sizeof(tempBuff));
len = sizeof(tempBuff) - 1; // leave a byte for null termination
err = sysctlbyname("machdep.cpu.brand_string", tempBuff, &len, nullptr, 0);
if (err == 0) {
this->ChipID.ProcessorName = tempBuff;
this->ChipID.ModelName = tempBuff;
}
// Cache size
len = sizeof(value);
err = sysctlbyname("hw.l1icachesize", &value, &len, nullptr, 0);
this->Features.L1CacheSize = static_cast<int>(value);
len = sizeof(value);
err = sysctlbyname("hw.l2cachesize", &value, &len, nullptr, 0);
this->Features.L2CacheSize = static_cast<int>(value);
// L1 Cache size
this->Features.L1CacheSize = 0;
err = kw_sysctlbyname_int64("hw.l1icachesize", &tempInt64);
if (err == 0) {
this->Features.L1CacheSize = static_cast<int>(tempInt64);
}
// L2 Cache size
this->Features.L2CacheSize = 0;
err = kw_sysctlbyname_int64("hw.l2cachesize", &tempInt64);
if (err == 0) {
this->Features.L2CacheSize = static_cast<int>(tempInt64);
}
return true;
#else
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment