Make hardware code cross-platform.

This commit is contained in:
Mike McQuaid 2016-04-25 18:00:01 +01:00
parent 8a582f2bd9
commit 8d995e961f
8 changed files with 281 additions and 270 deletions

View File

@ -1,4 +1,4 @@
class Hardware
module Hardware
class << self
# We won't change the name because of backward compatibility.
# So disable rubocop here.

View File

@ -0,0 +1,5 @@
if OS.mac?
require "extend/os/mac/hardware/cpu"
elsif OS.linux?
require "extend/os/linux/hardware/cpu"
end

View File

@ -0,0 +1,67 @@
module Hardware
class CPU
extend self
OPTIMIZATION_FLAGS = {
:penryn => "-march=core2 -msse4.1",
:core2 => "-march=core2",
:core => "-march=prescott"
}.freeze
def optimization_flags
OPTIMIZATION_FLAGS
end
# Linux supports x86 only, and universal archs do not apply
def arch_32_bit
:i386
end
def arch_64_bit
:x86_64
end
def universal_archs
[].extend ArchitectureListExtension
end
def cpuinfo
@cpuinfo ||= File.read("/proc/cpuinfo")
end
def type
@type ||= if cpuinfo =~ /Intel|AMD/
:intel
else
:dunno
end
end
def family
cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i
end
alias_method :intel_family, :family
def cores
cpuinfo.scan(/^processor/).size
end
def flags
@flags ||= cpuinfo[/^flags.*/, 0].split
end
# Compatibility with Mac method, which returns lowercase symbols
# instead of strings
def features
@features ||= flags[1..-1].map(&:intern)
end
%w[aes altivec avx avx2 lm sse3 ssse3 sse4 sse4_2].each do |flag|
define_method(flag + "?") { flags.include? flag }
end
alias_method :is_64_bit?, :lm?
def bits
is_64_bit? ? 64 : 32
end
end
end

View File

@ -0,0 +1,171 @@
require "os/mac/pathname"
module Hardware
class CPU
class << self
OPTIMIZATION_FLAGS = {
:penryn => "-march=core2 -msse4.1",
:core2 => "-march=core2",
:core => "-march=prescott",
:g3 => "-mcpu=750",
:g4 => "-mcpu=7400",
:g4e => "-mcpu=7450",
:g5 => "-mcpu=970",
:g5_64 => "-mcpu=970 -arch ppc64"
}.freeze
def optimization_flags
OPTIMIZATION_FLAGS
end
# These methods use info spewed out by sysctl.
# Look in <mach/machine.h> for decoding info.
def type
case sysctl_int("hw.cputype")
when 7
:intel
when 18
:ppc
else
:dunno
end
end
def family
if intel?
case sysctl_int("hw.cpufamily")
when 0x73d67300 # Yonah: Core Solo/Duo
:core
when 0x426f69ef # Merom: Core 2 Duo
:core2
when 0x78ea4fbc # Penryn
:penryn
when 0x6b5a4cd2 # Nehalem
:nehalem
when 0x573B5EEC # Arrandale
:arrandale
when 0x5490B78C # Sandy Bridge
:sandybridge
when 0x1F65E835 # Ivy Bridge
:ivybridge
when 0x10B282DC # Haswell
:haswell
when 0x582ed09c # Broadwell
:broadwell
when 0x37fc219f # Skylake
:skylake
else
:dunno
end
elsif ppc?
case sysctl_int("hw.cpusubtype")
when 9
:g3 # PowerPC 750
when 10
:g4 # PowerPC 7400
when 11
:g4e # PowerPC 7450
when 100
# This is the only 64-bit PPC CPU type, so it's useful
# to distinguish in `brew config` output and in bottle tags
MacOS.prefer_64_bit? ? :g5_64 : :g5 # PowerPC 970
else
:dunno
end
end
end
def extmodel
sysctl_int("machdep.cpu.extmodel")
end
def cores
sysctl_int("hw.ncpu")
end
def bits
sysctl_bool("hw.cpu64bit_capable") ? 64 : 32
end
def arch_32_bit
intel? ? :i386 : :ppc
end
def arch_64_bit
intel? ? :x86_64 : :ppc64
end
# Returns an array that's been extended with ArchitectureListExtension,
# which provides helpers like #as_arch_flags and #as_cmake_arch_flags.
def universal_archs
# Building 64-bit is a no-go on Tiger, and pretty hit or miss on Leopard.
# Don't even try unless Tigerbrew's experimental 64-bit Leopard support is enabled.
if MacOS.version <= :leopard && !MacOS.prefer_64_bit?
[arch_32_bit].extend ArchitectureListExtension
else
# Amazingly, this order (64, then 32) matters. It shouldn't, but it
# does. GCC (some versions? some systems?) can blow up if the other
# order is used.
# http://superuser.com/questions/740563/gcc-4-8-on-macos-fails-depending-on-arch-order
[arch_64_bit, arch_32_bit].extend ArchitectureListExtension
end
end
def features
@features ||= sysctl_n(
"machdep.cpu.features",
"machdep.cpu.extfeatures",
"machdep.cpu.leaf7_features"
).split(" ").map { |s| s.downcase.to_sym }
end
def aes?
sysctl_bool("hw.optional.aes")
end
def altivec?
sysctl_bool("hw.optional.altivec")
end
def avx?
sysctl_bool("hw.optional.avx1_0")
end
def avx2?
sysctl_bool("hw.optional.avx2_0")
end
def sse3?
sysctl_bool("hw.optional.sse3")
end
def ssse3?
sysctl_bool("hw.optional.supplementalsse3")
end
def sse4?
sysctl_bool("hw.optional.sse4_1")
end
def sse4_2?
sysctl_bool("hw.optional.sse4_2")
end
private
def sysctl_bool(key)
sysctl_int(key) == 1
end
def sysctl_int(key)
sysctl_n(key).to_i
end
def sysctl_n(*keys)
(@properties ||= {}).fetch(keys) do
@properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
end
end
end
end
end

View File

@ -1,13 +1,13 @@
require "os"
class Hardware
module CPU
extend self
module Hardware
class CPU
INTEL_32BIT_ARCHS = [:i386].freeze
INTEL_64BIT_ARCHS = [:x86_64].freeze
PPC_32BIT_ARCHS = [:ppc, :ppc7400, :ppc7450, :ppc970].freeze
PPC_64BIT_ARCHS = [:ppc64].freeze
class << self
def type
:dunno
end
@ -48,13 +48,6 @@ class Hardware
features.include?(name)
end
end
if OS.mac?
require "os/mac/hardware"
CPU.extend MacCPUs
elsif OS.linux?
require "os/linux/hardware"
CPU.extend LinuxCPUs
end
def self.cores_as_words
@ -79,3 +72,5 @@ class Hardware
end
end
end
require "extend/os/hardware"

View File

@ -1,63 +0,0 @@
module LinuxCPUs
OPTIMIZATION_FLAGS = {
:penryn => "-march=core2 -msse4.1",
:core2 => "-march=core2",
:core => "-march=prescott"
}.freeze
def optimization_flags
OPTIMIZATION_FLAGS
end
# Linux supports x86 only, and universal archs do not apply
def arch_32_bit
:i386
end
def arch_64_bit
:x86_64
end
def universal_archs
[].extend ArchitectureListExtension
end
def cpuinfo
@cpuinfo ||= File.read("/proc/cpuinfo")
end
def type
@type ||= if cpuinfo =~ /Intel|AMD/
:intel
else
:dunno
end
end
def family
cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i
end
alias_method :intel_family, :family
def cores
cpuinfo.scan(/^processor/).size
end
def flags
@flags ||= cpuinfo[/^flags.*/, 0].split
end
# Compatibility with Mac method, which returns lowercase symbols
# instead of strings
def features
@features ||= flags[1..-1].map(&:intern)
end
%w[aes altivec avx avx2 lm sse3 ssse3 sse4 sse4_2].each do |flag|
define_method(flag + "?") { flags.include? flag }
end
alias_method :is_64_bit?, :lm?
def bits
is_64_bit? ? 64 : 32
end
end

View File

@ -1,3 +1,5 @@
require "extend/os/hardware"
module ArchitectureListExtension
# @private
def fat?

View File

@ -1,166 +0,0 @@
require "os/mac/pathname"
module MacCPUs
OPTIMIZATION_FLAGS = {
:penryn => "-march=core2 -msse4.1",
:core2 => "-march=core2",
:core => "-march=prescott",
:g3 => "-mcpu=750",
:g4 => "-mcpu=7400",
:g4e => "-mcpu=7450",
:g5 => "-mcpu=970",
:g5_64 => "-mcpu=970 -arch ppc64"
}.freeze
def optimization_flags
OPTIMIZATION_FLAGS
end
# These methods use info spewed out by sysctl.
# Look in <mach/machine.h> for decoding info.
def type
case sysctl_int("hw.cputype")
when 7
:intel
when 18
:ppc
else
:dunno
end
end
def family
if intel?
case sysctl_int("hw.cpufamily")
when 0x73d67300 # Yonah: Core Solo/Duo
:core
when 0x426f69ef # Merom: Core 2 Duo
:core2
when 0x78ea4fbc # Penryn
:penryn
when 0x6b5a4cd2 # Nehalem
:nehalem
when 0x573B5EEC # Arrandale
:arrandale
when 0x5490B78C # Sandy Bridge
:sandybridge
when 0x1F65E835 # Ivy Bridge
:ivybridge
when 0x10B282DC # Haswell
:haswell
when 0x582ed09c # Broadwell
:broadwell
when 0x37fc219f # Skylake
:skylake
else
:dunno
end
elsif ppc?
case sysctl_int("hw.cpusubtype")
when 9
:g3 # PowerPC 750
when 10
:g4 # PowerPC 7400
when 11
:g4e # PowerPC 7450
when 100
# This is the only 64-bit PPC CPU type, so it's useful
# to distinguish in `brew config` output and in bottle tags
MacOS.prefer_64_bit? ? :g5_64 : :g5 # PowerPC 970
else
:dunno
end
end
end
def extmodel
sysctl_int("machdep.cpu.extmodel")
end
def cores
sysctl_int("hw.ncpu")
end
def bits
sysctl_bool("hw.cpu64bit_capable") ? 64 : 32
end
def arch_32_bit
intel? ? :i386 : :ppc
end
def arch_64_bit
intel? ? :x86_64 : :ppc64
end
# Returns an array that's been extended with ArchitectureListExtension,
# which provides helpers like #as_arch_flags and #as_cmake_arch_flags.
def universal_archs
# Building 64-bit is a no-go on Tiger, and pretty hit or miss on Leopard.
# Don't even try unless Tigerbrew's experimental 64-bit Leopard support is enabled.
if MacOS.version <= :leopard && !MacOS.prefer_64_bit?
[arch_32_bit].extend ArchitectureListExtension
else
# Amazingly, this order (64, then 32) matters. It shouldn't, but it
# does. GCC (some versions? some systems?) can blow up if the other
# order is used.
# http://superuser.com/questions/740563/gcc-4-8-on-macos-fails-depending-on-arch-order
[arch_64_bit, arch_32_bit].extend ArchitectureListExtension
end
end
def features
@features ||= sysctl_n(
"machdep.cpu.features",
"machdep.cpu.extfeatures",
"machdep.cpu.leaf7_features"
).split(" ").map { |s| s.downcase.to_sym }
end
def aes?
sysctl_bool("hw.optional.aes")
end
def altivec?
sysctl_bool("hw.optional.altivec")
end
def avx?
sysctl_bool("hw.optional.avx1_0")
end
def avx2?
sysctl_bool("hw.optional.avx2_0")
end
def sse3?
sysctl_bool("hw.optional.sse3")
end
def ssse3?
sysctl_bool("hw.optional.supplementalsse3")
end
def sse4?
sysctl_bool("hw.optional.sse4_1")
end
def sse4_2?
sysctl_bool("hw.optional.sse4_2")
end
private
def sysctl_bool(key)
sysctl_int(key) == 1
end
def sysctl_int(key)
sysctl_n(key).to_i
end
def sysctl_n(*keys)
(@properties ||= {}).fetch(keys) do
@properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
end
end
end