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

Adding support for the M1 Pro (fetching CPU info with sysctl) #139

Closed
a-hurst opened this issue Feb 28, 2022 · 3 comments
Closed

Adding support for the M1 Pro (fetching CPU info with sysctl) #139

a-hurst opened this issue Feb 28, 2022 · 3 comments

Comments

@a-hurst
Copy link

a-hurst commented Feb 28, 2022

Hi there,

Just learned about this (very cool) project, and noticed that the macOS version only supports the base M1 CPU and not the M1 Pro or M1 Max. Looking at the code related to macOS M1 support it looks like cpufetch is hard-coded to assume an M1 if it's running on arm64 macOS.

Checking on my own M1 Pro machine, it looks like the CPU name, number of performance/efficiency cores, feature support flags, cache sizes, etc. are all available through the system's sysctl library. Since I'm pretty sure you can access sysctl values directly in C, you could probably add more flexible & future-proof Apple Silicon support using the relevant field names.

Anyway, here are the names of the relevant fields (and their values) via sysctl -a on my Mac:

hw.ncpu: 10
hw.byteorder: 1234
hw.activecpu: 10
hw.perflevel1.cpusperl2: 2
hw.perflevel1.l1dcachesize: 65536
hw.perflevel1.l1icachesize: 131072
hw.perflevel1.l2cachesize: 4194304
hw.perflevel1.logicalcpu: 2
hw.perflevel1.logicalcpu_max: 2
hw.perflevel1.physicalcpu: 2
hw.perflevel1.physicalcpu_max: 2
hw.perflevel0.cpusperl2: 4
hw.perflevel0.l1dcachesize: 131072
hw.perflevel0.l1icachesize: 196608
hw.perflevel0.l2cachesize: 12582912
hw.perflevel0.logicalcpu: 8
hw.perflevel0.logicalcpu_max: 8
hw.perflevel0.physicalcpu: 8
hw.perflevel0.physicalcpu_max: 8
hw.features.allows_security_research: 0
hw.optional.arm.FEAT_AES: 1
hw.optional.arm.FEAT_BF16: 0
hw.optional.arm.FEAT_BTI: 0
hw.optional.arm.FEAT_CSV2: 1
hw.optional.arm.FEAT_CSV3: 1
hw.optional.arm.FEAT_DPB: 1
hw.optional.arm.FEAT_DPB2: 1
hw.optional.arm.FEAT_DotProd: 1
hw.optional.arm.FEAT_ECV: 1
hw.optional.arm.FEAT_FCMA: 1
hw.optional.arm.FEAT_FHM: 1
hw.optional.arm.FEAT_FP16: 1
hw.optional.arm.FEAT_FPAC: 0
hw.optional.arm.FEAT_FRINTTS: 1
hw.optional.arm.FEAT_FlagM: 1
hw.optional.arm.FEAT_FlagM2: 1
hw.optional.arm.FEAT_I8MM: 0
hw.optional.arm.FEAT_JSCVT: 1
hw.optional.arm.FEAT_LRCPC: 1
hw.optional.arm.FEAT_LRCPC2: 1
hw.optional.arm.FEAT_LSE: 1
hw.optional.arm.FEAT_LSE2: 1
hw.optional.arm.FEAT_PAuth: 1
hw.optional.arm.FEAT_PAuth2: 0
hw.optional.arm.FEAT_PMULL: 1
hw.optional.arm.FEAT_RDM: 1
hw.optional.arm.FEAT_SB: 1
hw.optional.arm.FEAT_SHA1: 1
hw.optional.arm.FEAT_SHA256: 1
hw.optional.arm.FEAT_SHA3: 1
hw.optional.arm.FEAT_SHA512: 1
hw.optional.arm.FEAT_SPECRES: 0
hw.optional.arm.FEAT_SSBS: 1
hw.optional.AdvSIMD: 1
hw.optional.AdvSIMD_HPFPCvt: 1
hw.optional.arm64: 1
hw.optional.armv8_1_atomics: 1
hw.optional.armv8_2_fhm: 1
hw.optional.armv8_2_sha3: 1
hw.optional.armv8_2_sha512: 1
hw.optional.armv8_3_compnum: 1
hw.optional.armv8_crc32: 1
hw.optional.armv8_gpi: 1
hw.optional.breakpoint: 6
hw.optional.floatingpoint: 1
hw.optional.neon: 1
hw.optional.neon_fp16: 1
hw.optional.neon_hpfp: 1
hw.optional.ucnormal_mem: 1
hw.optional.watchpoint: 4
hw.cacheconfig: 10 1 2 0 0 0 0 0 0 0
hw.cachelinesize: 128
hw.cachesize: 3445178368 65536 4194304 0 0 0 0 0 0 0
hw.cpufamily: 458787763
hw.cpusubfamily: 4
hw.cpusubtype: 2
hw.cputype: 16777228
hw.l1dcachesize: 65536
hw.l1icachesize: 131072
hw.l2cachesize: 4194304
hw.logicalcpu: 10
hw.logicalcpu_max: 10
hw.nperflevels: 2
hw.pagesize: 16384
hw.pagesize32: 16384
hw.physicalcpu: 10
hw.physicalcpu_max: 10
hw.targettype: J314s
machdep.cpu.brand_string: Apple M1 Pro
machdep.cpu.core_count: 10
machdep.cpu.cores_per_package: 10
machdep.cpu.logical_per_package: 10

In this case, hw.perflevel1.logicalcpu gives you the number of efficiency cores (2) and hw.perflevel1.logicalcpu is the number of performance cores (8), and machdep.cpu.brand_string tells you whether it's a "Pro" or a "Max" chip. I've found a similar table for the standard M1 posted here for comparison. There's some info about calculating per-core cache sizes from these values here too.

Some similar sysctl dumps I found for base M1s don't have the separate performance/efficiency core info fields though, so those fields might have been added in macOS 12 and thus need a fallback for macOS 11.

Hope this is helpful!

@Dr-Noob
Copy link
Owner

Dr-Noob commented Mar 6, 2022

Hi, thank you very much for your brief research on this and your suggestions.

Regarding the cache, as I don't support cache sizes for any other ARM chip, at the moment I'm not interested in adding it just for M1. Funny thing that macOS let you know the cache sizes but, AFAIK, Linux does not. And you are right, cpufetch simply assumes that the CPU is the Apple M1 if the program was compiled for ARM and it detects a CPU with the M1 cores, but does not differentiate between M1 versions (when this was implemented, only M1 existed). I think the best thing to do is to write here my decisions on how I did this and why, and how am I going to approach this now that are different M1 versions, just for anybody interested in this (one of such will probably be myself in the future 😅). So be prepared for a somewhat long discussion (TL;DR included).

I started looking for many sysctl dumps, even trying different computers by myself. I thought that machdep.cpu.brand_string was the best approach since it gives you the SoC name. Nice, right? If I remember correctly, this reported Apple M1 for many computers, but for others, it did not. I do not remember the exact string, but I found M1-based macs that did not report it under machdep.cpu.brand_string. My next bet was hw.cpufamily. It tells you the CPU "family". In this case, can tell you whether is a firestorm+icestorm (CPUFAMILY_ARM_FIRESTORM_ICESTORM). And it was correctly reported in all cases, so I chose this approach.

Now you're suggesting to use hw.perflevel0.logicalcpu and hw.perflevel1.logicalcpu which, for me, looks the best approach. You also noted the problem; not all the versions of macOS provide this information. So I might implement it using it, but I would need a fallback for older macOS. I don't see the point of doing so, because if there is a way of doing it with older macOS, why should I provide a second way of doing it for newer ones? Another story would be if, let's say, detection in macOS 11 would be impossible with the information that sysctl provides. Then I would need to cut the support and only let it for newer ones.

I still keep the faith that this crappy design in Apple OS is not that crappy and that there is a way to do this properly do this even in older macOS. My bet is to use hw.cpusubfamily. I have not seen this anywhere, but I noticed that it might be possible to distinguish the M1 chip using this field. Searching on the internet, I found that:

  • Apple M1 -> hw.cpusubfamily: 2 (proof)
  • Apple M1 Pro -> hw.cpusubfamily: 4 (proof)
  • Apple M1 Max -> hw.cpusubfamily: 5 (proof)

Which correspond to: CPUSUBFAMILY_ARM_HG, CPUSUBFAMILY_ARM_HS and CPUSUBFAMILY_ARM_HC_HD. I honestly don't know what the heck does it mean, but I would love to know so. In Asahi Linux, the HG thing appears, but not the others... Lastly, M1 Pro might have 8 or 10 cores, but I believe that hw.physicalcpu is present in older macOS, so it should be possible to detect everything properly.

TL;DR: My best bet is to use hw.cpufamily+hw.cpusubfamily+hw.physicalcpu.
I have pushed a patch to the M1 branch. Could you give it a try and see if it works?

@a-hurst
Copy link
Author

a-hurst commented Mar 6, 2022

Thanks for taking a look! With your patches on the M1 branch, cpufetch now properly detects my CPU and core count (apologies for the hard-to-read white terminal):

Screen Shot 2022-03-06 at 12 33 48 PM

Also, thanks for the detailed write-up, it's fun to see the thought process behind it all.

@Dr-Noob
Copy link
Owner

Dr-Noob commented Mar 6, 2022

Good to know!

I merged the changes to the master branch, so I'm closing the issue. Thanks for noticing the problem and reporting back the result!

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

No branches or pull requests

2 participants