From 8266383435e8a47e0eb3e85a65766a4d202ba55f Mon Sep 17 00:00:00 2001 From: Sean Molenaar Date: Mon, 21 Sep 2026 13:44:28 +0200 Subject: [PATCH 1/2] Add analytics reporting for the x86 version --- .../Homebrew/extend/os/linux/hardware/cpu.rb | 65 ++++++++++++++----- Library/Homebrew/test/utils/analytics_spec.rb | 11 ++++ Library/Homebrew/utils/analytics.rb | 1 + 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb index ffd673274fe21..7b1a12f681b4d 100644 --- a/Library/Homebrew/extend/os/linux/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/linux/hardware/cpu.rb @@ -10,6 +10,8 @@ module ClassMethods requires_ancestor { T.class_of(::Hardware::CPU) } + HEX_BASE = 16 + sig { returns(T::Hash[Symbol, String]) } def optimization_flags @optimization_flags ||= T.let(begin @@ -21,23 +23,56 @@ def optimization_flags sig { returns(Symbol) } def family - return :arm if arm? - return :ppc if ppc? - return :dunno unless intel? + if arm? + implementer = cpuinfo[/^CPU implementer\s*: (0x\h+)$/i, 1].to_s.hex + cpu_model = cpuinfo[/^CPU part\s*: (0x\h+)$/i, 1].to_s.hex + + arm_family(implementer, cpu_model) + elsif intel? + # See https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers + # and https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/Host.cpp + # and https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures#Roadmap + vendor_id = cpuinfo[/^vendor_id\s*: (.*)/, 1] + cpu_family = cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i + cpu_model = cpuinfo[/^model\s*: ([0-9]+)/, 1].to_i + unknown = :"unknown_0x#{cpu_family.to_s(HEX_BASE)}_0x#{cpu_model.to_s(HEX_BASE)}" + case vendor_id + when "GenuineIntel" + intel_family(cpu_family, cpu_model) + when "AuthenticAMD" + amd_family(cpu_family, cpu_model) + end || unknown + else + :dunno + end + end + + sig { params(implementer: Integer, cpu_model: Integer).returns(Symbol) } + def arm_family(implementer, cpu_model) + unknown = :"unknown_#{implementer.to_s(HEX_BASE)}_#{cpu_model.to_s(HEX_BASE)}" + # only mapping for Arm (0x41) is implemented + return unknown if implementer != 0x41 - # See https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers + # See https://en.wikipedia.org/wiki/ARM_architecture_family#Cores # and https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/Host.cpp - # and https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures#Roadmap - vendor_id = cpuinfo[/^vendor_id\s*: (.*)/, 1] - cpu_family = cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i - cpu_model = cpuinfo[/^model\s*: ([0-9]+)/, 1].to_i - unknown = :"unknown_0x#{cpu_family.to_s(16)}_0x#{cpu_model.to_s(16)}" - case vendor_id - when "GenuineIntel" - intel_family(cpu_family, cpu_model) - when "AuthenticAMD" - amd_family(cpu_family, cpu_model) - end || unknown + case cpu_model + when 0xc05, 0xc07, 0xc08, 0xc09, 0xc0f, 0xc0e + :armv7_a + when 0xd04, 0xd03, 0xd07, 0xd08, 0xd09, 0xd02 + :armv8_0_a + when 0xd05, 0xd0a, 0xd0b, 0xd0d, 0xd41, 0xd44, 0xd0c, 0xd06, 0xd4a, 0xd43 + :armv8_2_a + when 0xd40 + :armv8_4_a + when 0xd46, 0xd47, 0xd4d, 0xd48, 0xd4e, 0xd49, 0xd4f + :armv9_0_a + when 0xd80, 0xd81, 0xd82, 0xd84, 0xd85, 0xd8e + :armv9_2_a + when 0xd8a, 0xd90, 0xd8b, 0xd8f, 0xd87 + :armv9_3_a + else + unknown + end end sig { params(family: Integer, cpu_model: Integer).returns(T.nilable(Symbol)) } diff --git a/Library/Homebrew/test/utils/analytics_spec.rb b/Library/Homebrew/test/utils/analytics_spec.rb index 05d62852f31e1..6a7faf73e92fe 100644 --- a/Library/Homebrew/test/utils/analytics_spec.rb +++ b/Library/Homebrew/test/utils/analytics_spec.rb @@ -36,12 +36,23 @@ it "returns OS_VERSION, ARM and prefix when HOMEBREW_PREFIX is a custom prefix on arm" do expect(Homebrew).to receive(:default_prefix?).and_return(false).at_least(:once) + expect(described_class.default_package_tags).to have_key(:cpu_family) expect(described_class.default_package_tags).to have_key(:arch) expect(described_class.default_package_tags[:arch]).to eq HOMEBREW_PHYSICAL_PROCESSOR expect(described_class.default_package_tags).to have_key(:prefix) expect(described_class.default_package_tags[:prefix]).to eq "custom-prefix" end + it "serialises the Linux ARM CPU family in the package tags", :needs_linux do + allow(Hardware::CPU).to receive_messages(arm?: true, intel?: false) + allow(Hardware::CPU).to receive(:cpuinfo).and_return( + "CPU implementer : 0x41\nCPU part : 0xd08\n", + ) + described_class.clear_cache + + expect(described_class.default_package_tags[:cpu_family]).to eq "armv8_0_a" + end + it "returns OS_VERSION, Rosetta and prefix when HOMEBREW_PREFIX is a custom prefix on Rosetta", :needs_macos do expect(Homebrew).to receive(:default_prefix?).and_return(false).at_least(:once) expect(described_class.default_package_tags).to have_key(:prefix) diff --git a/Library/Homebrew/utils/analytics.rb b/Library/Homebrew/utils/analytics.rb index 8be80b47bd590..4530e97daf2e5 100644 --- a/Library/Homebrew/utils/analytics.rb +++ b/Library/Homebrew/utils/analytics.rb @@ -406,6 +406,7 @@ def default_package_tags developer: Homebrew::EnvConfig.developer?, devcmdrun: Homebrew::EnvConfig.devcmdrun?, arch: HOMEBREW_PHYSICAL_PROCESSOR, + cpu_family: Hardware::CPU.family.to_s, os: with_wsl_suffix_if_needed(HOMEBREW_SYSTEM), } end From 04757e8cf2b54973cbf4c4fb8953d6c7881580d5 Mon Sep 17 00:00:00 2001 From: Sean Molenaar Date: Mon, 19 Oct 2026 17:07:47 +0200 Subject: [PATCH 2/2] Use named variable for arm implementer Co-authored-by: Mike McQuaid --- Library/Homebrew/extend/os/linux/hardware/cpu.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb index 7b1a12f681b4d..90237fd4805c5 100644 --- a/Library/Homebrew/extend/os/linux/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/linux/hardware/cpu.rb @@ -50,8 +50,8 @@ def family sig { params(implementer: Integer, cpu_model: Integer).returns(Symbol) } def arm_family(implementer, cpu_model) unknown = :"unknown_#{implementer.to_s(HEX_BASE)}_#{cpu_model.to_s(HEX_BASE)}" - # only mapping for Arm (0x41) is implemented - return unknown if implementer != 0x41 + arm_implementer = 0x41 + return unknown if implementer != arm_implementer # See https://en.wikipedia.org/wiki/ARM_architecture_family#Cores # and https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/Host.cpp