10

I need to retrieve the real architecture of a Mac regardless of if the process is running through Rosetta or not.

Right now in Node.js, process.arch returns x64 and in shell, uname -m returns x86_64.

Elmo
  • 6,409
  • 16
  • 72
  • 140
  • My use case here is to ship the arm version of the app through auto update. Also track who are running emulated software and link that with performance or other issues. – Elmo Dec 17 '20 at 20:06
  • It should be possible to detect existence of Rosetta 2 and assume arm. – Elmo Dec 17 '20 at 20:06
  • 1
    There's [this note](https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment#3616845) on how to do that in general. I have doubts that there is a Nodejs module already written for this, though. – Ouroborus Dec 17 '20 at 20:14
  • Thanks! Do you know if there's a way to do the same in a shell script? (if your Terminal app is running in x86, uname -m will not return arm) – Elmo Dec 17 '20 at 20:16
  • Write an executable that does the actual check. In the script, try to execute the binary and check its results and whether or not it fails to actually execute. – Ouroborus Dec 17 '20 at 20:19
  • This is great for trying to get cross-architecture Vagrant images working: https://github.com/hashicorp/vagrant/issues/12610 – oligofren Mar 08 '22 at 22:51

2 Answers2

14

Thanks to @Ouroborus, this note describes how to figure out if your app is translated.

If it's translated:

$ sysctl sysctl.proc_translated
sysctl.proc_translated: 1

If not:

$ sysctl sysctl.proc_translated
sysctl.proc_translated: 0

On non-ARM Macs:

$ sysctl sysctl.proc_translated
sysctl: unknown oid 'sysctl.proc_translated'
Elmo
  • 6,409
  • 16
  • 72
  • 140
  • 1
    For ease of scripting, you can also use `sysctl -n sysctl.proc_translated`. `-n` will cause `sysctl` to only print the value. – Zach Bloomquist Jun 09 '22 at 14:15
  • 1
    If you want to ignore unknown oid values, you can run `sysctl -in sysctl.proc_translated`. This will only print the value without the error message. – John Yeary Jun 22 '22 at 14:21
2

As @Elmo's answer indicates, the command line sysctl -n sysctl.proc_translated or the native equivalent sysctlbyname() call will indicate whether you are running under Rosetta.

Two other sysctl values are relevant. On M1 hardware without Rosetta, these values are returned:

hw.cputype: 16777228
hw.cpufamily: 458787763

hw.cputype is 0x0100000C (CPU_TYPE_ARM64) and hw.cpufamily is 0x1b588bb3 (CPUFAMILY_ARM_FIRESTORM_ICESTORM).

However, when executed under Rosetta, the low-level machine code which collects CPUID takes precendence and following two values are returned, both via sysctlbyname() and the command line:

hw.cputype: 7
hw.cpufamily: 1463508716

These correspond to 0x7 (CPU_TYPE_X86) and 0x573b5eec (INTEL_WESTMERE).

It appears Rosetta reports an x86-compatible Westmere chip under Rosetta, but this choice seems consistent everywhere I've seen. This "virtual architecture" may be useful information for some programs.

Another possibility presents itself in the IO Registry. While the default IOService plane collects data in real-time, the IODeviceTree plane is stored at boot, and includes these entries in the tree (command line ioreg -p IODeviceTree or ioreg -c IOPlatformDevice):

cpu0@0  <class IOPlatformDevice, id 0x10000010f, registered, matched, active, busy 0 (180 ms), retain 8>
    | | | {
...
    | | |   "compatible" = <"apple,icestorm","ARM,v8">

(for CPUs 0-3) and

cpu4@100  <class IOPlatformDevice, id 0x100000113, registered, matched, active, busy 0 (186 ms), retain 8>
    | | | {
...
    | | |   "compatible" = <"apple,firestorm","ARM,v8">

(for CPUs 4-7)

This clearly indicates the ARMv8 Firestorm + Icestorm M1 chip.

The same approach should work for the M1 Pro and M1 Max.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63