Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Apple M2 #14

Merged
merged 4 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions main.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <charconv>
#include <iomanip>
#include <iostream>

Expand All @@ -11,22 +12,33 @@ void usage(char* prog) {
std::cout << " -h : help" << std::endl;
std::cout << " -l : list all keys and values" << std::endl;
std::cout << " -v : version" << std::endl;
std::cout << " -n : tries to query the temperature sensors for n times (e.g. -n3)";
std::cout << " (1 second interval) until a valid value is returned" << std::endl;
}

int main(int argc, char *argv[]) {
int c;
extern char *optarg;
unsigned int attempts = 1;

kern_return_t result;
int op = smctemp::kOpNone;
smctemp::UInt32Char_t key = { 0 };
smctemp::SmcVal_t val;

while ((c = getopt(argc, argv, "clvh")) != -1) {
while ((c = getopt(argc, argv, "clvhn:")) != -1) {
switch(c) {
case 'c':
op = smctemp::kOpReadCpuTemp;
break;
case 'n':
if (optarg) {
auto [ptr, ec] = std::from_chars(optarg, optarg + strlen(optarg), attempts);
if (ec != std::errc()) {
std::cerr << "Invalid argument provided for -n (integer is required)" << std::endl;
return 1;
}
}
break;
case 'l':
op = smctemp::kOpList;
break;
Expand Down Expand Up @@ -60,7 +72,17 @@ int main(int argc, char *argv[]) {
}
break;
case smctemp::kOpReadCpuTemp:
std::cout << std::fixed << std::setprecision(1) << smc_temp.GetCpuTemp();
double temp = 0.0;
while (attempts > 0) {
temp = smc_temp.GetCpuTemp();
if (temp > 0.0) {
break;
} else {
usleep(1'000'000);
attempts--;
}
}
std::cout << std::fixed << std::setprecision(1) << temp;
break;
}

Expand Down
116 changes: 90 additions & 26 deletions smctemp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,26 @@
#include <iostream>
#include <limits>
#include <string>
#include <vector>

#include "smctemp_string.h"

#if defined(ARCH_TYPE_ARM64)
#include <sys/sysctl.h>
#include <algorithm>
#include <array>

namespace {
std::string getCPUModel() {
std::array<char, 512> buffer;
enen92 marked this conversation as resolved.
Show resolved Hide resolved
size_t bufferLength = buffer.size();
sysctlbyname("machdep.cpu.brand_string", buffer.data(), &bufferLength, nullptr, 0);
std::string cpuModel = buffer.data();
std::transform(cpuModel.begin(), cpuModel.end(), cpuModel.begin(), ::tolower);
return cpuModel;
}
}
#endif

// Cache the keyInfo to lower the energy impact of SmcReadKey() / SmcReadKey2()
#define KEY_INFO_CACHE_SIZE 100
namespace smctemp {
Expand Down Expand Up @@ -366,6 +382,24 @@ kern_return_t SmcAccessor::PrintAll() {
return kIOReturnSuccess;
}

double SmcTemp::CalculateAverageTemperature(const std::vector<std::string>& sensors,
const std::pair<unsigned int, unsigned int>& limits) {
double temp = 0.0;
size_t valid_sensor_count = 0;
for (auto sensor : sensors) {
auto sensor_value = smc_accessor_.ReadValue(sensor.c_str());
if (sensor_value >= limits.first &&
sensor_value <= limits.second) {
temp += sensor_value;
valid_sensor_count++;
}
}
if (valid_sensor_count > 0) {
temp /= valid_sensor_count;
}
return temp;
}

double SmcTemp::GetCpuTemp() {
double temp = 0.0;
#if defined(ARCH_TYPE_X86_64)
Expand All @@ -388,35 +422,65 @@ double SmcTemp::GetCpuTemp() {
return temp;
}
#elif defined(ARCH_TYPE_ARM64)
std::vector<std::string> sensors{
static_cast<std::string>(kSensorTp01),
static_cast<std::string>(kSensorTp05),
static_cast<std::string>(kSensorTp0d),
static_cast<std::string>(kSensorTp0h),
static_cast<std::string>(kSensorTp0l),
static_cast<std::string>(kSensorTp0p),
static_cast<std::string>(kSensorTp0x),
static_cast<std::string>(kSensorTp0b),
static_cast<std::string>(kSensorTp09),
static_cast<std::string>(kSensorTp0t),
};
for (auto sensor : sensors) {
temp += smc_accessor_.ReadValue(sensor.c_str());
std::vector<std::string> sensors;
std::vector<std::string> aux_sensors;
const std::pair<unsigned int, unsigned int> valid_temperature_limits{10, 120};

const std::string cpumodel = getCPUModel();
if (cpumodel.find("m2") != std::string::npos) { // Apple M2
// CPU core 1
sensors.emplace_back(static_cast<std::string>(kSensorTp01));
// CPU core 2
sensors.emplace_back(static_cast<std::string>(kSensorTp09));
// CPU core 3
sensors.emplace_back(static_cast<std::string>(kSensorTp0f));
// CPU core 4
sensors.emplace_back(static_cast<std::string>(kSensorTp0n));
// CPU core 5
sensors.emplace_back(static_cast<std::string>(kSensorTp05));
// CPU core 6
sensors.emplace_back(static_cast<std::string>(kSensorTp0d));
// CPU core 7
sensors.emplace_back(static_cast<std::string>(kSensorTp0j));
// CPU core 8
sensors.emplace_back(static_cast<std::string>(kSensorTp0r));
} else if (cpumodel.find("m1") != std::string::npos) { // Apple M1
// CPU performance core 1 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp01));
// CPU performance core 2 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp05));
// CPU performance core 3 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0d));
// CPU performance core 4 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0h));
// CPU performance core 5 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0l));
// CPU performance core 6 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0p));
// CPU performance core 7 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0x));
// CPU performance core 8 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0b));
// CPU efficient core 1 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp09));
// CPU efficient core 2 temperature
sensors.emplace_back(static_cast<std::string>(kSensorTp0t));

aux_sensors.emplace_back(static_cast<std::string>(kSensorTc0a));
aux_sensors.emplace_back(static_cast<std::string>(kSensorTc0b));
aux_sensors.emplace_back(static_cast<std::string>(kSensorTc0x));
aux_sensors.emplace_back(static_cast<std::string>(kSensorTc0z));
} else {
// not supported
return temp;
}
temp /= sensors.size();

temp = CalculateAverageTemperature(sensors, valid_temperature_limits);
if (temp > std::numeric_limits<double>::epsilon()) {
return temp;
}
std::vector<std::string> aux_sensors{
static_cast<std::string>(kSensorTc0a),
static_cast<std::string>(kSensorTc0b),
static_cast<std::string>(kSensorTc0x),
static_cast<std::string>(kSensorTc0z),
};
for (auto sensor : aux_sensors) {
temp += smc_accessor_.ReadValue(sensor.c_str());
}
temp /= aux_sensors.size();

temp += CalculateAverageTemperature(aux_sensors, valid_temperature_limits);
#endif
return temp;
}
Expand Down
28 changes: 18 additions & 10 deletions smctemp.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

#include <IOKit/IOKitLib.h>
#include <string>
#include <utility>
#include <vector>

#include "smctemp_types.h"

Expand Down Expand Up @@ -54,16 +56,20 @@ constexpr UInt32Char_t kSensorTc0a = "Tc0a";
constexpr UInt32Char_t kSensorTc0b = "Tc0b";
constexpr UInt32Char_t kSensorTc0x = "Tc0x";
constexpr UInt32Char_t kSensorTc0z = "Tc0z";
constexpr UInt32Char_t kSensorTp01 = "Tp01"; // CPU performance core 1 temperature
constexpr UInt32Char_t kSensorTp05 = "Tp05"; // CPU performance core 2 temperature
constexpr UInt32Char_t kSensorTp0d = "Tp0D"; // CPU performance core 3 temperature
constexpr UInt32Char_t kSensorTp0h = "Tp0H"; // CPU performance core 4 temperature
constexpr UInt32Char_t kSensorTp0l = "Tp0L"; // CPU performance core 5 temperature
constexpr UInt32Char_t kSensorTp0p = "Tp0P"; // CPU performance core 6 temperature
constexpr UInt32Char_t kSensorTp0x = "Tp0X"; // CPU performance core 7 temperature
constexpr UInt32Char_t kSensorTp0b = "Tp0b"; // CPU performance core 8 temperature
constexpr UInt32Char_t kSensorTp09 = "Tp09"; // CPU efficient core 1 temperature
constexpr UInt32Char_t kSensorTp0t = "Tp0T"; // CPU efficient core 2 temperature
constexpr UInt32Char_t kSensorTp01 = "Tp01";
constexpr UInt32Char_t kSensorTp05 = "Tp05";
constexpr UInt32Char_t kSensorTp0d = "Tp0D";
constexpr UInt32Char_t kSensorTp0h = "Tp0H";
constexpr UInt32Char_t kSensorTp0l = "Tp0L";
constexpr UInt32Char_t kSensorTp0p = "Tp0P";
constexpr UInt32Char_t kSensorTp0x = "Tp0X";
constexpr UInt32Char_t kSensorTp0b = "Tp0b";
constexpr UInt32Char_t kSensorTp09 = "Tp09";
constexpr UInt32Char_t kSensorTp0t = "Tp0T";
constexpr UInt32Char_t kSensorTp0j = "Tp0j";
constexpr UInt32Char_t kSensorTp0r = "Tp0r";
constexpr UInt32Char_t kSensorTp0f = "Tp0f";
constexpr UInt32Char_t kSensorTp0n = "Tp0n";
#endif

class SmcAccessor {
Expand All @@ -88,6 +94,8 @@ class SmcAccessor {

class SmcTemp {
private:
double CalculateAverageTemperature(const std::vector<std::string>& sensors,
const std::pair<unsigned int, unsigned int>& limits);
SmcAccessor smc_accessor_;

public:
Expand Down
Loading