diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb index ffd673274fe21..48a907bcebceb 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, 0xd8f, 0xd87 + :armv9_2_a + when 0xd8a, 0xd90, 0xd8b + :armv9_3_a + else + unknown + end end sig { params(family: Integer, cpu_model: Integer).returns(T.nilable(Symbol)) } diff --git a/Library/Homebrew/test/hardware/cpu_spec.rb b/Library/Homebrew/test/hardware/cpu_spec.rb index 45f1ddc9e17e7..3455ae716fa21 100644 --- a/Library/Homebrew/test/hardware/cpu_spec.rb +++ b/Library/Homebrew/test/hardware/cpu_spec.rb @@ -9,7 +9,6 @@ [ :arm, :intel, - :ppc, :dunno, ] end @@ -51,6 +50,13 @@ :arm_twister, :arm_typhoon, :arm_vortex_tempest, + :armv7_a, + :armv8_0_a, + :armv8_2_a, + :armv8_4_a, + :armv9_0_a, + :armv9_2_a, + :armv9_3_a, :arrowlake, :atom, :bobcat, @@ -90,7 +96,8 @@ end it "returns the current CPU's family name as a symbol, or :dunno if it cannot be detected" do - expect(cpu_families).to include described_class.family + family = described_class.family + expect(cpu_families.include?(family) || family.start_with?("unknown_")).to be(true) end context "when hw.cpufamily is 0x573b5eec on a Mac", :needs_macos do diff --git a/Library/Homebrew/test/utils/analytics_spec.rb b/Library/Homebrew/test/utils/analytics_spec.rb index 05d62852f31e1..2f50624fdbb87 100644 --- a/Library/Homebrew/test/utils/analytics_spec.rb +++ b/Library/Homebrew/test/utils/analytics_spec.rb @@ -36,12 +36,20 @@ 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 CPU family in the package tags" do + allow(Hardware::CPU).to receive(:family).and_return(:armv8_0_a) + 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