Skip to content

Commit 659c752

Browse files
committed
Add ResolvePlatform function to info package
Signed-off-by: Evan Lezar <[email protected]>
1 parent 902ae83 commit 659c752

File tree

7 files changed

+270
-12
lines changed

7 files changed

+270
-12
lines changed

pkg/nvlib/info/api.go

+6
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ package info
1818

1919
// Interface provides the API to the info package.
2020
type Interface interface {
21+
PlatformResolver
2122
Properties
2223
}
2324

25+
// PlatformResolver defines a function to resolve a mode.
26+
type PlatformResolver interface {
27+
ResolvePlatform() Platform
28+
}
29+
2430
// Properties provides a set of functions to query capabilities of the system.
2531
//
2632
//go:generate moq -rm -stub -out properties_mock.go . Properties

pkg/nvlib/info/builder.go

+25-4
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,24 @@ import (
2323
)
2424

2525
type options struct {
26+
logger basicLogger
2627
root root
2728
nvmllib nvml.Interface
2829
devicelib device.Interface
30+
31+
platform Platform
32+
properties Properties
2933
}
3034

31-
// New creates a new instance of the 'info' Interface.
35+
// New creates a new instance of the 'info' interface.
3236
func New(opts ...Option) Interface {
3337
o := &options{}
3438
for _, opt := range opts {
3539
opt(o)
3640
}
41+
if o.logger == nil {
42+
o.logger = &nullLogger{}
43+
}
3744
if o.root == "" {
3845
o.root = "/"
3946
}
@@ -45,9 +52,23 @@ func New(opts ...Option) Interface {
4552
if o.devicelib == nil {
4653
o.devicelib = device.New(device.WithNvml(o.nvmllib))
4754
}
55+
if o.platform == "" {
56+
o.platform = PlatformAuto
57+
}
58+
if o.properties == nil {
59+
o.properties = &info{
60+
root: o.root,
61+
nvmllib: o.nvmllib,
62+
devicelib: o.devicelib,
63+
}
64+
}
4865
return &infolib{
49-
root: o.root,
50-
nvmllib: o.nvmllib,
51-
devicelib: o.devicelib,
66+
logger: o.logger,
67+
PlatformResolver: &platformResolver{
68+
logger: o.logger,
69+
platform: o.platform,
70+
Properties: o.properties,
71+
},
72+
Properties: o.properties,
5273
}
5374
}

pkg/nvlib/info/info.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,22 @@ import (
2727
)
2828

2929
type infolib struct {
30+
logger basicLogger
31+
Properties
32+
PlatformResolver
33+
}
34+
35+
type info struct {
3036
root root
3137
nvmllib nvml.Interface
3238
devicelib device.Interface
3339
}
3440

41+
var _ Properties = &info{}
3542
var _ Interface = &infolib{}
3643

3744
// HasDXCore returns true if DXCore is detected on the system.
38-
func (i *infolib) HasDXCore() (bool, string) {
45+
func (i *info) HasDXCore() (bool, string) {
3946
const (
4047
libraryName = "libdxcore.so"
4148
)
@@ -47,7 +54,7 @@ func (i *infolib) HasDXCore() (bool, string) {
4754
}
4855

4956
// HasNvml returns true if NVML is detected on the system.
50-
func (i *infolib) HasNvml() (bool, string) {
57+
func (i *info) HasNvml() (bool, string) {
5158
const (
5259
libraryName = "libnvidia-ml.so.1"
5360
)
@@ -59,7 +66,7 @@ func (i *infolib) HasNvml() (bool, string) {
5966
}
6067

6168
// IsTegraSystem returns true if the system is detected as a Tegra-based system.
62-
func (i *infolib) IsTegraSystem() (bool, string) {
69+
func (i *info) IsTegraSystem() (bool, string) {
6370
tegraReleaseFile := i.root.join("/etc/nv_tegra_release")
6471
tegraFamilyFile := i.root.join("/sys/devices/soc0/family")
6572

@@ -93,7 +100,7 @@ func (i *infolib) IsTegraSystem() (bool, string) {
93100
// GPU 0: Orin (nvgpu) (UUID: 54d0709b-558d-5a59-9c65-0c5fc14a21a4)
94101
//
95102
// This function returns true if ALL devices use the nvgpu module.
96-
func (i *infolib) UsesOnlyNVGPUModule() (uses bool, reason string) {
103+
func (i *info) UsesOnlyNVGPUModule() (uses bool, reason string) {
97104
// We ensure that this function never panics
98105
defer func() {
99106
if err := recover(); err != nil {

pkg/nvlib/info/logger.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
# Copyright 2024 NVIDIA CORPORATION
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package info
18+
19+
type basicLogger interface {
20+
Debugf(string, ...interface{})
21+
Infof(string, ...interface{})
22+
}
23+
24+
type nullLogger struct{}
25+
26+
func (n *nullLogger) Debugf(string, ...interface{}) {}
27+
28+
func (n *nullLogger) Infof(string, ...interface{}) {}

pkg/nvlib/info/options.go

+26-4
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,22 @@ type Option func(*options)
2727

2828
// WithDeviceLib sets the device library for the library.
2929
func WithDeviceLib(devicelib device.Interface) Option {
30-
return func(l *options) {
31-
l.devicelib = devicelib
30+
return func(i *options) {
31+
i.devicelib = devicelib
32+
}
33+
}
34+
35+
// WithLogger sets the logger for the library.
36+
func WithLogger(logger basicLogger) Option {
37+
return func(i *options) {
38+
i.logger = logger
3239
}
3340
}
3441

3542
// WithNvmlLib sets the nvml library for the library.
3643
func WithNvmlLib(nvmllib nvml.Interface) Option {
37-
return func(l *options) {
38-
l.nvmllib = nvmllib
44+
return func(i *options) {
45+
i.nvmllib = nvmllib
3946
}
4047
}
4148

@@ -45,3 +52,18 @@ func WithRoot(r string) Option {
4552
i.root = root(r)
4653
}
4754
}
55+
56+
// WithProperties provides an Option to set the Properties interface implementation.
57+
// This is predominantly used for testing.
58+
func WithProperties(properties Properties) Option {
59+
return func(i *options) {
60+
i.properties = properties
61+
}
62+
}
63+
64+
// WithPlatform provides an option to set the platform explicitly.
65+
func WithPlatform(platform Platform) Option {
66+
return func(i *options) {
67+
i.platform = platform
68+
}
69+
}

pkg/nvlib/info/resolver.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
# Copyright 2024 NVIDIA CORPORATION
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package info
18+
19+
// Platform represents a supported plaform.
20+
type Platform string
21+
22+
const (
23+
PlatformAuto = Platform("auto")
24+
PlatformNVML = Platform("nvml")
25+
PlatformTegra = Platform("tegra")
26+
PlatformWSL = Platform("wsl")
27+
PlatformUnknown = Platform("unknown")
28+
)
29+
30+
type platformResolver struct {
31+
logger basicLogger
32+
platform Platform
33+
Properties
34+
}
35+
36+
func (p platformResolver) ResolvePlatform() Platform {
37+
if p.platform != PlatformAuto {
38+
p.logger.Infof("Using requested platform '%s'", p.platform)
39+
return p.platform
40+
}
41+
42+
isWSL, reason := p.HasDXCore()
43+
p.logger.Debugf("Is WSL-based system? %v: %v", isWSL, reason)
44+
45+
isTegra, reason := p.IsTegraSystem()
46+
p.logger.Debugf("Is Tegra-based system? %v: %v", isTegra, reason)
47+
48+
hasNVML, reason := p.HasNvml()
49+
p.logger.Debugf("Is NVML-based system? %v: %v", hasNVML, reason)
50+
51+
usesNVGPUModule, reason := p.UsesOnlyNVGPUModule()
52+
p.logger.Debugf("Uses nvgpu kernel module? %v: %v", usesNVGPUModule, reason)
53+
54+
switch {
55+
case isWSL:
56+
return PlatformWSL
57+
case (isTegra && !hasNVML), usesNVGPUModule:
58+
return PlatformTegra
59+
case hasNVML:
60+
return PlatformNVML
61+
default:
62+
return PlatformUnknown
63+
}
64+
}

pkg/nvlib/info/resolver_test.go

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package info
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
23+
"github.com/stretchr/testify/require"
24+
)
25+
26+
func TestResolvePlatform(t *testing.T) {
27+
testCases := []struct {
28+
platform string
29+
isTegra bool
30+
hasDXCore bool
31+
hasNVML bool
32+
usesOnlyNVGPUModule bool
33+
expected string
34+
}{
35+
{
36+
platform: "auto",
37+
hasDXCore: true,
38+
expected: "wsl",
39+
},
40+
{
41+
platform: "auto",
42+
hasDXCore: false,
43+
isTegra: true,
44+
hasNVML: false,
45+
expected: "tegra",
46+
},
47+
{
48+
platform: "auto",
49+
hasDXCore: false,
50+
isTegra: false,
51+
hasNVML: false,
52+
expected: "unknown",
53+
},
54+
{
55+
platform: "auto",
56+
hasDXCore: false,
57+
isTegra: true,
58+
hasNVML: true,
59+
expected: "nvml",
60+
},
61+
{
62+
platform: "auto",
63+
hasDXCore: false,
64+
isTegra: true,
65+
hasNVML: true,
66+
usesOnlyNVGPUModule: true,
67+
expected: "tegra",
68+
},
69+
{
70+
platform: "nvml",
71+
hasDXCore: true,
72+
isTegra: true,
73+
expected: "nvml",
74+
},
75+
{
76+
platform: "wsl",
77+
hasDXCore: false,
78+
expected: "wsl",
79+
},
80+
{
81+
platform: "not-auto",
82+
hasDXCore: true,
83+
expected: "not-auto",
84+
},
85+
}
86+
87+
for i, tc := range testCases {
88+
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
89+
l := New(
90+
WithProperties(&PropertiesMock{
91+
HasDXCoreFunc: func() (bool, string) {
92+
return tc.hasDXCore, ""
93+
},
94+
HasNvmlFunc: func() (bool, string) {
95+
return tc.hasNVML, ""
96+
},
97+
IsTegraSystemFunc: func() (bool, string) {
98+
return tc.isTegra, ""
99+
},
100+
UsesOnlyNVGPUModuleFunc: func() (bool, string) {
101+
return tc.usesOnlyNVGPUModule, ""
102+
},
103+
}),
104+
WithPlatform(Platform(tc.platform)),
105+
)
106+
107+
require.Equal(t, Platform(tc.expected), l.ResolvePlatform())
108+
})
109+
}
110+
}

0 commit comments

Comments
 (0)