Skip to content

Commit

Permalink
Add AMD64 micro architecture level support
Browse files Browse the repository at this point in the history
This commit adds the support for AMD64 micro architecture levels
on Linux.

Signed-off-by: Zhongcheng Lao <laozhongcheng@gmail.com>
  • Loading branch information
laozc committed Oct 30, 2024
1 parent a413568 commit deefb02
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 8 deletions.
31 changes: 28 additions & 3 deletions cpuinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import (
"sync"

"github.com/containerd/log"
amd64variant "github.com/tonistiigi/go-archvariant"
)

// Present the ARM instruction set architecture, eg: v7, v8
// Present the instruction set architecture, eg: v7, v8 for ARM CPU,
// v3, v4 for AMD64 CPU.
// Don't use this value directly; call cpuVariant() instead.
var cpuVariantValue string

Expand All @@ -33,11 +35,34 @@ func cpuVariant() string {
cpuVariantOnce.Do(func() {
if isArmArch(runtime.GOARCH) {
var err error
cpuVariantValue, err = getCPUVariant()
cpuVariantValue, err = getArmCPUVariant()
if err != nil {
log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
log.L.Errorf("Error getArmCPUVariant for OS %s: %v", runtime.GOOS, err)
}
}
})
return cpuVariantValue
}

func cpuVariantMaximum() string {
cpuVariantOnce.Do(func() {
if isArmArch(runtime.GOARCH) {
var err error
cpuVariantValue, err = getArmCPUVariant()
if err != nil {
log.L.Errorf("Error getArmCPUVariant for OS %s: %v", runtime.GOOS, err)
}
} else if isAmd64Arch(runtime.GOARCH) {
var err error
cpuVariantValue, err = getAmd64MicroArchLevel()
if err != nil {
log.L.Errorf("Error getAmd64MicroArchLevel for OS %s: %v", runtime.GOOS, err)
}
}
})
return cpuVariantValue
}

func getAmd64MicroArchLevel() (string, error) {
return amd64variant.AMD64Variant(), nil
}
4 changes: 2 additions & 2 deletions cpuinfo_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ func getCPUVariantFromArch(arch string) (string, error) {
return variant, nil
}

// getCPUVariant returns cpu variant for ARM
// getArmCPUVariant returns cpu variant for ARM
// We first try reading "Cpu architecture" field from /proc/cpuinfo
// If we can't find it, then fall back using a system call
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
// was not present.
func getCPUVariant() (string, error) {
func getArmCPUVariant() (string, error) {
variant, err := getCPUInfo("Cpu architecture")
if err != nil {
if errors.Is(err, errNotFound) {
Expand Down
2 changes: 1 addition & 1 deletion cpuinfo_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestCPUVariant(t *testing.T) {

variants := []string{"v8", "v7", "v6", "v5", "v4", "v3"}

p, err := getCPUVariant()
p, err := getArmCPUVariant()
if err != nil {
t.Fatalf("Error getting CPU variant: %v", err)
return
Expand Down
4 changes: 2 additions & 2 deletions cpuinfo_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"runtime"
)

func getCPUVariant() (string, error) {
func getArmCPUVariant() (string, error) {

var variant string

Expand All @@ -48,7 +48,7 @@ func getCPUVariant() (string, error) {
variant = "unknown"
}
} else {
return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
return "", fmt.Errorf("getArmCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
}

return variant, nil
Expand Down
7 changes: 7 additions & 0 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ func isArmArch(arch string) bool {
return false
}

// isAmd64Arch returns true if the architecture is AMD64.
//
// The arch value should be normalized before being passed to this function.
func isAmd64Arch(arch string) bool {
return arch == "amd64"
}

// isKnownArch returns true if we know about the architecture.
//
// The arch value should be normalized before being passed to this function.
Expand Down
10 changes: 10 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,13 @@ func DefaultString() string {
func DefaultStrict() MatchComparer {
return OnlyStrict(DefaultSpec())
}

// MaximumString returns the maximum string specifier for the platform.
func MaximumString() string {
return FormatAll(MaximumSpec())
}

// MaximumStrict returns strict form of Maximum.
func MaximumStrict() MatchComparer {
return OnlyStrict(MaximumSpec())
}
19 changes: 19 additions & 0 deletions defaults_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,22 @@ func Default() MatchComparer {
Architecture: runtime.GOARCH,
})
}

// MaximumSpec returns the current platform's maximum platform specification.
func MaximumSpec() specs.Platform {
return specs.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
// The Variant field will be empty if arch != ARM and AMD64.
Variant: cpuVariantMaximum(),
}
}

// Maximum returns the maximum matcher for the platform.
func Maximum() MatchComparer {
return Ordered(MaximumSpec(), specs.Platform{
// darwin runtime also supports Linux binary via runu/LKL
OS: "linux",
Architecture: runtime.GOARCH,
})
}
20 changes: 20 additions & 0 deletions defaults_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,23 @@ func Default() MatchComparer {
Variant: cpuVariant(),
})
}

// MaximumSpec returns the current platform's maximum platform specification.
func MaximumSpec() specs.Platform {
return specs.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
// The Variant field will be empty if arch != ARM and AMD64.
Variant: cpuVariantMaximum(),
}
}

// Maximum returns the maximum matcher for the platform.
func Maximum() MatchComparer {
return Ordered(MaximumSpec(), specs.Platform{
OS: "linux",
Architecture: runtime.GOARCH,
// The Variant field will be empty if arch != ARM and AMD64.
Variant: cpuVariantMaximum(),
})
}
15 changes: 15 additions & 0 deletions defaults_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,18 @@ func DefaultSpec() specs.Platform {
func Default() MatchComparer {
return Only(DefaultSpec())
}

// MaximumSpec returns the current platform's maximum platform specification.
func MaximumSpec() specs.Platform {
return specs.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
// The Variant field will be empty if arch != ARM and AMD64.
Variant: cpuVariantMaximum(),
}
}

// Maximum returns the maximum matcher for the platform.
func Maximum() MatchComparer {
return Only(MaximumSpec())
}
17 changes: 17 additions & 0 deletions defaults_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,20 @@ func TestDefault(t *testing.T) {
t.Fatalf("default specifier should match formatted default spec: %v != %v", s, p)
}
}

func TestMaximum(t *testing.T) {
expected := specs.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
Variant: cpuVariantMaximum(),
}
p := MaximumSpec()
if !reflect.DeepEqual(p, expected) {
t.Fatalf("maximum platform not as expected: %#v != %#v", p, expected)
}

s := MaximumString()
if s != FormatAll(p) {
t.Fatalf("maximum specifier should match formatted maximum spec: %v != %v", s, p)
}
}
17 changes: 17 additions & 0 deletions defaults_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,20 @@ func prefix(v string) string {
func Default() MatchComparer {
return Only(DefaultSpec())
}

// MaximumSpec returns the current platform's maximum platform specification.
func MaximumSpec() specs.Platform {
major, minor, build := windows.RtlGetNtVersionNumbers()
return specs.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
// The Variant field will be empty if arch != ARM.
Variant: cpuVariantMaximum(),
}
}

// Maximum returns the current platform's maximum platform specification.
func Maximum() MatchComparer {
return Only(MaximumSpec())
}
19 changes: 19 additions & 0 deletions defaults_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ func TestDefault(t *testing.T) {
}
}

func TestMaximum(t *testing.T) {
major, minor, build := windows.RtlGetNtVersionNumbers()
expected := imagespec.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
Variant: cpuVariantMaximum(),
}
p := MaximumSpec()
if !reflect.DeepEqual(p, expected) {
t.Fatalf("maximum platform not as expected: %#v != %#v", p, expected)
}

s := MaximumString()
if s != FormatAll(p) {
t.Fatalf("maximum specifier should match formatted maximum spec: %v != %v", s, p)
}
}

func TestDefaultMatchComparer(t *testing.T) {
defaultMatcher := Default()

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tonistiigi/go-archvariant v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0=
github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
Expand Down
9 changes: 9 additions & 0 deletions platforms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,15 @@ func TestParseSelector(t *testing.T) {
formatted: "linux/amd64",
useV2Format: false,
},
{
input: "Linux/x86_64/v2",
expected: specs.Platform{
OS: "linux",
Architecture: "amd64",
Variant: "v2",
},
formatted: "linux/amd64/v2",
},
{
input: "i386",
expected: specs.Platform{
Expand Down

0 comments on commit deefb02

Please sign in to comment.