mirror of
https://github.com/beclab/Olares
synced 2026-04-21 13:37:46 +00:00
cli: add functions to detect MThreads AI Book (#2883)
* feat(connector): add functions to detect Mthreads AI Book and RockChip models * feat(gpu): add MThreads GPU support and related modules * fix(cli): remove redundant import of amdgpu package * chore(cli): remove unnecessary tasks when adding node --------- Co-authored-by: dkeven <dkvvven@gmail.com>
This commit is contained in:
parent
ebfa23852e
commit
51214c3d80
14 changed files with 191 additions and 26 deletions
57
cli/pkg/core/connector/mthreads.go
Normal file
57
cli/pkg/core/connector/mthreads.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package connector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func isMthreadsAIBook(cmdExec func(s string) (string, error)) bool {
|
||||
dmidecode, err := cmdExec("command -v dmidecode")
|
||||
if err != nil {
|
||||
fmt.Printf("Error executing dmidecode command: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if len(dmidecode) == 0 {
|
||||
fmt.Println("dmidecode command not found, cannot determine if it's an Mthreads AI Book.")
|
||||
return false
|
||||
}
|
||||
|
||||
output, err := cmdExec("dmidecode -s processor-manufacturer")
|
||||
if err != nil {
|
||||
fmt.Printf("Error executing dmidecode to get processor manufacturer: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return output == "AIBOOK"
|
||||
}
|
||||
|
||||
func isMthreadsAIBookM1000(cmdExec func(s string) (string, error)) bool {
|
||||
if !isMthreadsAIBook(cmdExec) {
|
||||
return false
|
||||
}
|
||||
|
||||
output, err := cmdExec("dmidecode -s processor-version")
|
||||
if err != nil {
|
||||
fmt.Printf("Error executing dmidecode to get processor version: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return output == "M1000"
|
||||
}
|
||||
|
||||
func IsMThreadsAIBookM1000Local() bool {
|
||||
return isMthreadsAIBookM1000(func(s string) (string, error) {
|
||||
out, err := exec.Command("sh", "-c", s).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
})
|
||||
}
|
||||
|
||||
func IsMThreadsAIBookM1000(execRuntime Runtime) bool {
|
||||
return isMthreadsAIBookM1000(func(s string) (string, error) {
|
||||
return execRuntime.GetRunner().SudoCmd(s, false, false)
|
||||
})
|
||||
}
|
||||
37
cli/pkg/core/connector/rockchip.go
Normal file
37
cli/pkg/core/connector/rockchip.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package connector
|
||||
|
||||
import "strings"
|
||||
|
||||
func isRockChip(execRuntime Runtime) bool {
|
||||
// check the /proc/device-tree/model exists and contains "rockchip"
|
||||
out, err := execRuntime.GetRunner().SudoCmd("cat /proc/device-tree/model 2>/dev/null || true", false, false)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if out != "" && strings.Contains(strings.ToLower(out), "rockchip") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isRockChipRK3588(execRuntime Runtime) bool {
|
||||
if !isRockChip(execRuntime) {
|
||||
return false
|
||||
}
|
||||
out, err := execRuntime.GetRunner().SudoCmd("cat /proc/device-tree/model 2>/dev/null || true", false, false)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if out != "" && strings.Contains(strings.ToLower(out), "rk3588") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getRockChipModel(execRuntime Runtime) string {
|
||||
out, err := execRuntime.GetRunner().SudoCmd("cat /proc/device-tree/model 2>/dev/null || true", false, false)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(out)
|
||||
}
|
||||
|
|
@ -81,6 +81,7 @@ type Systems interface {
|
|||
IsAmdApu() bool
|
||||
IsAmdGPU() bool
|
||||
IsAmdGPUOrAPU() bool
|
||||
IsMThreadsM1000() bool
|
||||
|
||||
IsUbuntu() bool
|
||||
IsDebian() bool
|
||||
|
|
@ -257,6 +258,10 @@ func (s *SystemInfo) IsAmdGPUOrAPU() bool {
|
|||
return s.CpuInfo.HasAmdAPU || s.HasAmdGPU
|
||||
}
|
||||
|
||||
func (s *SystemInfo) IsMThreadsM1000() bool {
|
||||
return s.CpuInfo.IsMThreadsM1000
|
||||
}
|
||||
|
||||
func (s *SystemInfo) IsUbuntu() bool {
|
||||
return s.HostInfo.OsPlatformFamily == common.Ubuntu
|
||||
}
|
||||
|
|
@ -469,6 +474,7 @@ type CpuInfo struct {
|
|||
CpuPhysicalCount int `json:"cpu_physical_count"`
|
||||
IsGB10Chip bool `json:"is_gb10_chip,omitempty"`
|
||||
HasAmdAPU bool `json:"has_amd_apu,omitempty"`
|
||||
IsMThreadsM1000 bool `json:"is_mthreads_m1000,omitempty"`
|
||||
}
|
||||
|
||||
// Not considering the case where AMD GPU and AMD APU coexist.
|
||||
|
|
@ -537,6 +543,9 @@ func getCpu() *CpuInfo {
|
|||
hasAmdAPU = false
|
||||
}
|
||||
|
||||
// check if it is mthreads m1000
|
||||
ret.IsMThreadsM1000 = IsMThreadsAIBookM1000Local()
|
||||
|
||||
ret.IsGB10Chip = isGB10Chip
|
||||
ret.HasAmdAPU = hasAmdAPU
|
||||
|
||||
|
|
|
|||
33
cli/pkg/gpu/mtgpu/module.go
Normal file
33
cli/pkg/gpu/mtgpu/module.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package mtgpu
|
||||
|
||||
import (
|
||||
"github.com/beclab/Olares/cli/pkg/common"
|
||||
"github.com/beclab/Olares/cli/pkg/core/task"
|
||||
)
|
||||
|
||||
// InstallMThreadsPluginModule installs MThreads GPU device plugin on Kubernetes.
|
||||
type InstallMThreadsPluginModule struct {
|
||||
common.KubeModule
|
||||
Skip bool // conditional execution based on GPU enablement
|
||||
}
|
||||
|
||||
func (m *InstallMThreadsPluginModule) IsSkip() bool {
|
||||
return m.Skip
|
||||
}
|
||||
|
||||
func (m *InstallMThreadsPluginModule) Init() {
|
||||
m.Name = "InstallMThreadsPlugin"
|
||||
|
||||
// update node with MThreads GPU labels
|
||||
updateNode := &task.RemoteTask{
|
||||
Name: "UpdateNodeMThreadsGPUInfo",
|
||||
Hosts: m.Runtime.GetHostsByRole(common.Master),
|
||||
Action: new(UpdateNodeMThreadsGPUInfo),
|
||||
Parallel: false,
|
||||
Retry: 1,
|
||||
}
|
||||
|
||||
m.Tasks = []task.Interface{
|
||||
updateNode,
|
||||
}
|
||||
}
|
||||
39
cli/pkg/gpu/mtgpu/tasks.go
Normal file
39
cli/pkg/gpu/mtgpu/tasks.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package mtgpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/beclab/Olares/cli/pkg/clientset"
|
||||
"github.com/beclab/Olares/cli/pkg/common"
|
||||
"github.com/beclab/Olares/cli/pkg/core/connector"
|
||||
"github.com/beclab/Olares/cli/pkg/core/logger"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// UpdateNodeMThreadsGPUInfo updates Kubernetes node labels with MThreads GPU information.
|
||||
type UpdateNodeMThreadsGPUInfo struct {
|
||||
common.KubeAction
|
||||
}
|
||||
|
||||
func (u *UpdateNodeMThreadsGPUInfo) Execute(runtime connector.Runtime) error {
|
||||
client, err := clientset.NewKubeClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.WithStack(err), "kubeclient create error")
|
||||
}
|
||||
|
||||
// Check if MThreads AI Book M1000 exists
|
||||
m1000Exists := connector.IsMThreadsAIBookM1000(runtime)
|
||||
if !m1000Exists {
|
||||
logger.Info("MThreads AI Book M1000 is not detected")
|
||||
return nil
|
||||
}
|
||||
|
||||
if runtime.GetSystemInfo().IsAmdApu() {
|
||||
return gpu.UpdateNodeGpuLabel(context.Background(), client.Kubernetes(), nil, nil, nil, ptr.To(gpu.MThreadsM1000Type))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -367,8 +367,6 @@ func (u *UpdateNodeGPUInfo) Execute(runtime connector.Runtime) error {
|
|||
// TODO:
|
||||
gpuType := NvidiaCardType
|
||||
switch {
|
||||
case runtime.GetSystemInfo().IsAmdApu():
|
||||
gpuType = AmdApuCardType
|
||||
case runtime.GetSystemInfo().IsGB10Chip():
|
||||
gpuType = GB10ChipType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,10 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
NvidiaCardType = "nvidia" // handling by HAMi
|
||||
AmdGpuCardType = "amd-gpu" //
|
||||
AmdApuCardType = "amd-apu" // AMD APU with integrated GPU , AI Max 395 etc.
|
||||
GB10ChipType = "nvidia-gb10" // NVIDIA GB10 Superchip & unified system memory
|
||||
StrixHaloChipType = "strix-halo" // AMD Strix Halo GPU & unified system memory
|
||||
NvidiaCardType = "nvidia" // handling by HAMi
|
||||
AmdGpuCardType = "amd-gpu" //
|
||||
AmdApuCardType = "amd-apu" // AMD APU with integrated GPU , AI Max 395 etc.
|
||||
GB10ChipType = "nvidia-gb10" // NVIDIA GB10 Superchip & unified system memory
|
||||
StrixHaloChipType = "strix-halo" // AMD Strix Halo GPU & unified system memory
|
||||
MThreadsM1000Type = "mthreads-m1000" // MThreads M1000 AI Book with integrated GPU
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/beclab/Olares/cli/pkg/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/bootstrap/os"
|
||||
"github.com/beclab/Olares/cli/pkg/common"
|
||||
"github.com/beclab/Olares/cli/pkg/core/logger"
|
||||
"github.com/beclab/Olares/cli/pkg/core/module"
|
||||
"github.com/beclab/Olares/cli/pkg/core/pipeline"
|
||||
"github.com/beclab/Olares/cli/pkg/core/task"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu"
|
||||
"github.com/beclab/Olares/cli/pkg/k3s"
|
||||
"github.com/beclab/Olares/cli/pkg/kubernetes"
|
||||
"github.com/beclab/Olares/cli/pkg/manifest"
|
||||
|
|
@ -79,23 +76,10 @@ func (m *AddNodeModule) Init() {
|
|||
&k3s.JoinNodesModule{},
|
||||
}
|
||||
}
|
||||
m.underlyingModules = append(m.underlyingModules, &gpu.NodeLabelingModule{})
|
||||
for _, underlyingModule := range m.underlyingModules {
|
||||
underlyingModule.Default(m.Runtime, m.PipelineCache, m.ModuleCache)
|
||||
underlyingModule.AutoAssert()
|
||||
underlyingModule.Init()
|
||||
m.Tasks = append(m.Tasks, underlyingModule.GetTasks()...)
|
||||
}
|
||||
m.Tasks = append(m.Tasks,
|
||||
&task.RemoteTask{
|
||||
Name: "UpdateNodeGPUInfo",
|
||||
Action: new(gpu.UpdateNodeGPUInfo),
|
||||
Retry: 1,
|
||||
},
|
||||
&task.LocalTask{
|
||||
Name: "UpdateNodeAmdGPUInfo",
|
||||
Action: new(amdgpu.UpdateNodeAmdGPUInfo),
|
||||
Retry: 1,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/beclab/Olares/cli/pkg/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/common"
|
||||
"github.com/beclab/Olares/cli/pkg/core/module"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu/mtgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/kubesphere/plugins"
|
||||
"github.com/beclab/Olares/cli/pkg/manifest"
|
||||
"github.com/beclab/Olares/cli/pkg/storage"
|
||||
|
|
@ -65,6 +66,12 @@ func (l *linuxInstallPhaseBuilder) installGpuPlugin() phase {
|
|||
}
|
||||
return true
|
||||
}()},
|
||||
&mtgpu.InstallMThreadsPluginModule{Skip: func() bool {
|
||||
if l.runtime.GetSystemInfo().IsMThreadsM1000() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}()},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package system
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/beclab/Olares/cli/pkg/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/bootstrap/os"
|
||||
"github.com/beclab/Olares/cli/pkg/bootstrap/patch"
|
||||
"github.com/beclab/Olares/cli/pkg/bootstrap/precheck"
|
||||
|
|
@ -12,6 +11,7 @@ import (
|
|||
"github.com/beclab/Olares/cli/pkg/core/module"
|
||||
"github.com/beclab/Olares/cli/pkg/daemon"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/images"
|
||||
"github.com/beclab/Olares/cli/pkg/k3s"
|
||||
"github.com/beclab/Olares/cli/pkg/manifest"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package pipelines
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/beclab/Olares/cli/pkg/amdgpu"
|
||||
"github.com/beclab/Olares/cli/pkg/common"
|
||||
"github.com/beclab/Olares/cli/pkg/core/action"
|
||||
"github.com/beclab/Olares/cli/pkg/core/connector"
|
||||
|
|
@ -11,6 +10,7 @@ import (
|
|||
"github.com/beclab/Olares/cli/pkg/core/module"
|
||||
"github.com/beclab/Olares/cli/pkg/core/pipeline"
|
||||
"github.com/beclab/Olares/cli/pkg/core/task"
|
||||
"github.com/beclab/Olares/cli/pkg/gpu/amdgpu"
|
||||
)
|
||||
|
||||
type singleTaskModule struct {
|
||||
|
|
|
|||
Loading…
Reference in a new issue