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 temperature support for M1 Macs #456

Closed
mikemadden42 opened this issue Apr 8, 2021 · 29 comments
Closed

Add temperature support for M1 Macs #456

mikemadden42 opened this issue Apr 8, 2021 · 29 comments

Comments

@mikemadden42
Copy link

Would it be possible to add temperature support for M1 Macs?

On an Intel Mac, I can use the following to find information about the temperature of system components:

use sysinfo::{System, SystemExt};

fn main() {
    let sys = System::new_all();

    for component in sys.get_components() {
        println!("{:?}", component);
    }
}
PECI CPU: 46.859375°C (max: 0°C)
CPU Proximity: 42.375°C (max: 0°C)
Battery: 30.09375°C (max: 0°C)

On M1 Macs, sys.get_components() appears empty.

$ rustc --version
rustc 1.51.0 (2fd73fabe 2021-03-23)

$ tail -2 Cargo.toml
[dependencies]
sysinfo = "0.16.5"
@mikemadden42
Copy link
Author

I wonder if the issue with sysinfo is related to this issue:
iglance/iGlance#225 (comment)

@GuillaumeGomez
Copy link
Owner

I'd like to add this support but I don't have a mac with M1 processor, so it'll need someone else to implement it. :-/

@nbigaouette
Copy link

nbigaouette commented Apr 8, 2021

This Objective-C project seems to be able to read some temperature on the M1: https://github.com/freedomtan/sensors_cmdline/

I'll see if I can hack something...

EDIT: There is also this project (still in Objective-C): https://github.com/fermion-star/apple_sensors

@GuillaumeGomez
Copy link
Owner

Good luck!

@nbigaouette
Copy link

Good luck!

It's dangerous to go alone, I'll get all the luck I can!

:D

@GuillaumeGomez
Copy link
Owner

On any objective-C related source code, it's very useful indeed. :3

@fdncred
Copy link
Contributor

fdncred commented Dec 19, 2021

just adding my voice here in wishing sensors worked on M1. :)

@GuillaumeGomez
Copy link
Owner

Same answer: I don't have a mac with M1 processors so I'll need someone to do it. :)

@zannis
Copy link

zannis commented Feb 3, 2022

I could help with this one if you can provide some info on how to approach it, I'm pretty new to Macs internals :/

@GuillaumeGomez
Copy link
Owner

You have everything you need in this message. The difficulty being to find the C equivalent of the objective-C API so you can call it from rust.

@macshome
Copy link

macshome commented Feb 7, 2022

Yeah, the issue is that the older code is using the SMC to get temperatures and M1 Macs don't have a SMC. They share the sensor layout with iOS devices for things like the CPU. This means you need to talk to IOKit to get the info.

Seeing as this has been sitting like this for a long time, and I've wanted to dabble in Rust, I might take a look at it.

P.S. To call Obj-C from just about anything that talks C you can use the objc_msgSend method. There are some Rust tools built on this as well like rust-objc.

@GuillaumeGomez
Copy link
Owner

It's in this file.

P.S. To call Obj-C from just about anything that talks C you can use the objc_msgSend method. There are some Rust tools built on this as well like rust-objc.

I removed all objective-C code from sysinfo and I'd prefer to keep it this way. :)

If needed, you can simply reimplement the objective-C function (I can help with that if you don't know how to do it) by looking at its source code.

@macshome
Copy link

macshome commented Feb 8, 2022

I installed rust and read some docs last night to take a look at this in more depth. Seems like it's pretty straightforward to get the C working and then define those externals in the ffi class. I've got M1 and M1 Pro MacBooks to test with.

Work is busy, so I'm not blasting through it unfortunately.

@GuillaumeGomez
Copy link
Owner

It's fine, take your time. And thanks for working on this!

@macshome
Copy link

Going through this it seems we can get the temps without resorting to private SPI calls. As a question though, which temperature sensor are most interested in? I assume it's the closest analog to the CPU Proximity (heat spreader) "TC0P" that is being used in the existing code?

@GuillaumeGomez
Copy link
Owner

You can get all of them, no need to filter. :)

Currently it's not about filtering on mac but more like there isn't a generic way to get all of them (because they have IDs that change at each update for whatever reason...).

@macshome
Copy link

Well, a M1 Pro (10-core CPU) has 64 HIDEvent temp sensors it seems. Since the M1 Macs are all SoC based I suppose the differences in distance are minimal.

How would you like to consume the list from my code? Dictionary? Array? I assume you want the name and the temp value for each.

@GuillaumeGomez
Copy link
Owner

GuillaumeGomez commented Feb 10, 2022

The answer is here (so yes, a vector for the moment, maybe I'll switch to a hash map later on... But out of scope in here).

@macshome
Copy link

Here is a list of the sensors and temps on a 10 Core M1 Pro. Some of the names are easier than others to figure out. In your code you seem to be looking at 4 in particular. Is that still the case here or do you just want all of them? It's simple enough to filter or just return them all.

Sensor Name Temp C
gas gauge battery 23.2
NAND CH0 temp 24.0
PMU tcal 51.9
PMU tdev1 27.6
PMU tdev2 27.5
PMU tdev3 27.7
PMU tdev4 23.0
PMU tdev5 23.4
PMU tdev6 26.9
PMU tdev7 28.4
PMU tdev8 26.9
PMU tdie0 27.8
PMU tdie1 28.1
PMU tdie10 27.7
PMU tdie2 28.1
PMU tdie3 27.9
PMU tdie4 28.2
PMU tdie5 28.1
PMU tdie6 27.9
PMU tdie7 27.9
PMU tdie8 27.9
PMU tdie9 27.9
PMU TP0s 27.8
PMU TP0s 27.8
PMU TP1g 28.1
PMU TP1s 27.5
PMU TP2g 28.1
PMU TP2s 27.7
PMU TP3g 27.6

@GuillaumeGomez
Copy link
Owner

Like I said, I didn't grow the list because these IDs change between macs and I don't have a generic way to get them all.

In the list you provided, as you long as there is a "readable name" (meaning you'll need a table for this too unfortunately), you can keep all of them.

@macshome
Copy link

Ok. That actually makes the ARM sensors easier to get as I’m just asking for all the HID events with the usage page for the internal temperature sensors. The only processing I’ll do is to dedupe and toss the ones without readable names.

I’ll be back to my computers tomorrow and can start looking at how to get this working with the ffi.

@macshome
Copy link

OK, taking a look at how to get this working in Rust now. It seems like I add my function prototypes to this ffi.rs file and then implement them in this components.rs file?

@macshome
Copy link

I guess the first step is learning how to define and call non-public types and functions in C from Rust. :D

In my main.c I setup the non-public types like this...

#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
#include <stdio.h>

typedef struct __IOHIDEvent *IOHIDEventRef;
typedef double IOHIDFloat;

IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator);
IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t , int32_t, int64_t);
IOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef event, int32_t field);

#define kIOHIDEventTypeTemperature  15
#define IOHIDEventFieldBase(type)   (type << 16)

The main sticking point is the import of that specific hidsystem file. I think once I can do that I can declare my types and functions pretty easily. Would copying the header to the project and then using #[link] work?

Sorry to be such a pain on this, this is my first time touching Rust.

@GuillaumeGomez
Copy link
Owner

No problem, don't worry. We all have to learn somewhere when we begin and your efforts are really appreciated!

OK, taking a look at how to get this working in Rust now. It seems like I add my function prototypes to this ffi.rs file and then implement them in this components.rs file?

Yes and yes.

The main sticking point is the import of that specific hidsystem file. I think once I can do that I can declare my types and functions pretty easily. Would copying the header to the project and then using #[link] work?

It'd be much simpler to simply redeclare them in Rust. For example:

extern "C" {
    pub type IOHIDEventRef = c_void;
    pub type __IOHIDEvent = *mut IOHIDEventRef;

    pub fn IOHIDEventSystemClientCreate(allocator: CFAllocatorRef)-> IOHIDEventSystemClientRef;
}

@macshome
Copy link

macshome commented Mar 2, 2022

OK. Been reading up on Rust and finally got my debugger working. Been at horse shows the last two weekends in a row, but hopefully I have some time now to get back to this.

@GuillaumeGomez
Copy link
Owner

Thanks! Again please remember: we're not in a hurry so take as much time as you want/need.

@GuillaumeGomez
Copy link
Owner

Fixed in #792.

@macshome
Copy link

macshome commented Dec 8, 2022

Thanks for getting this done. I haven't had the time and have had some debates with work about allowing me to participate.

@GuillaumeGomez
Copy link
Owner

No problem. We were lucky that someone had a mac M1, time and motivation to do it. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants