Skip to content

Commit f439dfa

Browse files
committed
Add AMD64 micro architecture level support
This commit adds the support for AMD64 micro architecture levels on Linux. Signed-off-by: Zhongcheng Lao <[email protected]>
1 parent a413568 commit f439dfa

15 files changed

+169
-8
lines changed

cpuinfo.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import (
2121
"sync"
2222

2323
"github.com/containerd/log"
24+
amd64variant "github.com/tonistiigi/go-archvariant"
2425
)
2526

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

@@ -33,11 +35,34 @@ func cpuVariant() string {
3335
cpuVariantOnce.Do(func() {
3436
if isArmArch(runtime.GOARCH) {
3537
var err error
36-
cpuVariantValue, err = getCPUVariant()
38+
cpuVariantValue, err = getArmCPUVariant()
3739
if err != nil {
38-
log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
40+
log.L.Errorf("Error getArmCPUVariant for OS %s: %v", runtime.GOOS, err)
3941
}
4042
}
4143
})
4244
return cpuVariantValue
4345
}
46+
47+
func cpuVariantMaximum() string {
48+
cpuVariantOnce.Do(func() {
49+
if isArmArch(runtime.GOARCH) {
50+
var err error
51+
cpuVariantValue, err = getArmCPUVariant()
52+
if err != nil {
53+
log.L.Errorf("Error getArmCPUVariant for OS %s: %v", runtime.GOOS, err)
54+
}
55+
} else if isAmd64Arch(runtime.GOARCH) {
56+
var err error
57+
cpuVariantValue, err = getAmd64MicroArchLevel()
58+
if err != nil {
59+
log.L.Errorf("Error getAmd64MicroArchLevel for OS %s: %v", runtime.GOOS, err)
60+
}
61+
}
62+
})
63+
return cpuVariantValue
64+
}
65+
66+
func getAmd64MicroArchLevel() (string, error) {
67+
return amd64variant.AMD64Variant(), nil
68+
}

cpuinfo_linux.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ func getCPUVariantFromArch(arch string) (string, error) {
106106
return variant, nil
107107
}
108108

109-
// getCPUVariant returns cpu variant for ARM
109+
// getArmCPUVariant returns cpu variant for ARM
110110
// We first try reading "Cpu architecture" field from /proc/cpuinfo
111111
// If we can't find it, then fall back using a system call
112112
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
113113
// was not present.
114-
func getCPUVariant() (string, error) {
114+
func getArmCPUVariant() (string, error) {
115115
variant, err := getCPUInfo("Cpu architecture")
116116
if err != nil {
117117
if errors.Is(err, errNotFound) {

cpuinfo_linux_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestCPUVariant(t *testing.T) {
2929

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

32-
p, err := getCPUVariant()
32+
p, err := getArmCPUVariant()
3333
if err != nil {
3434
t.Fatalf("Error getting CPU variant: %v", err)
3535
return

cpuinfo_other.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"runtime"
2424
)
2525

26-
func getCPUVariant() (string, error) {
26+
func getArmCPUVariant() (string, error) {
2727

2828
var variant string
2929

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

5454
return variant, nil

database.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ func isArmArch(arch string) bool {
4848
return false
4949
}
5050

51+
// isAmd64Arch returns true if the architecture is AMD64.
52+
//
53+
// The arch value should be normalized before being passed to this function.
54+
func isAmd64Arch(arch string) bool {
55+
return arch == "amd64"
56+
}
57+
5158
// isKnownArch returns true if we know about the architecture.
5259
//
5360
// The arch value should be normalized before being passed to this function.

defaults.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,13 @@ func DefaultString() string {
2727
func DefaultStrict() MatchComparer {
2828
return OnlyStrict(DefaultSpec())
2929
}
30+
31+
// MaximumString returns the maximum string specifier for the platform.
32+
func MaximumString() string {
33+
return FormatAll(MaximumSpec())
34+
}
35+
36+
// MaximumStrict returns strict form of Maximum.
37+
func MaximumStrict() MatchComparer {
38+
return OnlyStrict(MaximumSpec())
39+
}

defaults_darwin.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,22 @@ func Default() MatchComparer {
4242
Architecture: runtime.GOARCH,
4343
})
4444
}
45+
46+
// MaximumSpec returns the current platform's maximum platform specification.
47+
func MaximumSpec() specs.Platform {
48+
return specs.Platform{
49+
OS: runtime.GOOS,
50+
Architecture: runtime.GOARCH,
51+
// The Variant field will be empty if arch != ARM and AMD64.
52+
Variant: cpuVariantMaximum(),
53+
}
54+
}
55+
56+
// Maximum returns the maximum matcher for the platform.
57+
func Maximum() MatchComparer {
58+
return Ordered(MaximumSpec(), specs.Platform{
59+
// darwin runtime also supports Linux binary via runu/LKL
60+
OS: "linux",
61+
Architecture: runtime.GOARCH,
62+
})
63+
}

defaults_freebsd.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,23 @@ func Default() MatchComparer {
4141
Variant: cpuVariant(),
4242
})
4343
}
44+
45+
// MaximumSpec returns the current platform's maximum platform specification.
46+
func MaximumSpec() specs.Platform {
47+
return specs.Platform{
48+
OS: runtime.GOOS,
49+
Architecture: runtime.GOARCH,
50+
// The Variant field will be empty if arch != ARM and AMD64.
51+
Variant: cpuVariantMaximum(),
52+
}
53+
}
54+
55+
// Maximum returns the maximum matcher for the platform.
56+
func Maximum() MatchComparer {
57+
return Ordered(MaximumSpec(), specs.Platform{
58+
OS: "linux",
59+
Architecture: runtime.GOARCH,
60+
// The Variant field will be empty if arch != ARM and AMD64.
61+
Variant: cpuVariantMaximum(),
62+
})
63+
}

defaults_unix.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,18 @@ func DefaultSpec() specs.Platform {
3838
func Default() MatchComparer {
3939
return Only(DefaultSpec())
4040
}
41+
42+
// MaximumSpec returns the current platform's maximum platform specification.
43+
func MaximumSpec() specs.Platform {
44+
return specs.Platform{
45+
OS: runtime.GOOS,
46+
Architecture: runtime.GOARCH,
47+
// The Variant field will be empty if arch != ARM and AMD64.
48+
Variant: cpuVariantMaximum(),
49+
}
50+
}
51+
52+
// Maximum returns the maximum matcher for the platform.
53+
func Maximum() MatchComparer {
54+
return Only(MaximumSpec())
55+
}

defaults_unix_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,20 @@ func TestDefault(t *testing.T) {
4242
t.Fatalf("default specifier should match formatted default spec: %v != %v", s, p)
4343
}
4444
}
45+
46+
func TestMaximum(t *testing.T) {
47+
expected := specs.Platform{
48+
OS: runtime.GOOS,
49+
Architecture: runtime.GOARCH,
50+
Variant: cpuVariantMaximum(),
51+
}
52+
p := MaximumSpec()
53+
if !reflect.DeepEqual(p, expected) {
54+
t.Fatalf("maximum platform not as expected: %#v != %#v", p, expected)
55+
}
56+
57+
s := MaximumString()
58+
if s != FormatAll(p) {
59+
t.Fatalf("maximum specifier should match formatted maximum spec: %v != %v", s, p)
60+
}
61+
}

defaults_windows.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,20 @@ func prefix(v string) string {
116116
func Default() MatchComparer {
117117
return Only(DefaultSpec())
118118
}
119+
120+
// MaximumSpec returns the current platform's maximum platform specification.
121+
func MaximumSpec() specs.Platform {
122+
major, minor, build := windows.RtlGetNtVersionNumbers()
123+
return specs.Platform{
124+
OS: runtime.GOOS,
125+
Architecture: runtime.GOARCH,
126+
OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
127+
// The Variant field will be empty if arch != ARM.
128+
Variant: cpuVariantMaximum(),
129+
}
130+
}
131+
132+
// Maximum returns the current platform's maximum platform specification.
133+
func Maximum() MatchComparer {
134+
return Only(MaximumSpec())
135+
}

defaults_windows_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ func TestDefault(t *testing.T) {
4747
}
4848
}
4949

50+
func TestMaximum(t *testing.T) {
51+
major, minor, build := windows.RtlGetNtVersionNumbers()
52+
expected := imagespec.Platform{
53+
OS: runtime.GOOS,
54+
Architecture: runtime.GOARCH,
55+
OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
56+
Variant: cpuVariantMaximum(),
57+
}
58+
p := MaximumSpec()
59+
if !reflect.DeepEqual(p, expected) {
60+
t.Fatalf("maximum platform not as expected: %#v != %#v", p, expected)
61+
}
62+
63+
s := MaximumString()
64+
if s != FormatAll(p) {
65+
t.Fatalf("maximum specifier should match formatted maximum spec: %v != %v", s, p)
66+
}
67+
}
68+
5069
func TestDefaultMatchComparer(t *testing.T) {
5170
defaultMatcher := Default()
5271

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/containerd/log v0.1.0
77
github.com/opencontainers/image-spec v1.1.0
88
github.com/stretchr/testify v1.8.4
9+
github.com/tonistiigi/go-archvariant v1.0.0
910
golang.org/x/sys v0.26.0
1011
)
1112

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
1515
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
1616
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
1717
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
18+
github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0=
19+
github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho=
1820
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1921
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
2022
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

platforms_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,15 @@ func TestParseSelector(t *testing.T) {
263263
formatted: "linux/amd64",
264264
useV2Format: false,
265265
},
266+
{
267+
input: "Linux/x86_64/v2",
268+
expected: specs.Platform{
269+
OS: "linux",
270+
Architecture: "amd64",
271+
Variant: "v2",
272+
},
273+
formatted: "linux/amd64/v2",
274+
},
266275
{
267276
input: "i386",
268277
expected: specs.Platform{

0 commit comments

Comments
 (0)