mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
feat(llm,host): support Hygon DCU runtime for vLLM containers (#25258)
Wire vendor on LLM SKU devices, resolve supplemental groups for DCU access, source DTK env in vLLM entrypoint, and add hysmi telegraf metrics.
This commit is contained in:
@@ -70,8 +70,10 @@ const (
|
||||
)
|
||||
|
||||
type ContainerSecurityContext struct {
|
||||
RunAsUser *int64 `json:"run_as_user,omitempty"`
|
||||
RunAsGroup *int64 `json:"run_as_group,omitempty"`
|
||||
RunAsUser *int64 `json:"run_as_user,omitempty"`
|
||||
RunAsGroup *int64 `json:"run_as_group,omitempty"`
|
||||
SupplementalGroups []int64 `json:"supplemental_groups,omitempty"`
|
||||
SupplementalGroupNames []string `json:"supplemental_group_names,omitempty"`
|
||||
// procMount denotes the type of proc mount to use for the containers.
|
||||
// The default is DefaultProcMount which uses the container runtime defaults for
|
||||
ProcMount ContainerProcMountType `json:"proc_mount"`
|
||||
|
||||
@@ -80,6 +80,7 @@ func (s PortMappings) IsZero() bool {
|
||||
type Device struct {
|
||||
DevType string `json:"dev_type"`
|
||||
SharingMode string `json:"sharing_mode,omitempty"`
|
||||
Vendor string `json:"vendor,omitempty"`
|
||||
Model string `json:"model"`
|
||||
DevicePath string `json:"device_path"`
|
||||
// MemoryMb is optional per-device VRAM (MiB) for HAMI. When > 0 it is used
|
||||
|
||||
@@ -877,6 +877,10 @@ type PCIDevModelTypes struct {
|
||||
|
||||
VirtualDev bool
|
||||
Hypervisor string
|
||||
|
||||
Vendor string `json:"vendor,allowempty"`
|
||||
VendorDeviceId string `json:"vendor_device_id,allowempty"`
|
||||
PciId string `json:"pci_id,allowempty"`
|
||||
}
|
||||
|
||||
func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, zone *SZone, domainId, tenantId string) ([]string, []PCIDevModelTypes) {
|
||||
@@ -918,7 +922,7 @@ func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
devices := devicesQ.SubQuery()
|
||||
hosts := hostQuery.SubQuery()
|
||||
|
||||
q := devices.Query(hosts.Field("host_type"), devices.Field("model"), devices.Field("dev_type"), devices.Field("sharing_mode"), devices.Field("nvme_size_mb"), devices.Field("memory_size"))
|
||||
q := devices.Query(hosts.Field("host_type"), devices.Field("vendor_device_id"), devices.Field("model"), devices.Field("dev_type"), devices.Field("sharing_mode"), devices.Field("nvme_size_mb"), devices.Field("memory_size"))
|
||||
q = q.Filter(sqlchemy.NotIn(devices.Field("dev_type"), []string{api.USB_TYPE, api.NIC_TYPE}))
|
||||
if zone != nil {
|
||||
q = q.Join(hosts, sqlchemy.Equals(devices.Field("host_id"), hosts.Field("id")))
|
||||
@@ -937,7 +941,7 @@ func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
sqlchemy.IsNullOrEmpty(hosts.Field("manager_id")),
|
||||
))
|
||||
}*/
|
||||
q = q.GroupBy(hosts.Field("host_type"), devices.Field("model"), devices.Field("dev_type"), devices.Field("sharing_mode"), devices.Field("nvme_size_mb"), devices.Field("memory_size"))
|
||||
q = q.GroupBy(hosts.Field("host_type"), devices.Field("vendor_device_id"), devices.Field("model"), devices.Field("dev_type"), devices.Field("sharing_mode"), devices.Field("nvme_size_mb"), devices.Field("memory_size"))
|
||||
|
||||
rows, err := q.Rows()
|
||||
if err != nil {
|
||||
@@ -949,12 +953,13 @@ func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
gpuModels := make([]string, 0)
|
||||
for rows.Next() {
|
||||
var m, t, sharingMode string
|
||||
var vendorDeviceId string
|
||||
var nvmeSizeMB int
|
||||
var memSizeMB int
|
||||
var vdev bool
|
||||
var hypervisor string
|
||||
var hostType string
|
||||
rows.Scan(&hostType, &m, &t, &sharingMode, &nvmeSizeMB, &memSizeMB)
|
||||
rows.Scan(&hostType, &vendorDeviceId, &m, &t, &sharingMode, &nvmeSizeMB, &memSizeMB)
|
||||
|
||||
if m == "" {
|
||||
continue
|
||||
@@ -972,7 +977,18 @@ func getIsolatedDeviceInfo(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
hypervisor = api.HYPERVISOR_ZETTAKIT
|
||||
}
|
||||
|
||||
gpus = append(gpus, PCIDevModelTypes{m, t, sharingMode, nvmeSizeMB, memSizeMB, vdev, hypervisor})
|
||||
gpus = append(gpus, PCIDevModelTypes{
|
||||
Model: m,
|
||||
DevType: t,
|
||||
SharingMode: sharingMode,
|
||||
NvmeSizeMB: nvmeSizeMB,
|
||||
DevMemorySize: memSizeMB,
|
||||
VirtualDev: vdev,
|
||||
Hypervisor: hypervisor,
|
||||
Vendor: GetVendorByVendorDeviceId(vendorDeviceId),
|
||||
VendorDeviceId: vendorDeviceId,
|
||||
PciId: vendorDeviceId,
|
||||
})
|
||||
|
||||
if !utils.IsInStringArray(m, gpuModels) {
|
||||
gpuModels = append(gpuModels, m)
|
||||
|
||||
@@ -2139,6 +2139,13 @@ func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclie
|
||||
LocalhostRef: secInput.ApparmorProfile,
|
||||
}
|
||||
}
|
||||
supplementalGroups, err := resolveSupplementalGroups(secInput.SupplementalGroups, secInput.SupplementalGroupNames)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "resolve supplemental groups")
|
||||
}
|
||||
if len(supplementalGroups) > 0 {
|
||||
ctrCfg.Linux.SecurityContext.SupplementalGroups = supplementalGroups
|
||||
}
|
||||
}
|
||||
|
||||
if spec.EnableLxcfs {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package guestman
|
||||
|
||||
import (
|
||||
"os/user"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func parseGroupEntLine(line string) (int64, error) {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
return 0, errors.Error("empty group entry")
|
||||
}
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) < 3 {
|
||||
return 0, errors.Errorf("invalid group entry: %q", line)
|
||||
}
|
||||
gid, err := strconv.ParseInt(parts[2], 10, 64)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "parse gid from group entry %q", line)
|
||||
}
|
||||
return gid, nil
|
||||
}
|
||||
|
||||
func lookupHostGroupGID(name string) (int64, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return 0, errors.Error("group name is empty")
|
||||
}
|
||||
out, err := procutils.NewRemoteCommandAsFarAsPossible("getent", "group", name).Output()
|
||||
if err == nil {
|
||||
if gid, parseErr := parseGroupEntLine(string(out)); parseErr == nil {
|
||||
return gid, nil
|
||||
}
|
||||
}
|
||||
grp, lookupErr := user.LookupGroup(name)
|
||||
if lookupErr != nil {
|
||||
return 0, errors.Wrapf(lookupErr, "lookup group %q", name)
|
||||
}
|
||||
gid, err := strconv.ParseInt(grp.Gid, 10, 64)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "parse gid for group %q", name)
|
||||
}
|
||||
return gid, nil
|
||||
}
|
||||
|
||||
func resolveSupplementalGroups(gids []int64, names []string) ([]int64, error) {
|
||||
seen := make(map[int64]struct{}, len(gids)+len(names))
|
||||
out := make([]int64, 0, len(gids)+len(names))
|
||||
for _, gid := range gids {
|
||||
if _, ok := seen[gid]; ok {
|
||||
continue
|
||||
}
|
||||
seen[gid] = struct{}{}
|
||||
out = append(out, gid)
|
||||
}
|
||||
for _, name := range names {
|
||||
gid, err := lookupHostGroupGID(name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "resolve supplemental group %q", name)
|
||||
}
|
||||
if _, ok := seen[gid]; ok {
|
||||
continue
|
||||
}
|
||||
seen[gid] = struct{}{}
|
||||
out = append(out, gid)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package guestman
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseGroupEntLine(t *testing.T) {
|
||||
gid, err := parseGroupEntLine("video:x:44:")
|
||||
if err != nil {
|
||||
t.Fatalf("parseGroupEntLine: %v", err)
|
||||
}
|
||||
if gid != 44 {
|
||||
t.Fatalf("gid = %d, want 44", gid)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_resolveSupplementalGroups(t *testing.T) {
|
||||
out, err := resolveSupplementalGroups([]int64{44, 100}, []string{})
|
||||
if err != nil {
|
||||
t.Fatalf("resolveSupplementalGroups: %v", err)
|
||||
}
|
||||
want := []int64{44, 100}
|
||||
if !reflect.DeepEqual(out, want) {
|
||||
t.Fatalf("got %v, want %v", out, want)
|
||||
}
|
||||
|
||||
out, err = resolveSupplementalGroups([]int64{44}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("resolveSupplementalGroups single gid: %v", err)
|
||||
}
|
||||
want = []int64{44}
|
||||
if !reflect.DeepEqual(out, want) {
|
||||
t.Fatalf("single gid got %v, want %v", out, want)
|
||||
}
|
||||
}
|
||||
@@ -2690,9 +2690,14 @@ func (h *SHostInfo) injectTelegrafDeviceConfig(conf map[string]interface{}) {
|
||||
// group dev
|
||||
hasNetint := false
|
||||
hasVasmi := false
|
||||
hasHygon := false
|
||||
hasNvidiasmi := false
|
||||
hasNpusmi := false
|
||||
for _, dev := range devs {
|
||||
vendorId := strings.Split(dev.GetVendorDeviceId(), ":")[0]
|
||||
if vendorId == api.HYGON_VENDOR_ID {
|
||||
hasHygon = true
|
||||
}
|
||||
if !utils.IsInStringArray(dev.GetSharingMode(), api.VIRTUAL_SHARING_MODES) {
|
||||
continue
|
||||
}
|
||||
@@ -2701,7 +2706,6 @@ func (h *SHostInfo) injectTelegrafDeviceConfig(conf map[string]interface{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
vendorId := strings.Split(dev.GetVendorDeviceId(), ":")[0]
|
||||
switch vendorId {
|
||||
case api.AMD_VENDOR_ID:
|
||||
confMap, ok := conf[system_service.TELEGRAF_INPUT_RADEONTOP].(map[string]interface{})
|
||||
@@ -2735,6 +2739,11 @@ func (h *SHostInfo) injectTelegrafDeviceConfig(conf map[string]interface{}) {
|
||||
system_service.TELEGRAF_INPUT_CONF_BIN_PATH: "/usr/bin/vasmi",
|
||||
}
|
||||
}
|
||||
if hasHygon {
|
||||
conf[system_service.TELEGRAF_INPUT_HYSMI] = map[string]interface{}{
|
||||
system_service.TELEGRAF_INPUT_CONF_BIN_PATH: options.HostOptions.HygonHySmiPath,
|
||||
}
|
||||
}
|
||||
if hasNvidiasmi {
|
||||
conf[system_service.TELEGRAF_INPUT_NVIDIASMI] = struct{}{}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ func (m *hygonDCUManager) GetContainerExtraConfigures(devs []*hostapi.ContainerD
|
||||
|
||||
func buildHygonRuntimeMounts() []*runtimeapi.Mount {
|
||||
hyhalPath := options.HostOptions.HygonHyhalPath
|
||||
dtkPath := options.HostOptions.HygonDtkPath
|
||||
//dtkPath := options.HostOptions.HygonDtkPath
|
||||
mounts := []*runtimeapi.Mount{}
|
||||
if hygonPathExists(hyhalPath) {
|
||||
mounts = append(mounts, &runtimeapi.Mount{
|
||||
@@ -127,21 +127,21 @@ func buildHygonRuntimeMounts() []*runtimeapi.Mount {
|
||||
Readonly: true,
|
||||
})
|
||||
}
|
||||
if hygonPathExists(dtkPath) {
|
||||
/*if hygonPathExists(dtkPath) {
|
||||
mounts = append(mounts, &runtimeapi.Mount{
|
||||
ContainerPath: dtkPath,
|
||||
HostPath: dtkPath,
|
||||
Readonly: true,
|
||||
})
|
||||
}
|
||||
}*/
|
||||
return mounts
|
||||
}
|
||||
|
||||
func buildHygonRuntimeEnvs(indices []string) []*runtimeapi.KeyValue {
|
||||
hyhalPath := options.HostOptions.HygonHyhalPath
|
||||
dtkPath := options.HostOptions.HygonDtkPath
|
||||
// hyhalPath := options.HostOptions.HygonHyhalPath
|
||||
// dtkPath := options.HostOptions.HygonDtkPath
|
||||
envs := []*runtimeapi.KeyValue{
|
||||
{
|
||||
/*{
|
||||
Key: "HYGON_VISIBLE_DEVICES",
|
||||
Value: strings.Join(indices, ","),
|
||||
},
|
||||
@@ -160,7 +160,7 @@ func buildHygonRuntimeEnvs(indices []string) []*runtimeapi.KeyValue {
|
||||
{
|
||||
Key: "ROCM_SMI_LIB_PATH",
|
||||
Value: path.Join(hyhalPath, "lib"),
|
||||
},
|
||||
},*/
|
||||
}
|
||||
return envs
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
TELEGRAF_INPUT_CONF_BIN_PATH = "bin_path"
|
||||
TELEGRAF_INPUT_NETDEV = "ni_rsrc_mon"
|
||||
TELEGRAF_INPUT_VASMI = "vasmi"
|
||||
TELEGRAF_INPUT_HYSMI = "hysmi"
|
||||
TELEGRAF_INPUT_NVIDIASMI = "nvidia-smi"
|
||||
TELEGRAF_INPUT_NPUSMI = "npu-smi"
|
||||
)
|
||||
@@ -338,6 +339,13 @@ func (s *STelegraf) GetConfig(kwargs map[string]interface{}) string {
|
||||
conf += "\n"
|
||||
}
|
||||
|
||||
if hysmi, ok := kwargs[TELEGRAF_INPUT_HYSMI]; ok {
|
||||
hysmiMap, _ := hysmi.(map[string]interface{})
|
||||
conf += fmt.Sprintf("[[inputs.%s]]\n", TELEGRAF_INPUT_HYSMI)
|
||||
conf += fmt.Sprintf(" bin_path = \"%s\"\n", hysmiMap[TELEGRAF_INPUT_CONF_BIN_PATH].(string))
|
||||
conf += "\n"
|
||||
}
|
||||
|
||||
if _, ok := kwargs[TELEGRAF_INPUT_NVIDIASMI]; ok {
|
||||
conf += "[[inputs.nvidia_smi]]\n"
|
||||
conf += "\n"
|
||||
|
||||
@@ -9,16 +9,19 @@ import (
|
||||
)
|
||||
|
||||
func TestBuildVLLMEntrypointScriptMountedModelsFlag(t *testing.T) {
|
||||
sleepScript := buildVLLMEntrypointScript("", 1, nil, nil)
|
||||
sleepScript := buildVLLMEntrypointScript("", 1, nil, nil, false)
|
||||
if !strings.Contains(sleepScript, "sleep infinity") {
|
||||
t.Fatalf("expected idle script without model path, got %q", sleepScript)
|
||||
}
|
||||
if strings.Contains(sleepScript, "find ") {
|
||||
t.Fatalf("idle script should not find models, got %q", sleepScript)
|
||||
}
|
||||
if strings.Contains(sleepScript, "/opt/dtk/env.sh") {
|
||||
t.Fatalf("idle script should not source dtk env, got %q", sleepScript)
|
||||
}
|
||||
|
||||
nested := "/data/models/huggingface/Qwen3-8B"
|
||||
serveScript := buildVLLMEntrypointScript(nested, 1, nil, &api.LLMSpecVllm{PreferredModel: "Qwen3-8B"})
|
||||
serveScript := buildVLLMEntrypointScript(nested, 1, nil, &api.LLMSpecVllm{PreferredModel: "Qwen3-8B"}, false)
|
||||
if strings.Contains(serveScript, "sleep infinity") {
|
||||
t.Fatalf("expected serve script with model path, got %q", serveScript)
|
||||
}
|
||||
@@ -28,6 +31,9 @@ func TestBuildVLLMEntrypointScriptMountedModelsFlag(t *testing.T) {
|
||||
if !strings.Contains(serveScript, nested) {
|
||||
t.Fatalf("expected nested model path in serve script, got %q", serveScript)
|
||||
}
|
||||
if strings.Contains(serveScript, "/opt/dtk/env.sh") {
|
||||
t.Fatalf("non-hygon serve script should not source dtk env, got %q", serveScript)
|
||||
}
|
||||
if strings.Contains(serveScript, "find ") {
|
||||
t.Fatalf("serve script should not find under MODELS_PATH, got %q", serveScript)
|
||||
}
|
||||
@@ -36,6 +42,25 @@ func TestBuildVLLMEntrypointScriptMountedModelsFlag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildVLLMEntrypointScriptHygonSourcesDTKEnv(t *testing.T) {
|
||||
modelPath := "/data/models/huggingface/Qwen3-8B"
|
||||
script := buildVLLMEntrypointScript(modelPath, 2, nil, nil, true)
|
||||
if !strings.Contains(script, "/opt/dtk/env.sh") {
|
||||
t.Fatalf("expected dtk env source, got %q", script)
|
||||
}
|
||||
if !strings.Contains(script, "/opt/dtk-*/env.sh") {
|
||||
t.Fatalf("expected dtk version fallback, got %q", script)
|
||||
}
|
||||
if !strings.Contains(script, api.LLM_VLLM_EXEC_PATH) {
|
||||
t.Fatalf("expected vllm exec after env source, got %q", script)
|
||||
}
|
||||
idx := strings.Index(script, "/opt/dtk/env.sh")
|
||||
execIdx := strings.Index(script, "exec "+api.LLM_VLLM_EXEC_PATH)
|
||||
if idx < 0 || execIdx < 0 || idx > execIdx {
|
||||
t.Fatalf("expected env source before exec vllm, got %q", script)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSGLangEntrypointScriptNestedModelPath(t *testing.T) {
|
||||
sleepScript := buildSGLangEntrypointScript("", 1, nil, nil)
|
||||
if !strings.Contains(sleepScript, "sleep infinity") {
|
||||
@@ -79,7 +104,7 @@ func TestLocalPathSkuEnablesServeEntrypoint(t *testing.T) {
|
||||
if modelPath != "/data/models/huggingface/Qwen3-8B" {
|
||||
t.Fatalf("expected nested local_path mount, got %q", modelPath)
|
||||
}
|
||||
script := buildVLLMEntrypointScript(modelPath, 1, nil, nil)
|
||||
script := buildVLLMEntrypointScript(modelPath, 1, nil, nil, false)
|
||||
if !strings.Contains(script, modelPath) {
|
||||
t.Fatalf("expected script to embed mount path, got %q", script)
|
||||
}
|
||||
|
||||
@@ -198,16 +198,31 @@ func buildVLLMServeFlags(modelPath string, tensorParallelSize int, backendParame
|
||||
)
|
||||
}
|
||||
|
||||
func buildVLLMEntrypointScript(modelPath string, tensorParallelSize int, backendParameters []string, effSpec *api.LLMSpecVllm) string {
|
||||
func buildHygonVLLMEnvSourceLines() []string {
|
||||
return []string{
|
||||
"if [ -f /opt/dtk/env.sh ]; then",
|
||||
" . /opt/dtk/env.sh",
|
||||
"else",
|
||||
" _dtk_env=$(ls /opt/dtk-*/env.sh 2>/dev/null | head -1)",
|
||||
" if [ -n \"$_dtk_env\" ] && [ -f \"$_dtk_env\" ]; then",
|
||||
" . \"$_dtk_env\"",
|
||||
" fi",
|
||||
"fi",
|
||||
}
|
||||
}
|
||||
|
||||
func buildVLLMEntrypointScript(modelPath string, tensorParallelSize int, backendParameters []string, effSpec *api.LLMSpecVllm, hygon bool) string {
|
||||
modelPath = strings.TrimSpace(modelPath)
|
||||
if modelPath == "" {
|
||||
return "exec sleep infinity"
|
||||
}
|
||||
serveCmd := strings.Join(buildVLLMServeFlags(modelPath, tensorParallelSize, backendParameters, effSpec), " ")
|
||||
return strings.Join([]string{
|
||||
"set -e",
|
||||
fmt.Sprintf("exec %s %s", api.LLM_VLLM_EXEC_PATH, serveCmd),
|
||||
}, "\n")
|
||||
lines := []string{"set -e"}
|
||||
if hygon {
|
||||
lines = append(lines, buildHygonVLLMEnvSourceLines()...)
|
||||
}
|
||||
lines = append(lines, fmt.Sprintf("exec %s %s", api.LLM_VLLM_EXEC_PATH, serveCmd))
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func (v *vllm) GetSpec(sku *models.SLLMSku) interface{} {
|
||||
@@ -414,7 +429,8 @@ func (v *vllm) GetContainerSpec(ctx context.Context, llm *models.SLLM, image *mo
|
||||
}
|
||||
modelPath := models.PickContainerModelMountPath(models.CollectContainerModelMountPaths(llm, sku), preferred)
|
||||
hasMountedModels := modelPath != "" || len(postOverlays) > 0 || models.SkuHasLocalHostPathModel(sku)
|
||||
startScript := buildVLLMEntrypointScript(modelPath, tensorParallelSize, backendParameters, effSpec)
|
||||
hygon := models.HasHygonDevices(llm, sku)
|
||||
startScript := buildVLLMEntrypointScript(modelPath, tensorParallelSize, backendParameters, effSpec, hygon)
|
||||
envs := []*commonapi.ContainerKeyValue{
|
||||
{
|
||||
Key: "HUGGING_FACE_HUB_CACHE",
|
||||
@@ -446,6 +462,9 @@ func (v *vllm) GetContainerSpec(ctx context.Context, llm *models.SLLM, image *mo
|
||||
Envs: envs,
|
||||
},
|
||||
}
|
||||
if hygon {
|
||||
spec.Command = []string{"/bin/bash", "-c"}
|
||||
}
|
||||
if hasMountedModels {
|
||||
spec.StartupProbe = newLLMHTTPStartupProbe(api.LLM_VLLM_DEFAULT_PORT, "/v1/models")
|
||||
}
|
||||
@@ -453,6 +472,15 @@ func (v *vllm) GetContainerSpec(ctx context.Context, llm *models.SLLM, image *mo
|
||||
// GPU Devices
|
||||
appendContainerIsolatedDevices(&spec, llm, sku, devices)
|
||||
|
||||
if hygon {
|
||||
spec.Capabilities = &commonapi.ContainerCapability{
|
||||
Add: []string{"SYS_PTRACE"},
|
||||
}
|
||||
spec.SecurityContext = &commonapi.ContainerSecurityContext{
|
||||
SupplementalGroupNames: []string{"video"},
|
||||
}
|
||||
}
|
||||
|
||||
// Volume Mounts
|
||||
diskIndex := 0
|
||||
ctrVols := []*commonapi.ContainerVolumeMount{
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package llm_container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
api "yunion.io/x/onecloud/pkg/apis/llm"
|
||||
"yunion.io/x/onecloud/pkg/llm/models"
|
||||
)
|
||||
|
||||
func TestVLLMGetContainerSpecHygonRuntime(t *testing.T) {
|
||||
v := newVLLM().(*vllm)
|
||||
hostPaths := api.HostPaths{
|
||||
{
|
||||
Type: "directory",
|
||||
Path: "/data/models/Qwen3-8B",
|
||||
Containers: api.ContainerHostPathRelations{
|
||||
"0": {MountPath: "/data/models/huggingface/Qwen3-8B"},
|
||||
},
|
||||
},
|
||||
}
|
||||
hygonSku := &models.SLLMSku{
|
||||
SLLMSkuBase: models.SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_HYGON_DCU},
|
||||
{DevType: computeapi.CONTAINER_DEV_HYGON_DCU},
|
||||
},
|
||||
},
|
||||
LLMType: string(api.LLM_CONTAINER_VLLM),
|
||||
Source: api.LLM_MODEL_SOURCE_LOCAL_PATH,
|
||||
LocalPath: "/data/models/Qwen3-8B",
|
||||
}
|
||||
hygonSku.HostPaths = &hostPaths
|
||||
image := &models.SLLMImage{}
|
||||
out := v.GetContainerSpec(context.Background(), nil, image, hygonSku, nil, nil, "")
|
||||
if out == nil {
|
||||
t.Fatal("expected container spec")
|
||||
}
|
||||
spec := &out.ContainerSpec
|
||||
if spec.Capabilities == nil || !reflect.DeepEqual(spec.Capabilities.Add, []string{"SYS_PTRACE"}) {
|
||||
t.Fatalf("capabilities = %#v, want SYS_PTRACE", spec.Capabilities)
|
||||
}
|
||||
if spec.SecurityContext == nil || !reflect.DeepEqual(spec.SecurityContext.SupplementalGroupNames, []string{"video"}) {
|
||||
t.Fatalf("security context = %#v, want video group", spec.SecurityContext)
|
||||
}
|
||||
if len(spec.Command) != 2 || spec.Command[0] != "/bin/bash" || spec.Command[1] != "-c" {
|
||||
t.Fatalf("command = %#v, want [/bin/bash -c]", spec.Command)
|
||||
}
|
||||
if len(spec.Args) == 0 || !strings.Contains(spec.Args[0], "/opt/dtk/env.sh") {
|
||||
t.Fatalf("args = %#v, want dtk env source in entrypoint", spec.Args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVLLMGetContainerSpecNvidiaNoHygonRuntime(t *testing.T) {
|
||||
v := newVLLM().(*vllm)
|
||||
nvSku := &models.SLLMSku{
|
||||
SLLMSkuBase: models.SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_NVIDIA_GPU},
|
||||
},
|
||||
},
|
||||
}
|
||||
image := &models.SLLMImage{}
|
||||
out := v.GetContainerSpec(context.Background(), nil, image, nvSku, nil, nil, "")
|
||||
if out == nil {
|
||||
t.Fatal("expected container spec")
|
||||
}
|
||||
spec := &out.ContainerSpec
|
||||
if spec.Capabilities != nil {
|
||||
t.Fatalf("expected nil capabilities, got %#v", spec.Capabilities)
|
||||
}
|
||||
if spec.SecurityContext != nil {
|
||||
t.Fatalf("expected nil security context, got %#v", spec.SecurityContext)
|
||||
}
|
||||
if len(spec.Command) != 2 || spec.Command[0] != "/bin/sh" {
|
||||
t.Fatalf("command = %#v, want [/bin/sh -c]", spec.Command)
|
||||
}
|
||||
if len(spec.Args) > 0 && strings.Contains(spec.Args[0], "/opt/dtk/env.sh") {
|
||||
t.Fatalf("args should not source dtk env for nvidia, got %#v", spec.Args)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -97,6 +98,24 @@ func getEffectiveDevices(llmBase *SLLMBase, skuBase *SLLMSkuBase) *api.Devices {
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasHygonDevices reports whether effective devices include Hygon DCU (exclusive or HAMI).
|
||||
func HasHygonDevices(llm *SLLM, sku *SLLMSku) bool {
|
||||
devs := GetEffectiveDevices(llm, sku)
|
||||
if devs == nil {
|
||||
return false
|
||||
}
|
||||
for _, d := range *devs {
|
||||
if strings.EqualFold(d.Vendor, "HYGON") {
|
||||
return true
|
||||
}
|
||||
switch d.DevType {
|
||||
case computeapi.CONTAINER_DEV_HYGON_DCU, computeapi.CONTAINER_DEV_HYGON_DCU_HAMI:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetEffectiveHostPaths returns the host_paths to apply with llm's override taking priority over sku.
|
||||
func GetEffectiveHostPaths(llm *SLLM, sku *SLLMSku) *api.HostPaths {
|
||||
var llmBase *SLLMBase
|
||||
|
||||
@@ -99,6 +99,7 @@ func GetLLMBasePodCreateInput(
|
||||
isolatedDevice := &computeapi.IsolatedDeviceConfig{
|
||||
DevType: devices[i].DevType,
|
||||
SharingMode: devices[i].SharingMode,
|
||||
Vendor: devices[i].Vendor,
|
||||
Model: devices[i].Model,
|
||||
DevicePath: devices[i].DevicePath,
|
||||
MemoryMb: memMb,
|
||||
|
||||
@@ -662,6 +662,7 @@ func buildIsolatedDeviceMemoryParams(device api.Device) *jsonutils.JSONDict {
|
||||
params.Set("show_baremetal_isolated_devices", jsonutils.JSONTrue)
|
||||
setStringArrayParam(params, "dev_type", dev.DevType)
|
||||
setStringArrayParam(params, "sharing_mode", dev.SharingMode)
|
||||
setStringArrayParam(params, "vendor", dev.Vendor)
|
||||
setStringArrayParam(params, "model", dev.Model)
|
||||
setStringArrayParam(params, "device_path", dev.DevicePath)
|
||||
return params
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
api "yunion.io/x/onecloud/pkg/apis/llm"
|
||||
)
|
||||
|
||||
func TestHasHygonDevices(t *testing.T) {
|
||||
hygonSku := &SLLMSku{
|
||||
SLLMSkuBase: SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_HYGON_DCU},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !HasHygonDevices(nil, hygonSku) {
|
||||
t.Fatal("expected Hygon DCU sku to be detected")
|
||||
}
|
||||
|
||||
hamiSku := &SLLMSku{
|
||||
SLLMSkuBase: SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_HYGON_DCU_HAMI},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !HasHygonDevices(nil, hamiSku) {
|
||||
t.Fatal("expected Hygon DCU HAMI sku to be detected")
|
||||
}
|
||||
|
||||
nvSku := &SLLMSku{
|
||||
SLLMSkuBase: SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_NVIDIA_GPU},
|
||||
},
|
||||
},
|
||||
}
|
||||
if HasHygonDevices(nil, nvSku) {
|
||||
t.Fatal("expected NVIDIA sku not to be detected as Hygon")
|
||||
}
|
||||
|
||||
llm := &SLLM{
|
||||
SLLMBase: SLLMBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.CONTAINER_DEV_HYGON_DCU},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !HasHygonDevices(llm, nvSku) {
|
||||
t.Fatal("expected llm device override to win over sku")
|
||||
}
|
||||
|
||||
normalizedHygonSku := &SLLMSku{
|
||||
SLLMSkuBase: SLLMSkuBase{
|
||||
Devices: &api.Devices{
|
||||
{DevType: computeapi.GPU_TYPE, Vendor: "HYGON", Model: "BW"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !HasHygonDevices(nil, normalizedHygonSku) {
|
||||
t.Fatal("expected normalized GPU+HYGON vendor sku to be detected as Hygon")
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -95,7 +96,24 @@ func normalizeLLMSkuDevices(devices *api.Devices) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func canonicalizeLLMDeviceVendor(vendor string) string {
|
||||
vendor = strings.TrimSpace(vendor)
|
||||
if vendor == "" {
|
||||
return ""
|
||||
}
|
||||
for name := range computeapi.VENDOR_ID_MAP {
|
||||
if strings.EqualFold(name, vendor) {
|
||||
return name
|
||||
}
|
||||
}
|
||||
if name, ok := computeapi.ID_VENDOR_MAP[vendor]; ok {
|
||||
return name
|
||||
}
|
||||
return strings.ToUpper(vendor)
|
||||
}
|
||||
|
||||
func normalizeLLMSkuDevice(dev *api.Device) {
|
||||
origDevType := dev.DevType
|
||||
switch dev.DevType {
|
||||
case "":
|
||||
dev.DevType = computeapi.GPU_TYPE
|
||||
@@ -133,6 +151,16 @@ func normalizeLLMSkuDevice(dev *api.Device) {
|
||||
if dev.SharingMode == "" {
|
||||
dev.SharingMode = computeapi.DEVICE_SHARING_MODE_HAMI
|
||||
}
|
||||
if dev.Vendor == "" {
|
||||
switch origDevType {
|
||||
case computeapi.CONTAINER_DEV_HYGON_DCU, computeapi.CONTAINER_DEV_HYGON_DCU_HAMI:
|
||||
dev.Vendor = "HYGON"
|
||||
case computeapi.CONTAINER_DEV_NVIDIA_GPU, computeapi.CONTAINER_DEV_NVIDIA_MPS,
|
||||
computeapi.CONTAINER_DEV_NVIDIA_GPU_SHARE, computeapi.CONTAINER_DEV_NVIDIA_HAMI:
|
||||
dev.Vendor = "NVIDIA"
|
||||
}
|
||||
}
|
||||
dev.Vendor = canonicalizeLLMDeviceVendor(dev.Vendor)
|
||||
}
|
||||
|
||||
func (skuBase *SLLMSkuBase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.LLMSkuBaseUpdateInput) (api.LLMSkuBaseUpdateInput, error) {
|
||||
|
||||
@@ -25,48 +25,63 @@ func TestNormalizeLLMSkuDeviceLegacyTypes(t *testing.T) {
|
||||
in api.Device
|
||||
wantDevType string
|
||||
wantSharingMode string
|
||||
wantVendor string
|
||||
}{
|
||||
{
|
||||
name: "NVIDIA_GPU_SHARE",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_NVIDIA_GPU_SHARE},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_UNLIMITED,
|
||||
wantVendor: "NVIDIA",
|
||||
},
|
||||
{
|
||||
name: "NVIDIA_MPS",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_NVIDIA_MPS},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_MPS,
|
||||
wantVendor: "NVIDIA",
|
||||
},
|
||||
{
|
||||
name: "NVIDIA_GPU",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_NVIDIA_GPU},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_EXCLUSIVE,
|
||||
wantVendor: "NVIDIA",
|
||||
},
|
||||
{
|
||||
name: "NVIDIA_HAMI",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_NVIDIA_HAMI},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_HAMI,
|
||||
wantVendor: "NVIDIA",
|
||||
},
|
||||
{
|
||||
name: "HYGON_DCU",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_HYGON_DCU},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_EXCLUSIVE,
|
||||
wantVendor: "HYGON",
|
||||
},
|
||||
{
|
||||
name: "HYGON_DCU_HAMI",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_HYGON_DCU_HAMI},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_HAMI,
|
||||
wantVendor: "HYGON",
|
||||
},
|
||||
{
|
||||
name: "explicit sharing_mode preserved",
|
||||
in: api.Device{DevType: computeapi.CONTAINER_DEV_NVIDIA_GPU_SHARE, SharingMode: computeapi.DEVICE_SHARING_MODE_MPS},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_MPS,
|
||||
wantVendor: "NVIDIA",
|
||||
},
|
||||
{
|
||||
name: "explicit vendor preserved and canonicalized",
|
||||
in: api.Device{DevType: computeapi.GPU_TYPE, Vendor: "hygon", Model: "BW"},
|
||||
wantDevType: computeapi.GPU_TYPE,
|
||||
wantSharingMode: computeapi.DEVICE_SHARING_MODE_HAMI,
|
||||
wantVendor: "HYGON",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
@@ -79,6 +94,9 @@ func TestNormalizeLLMSkuDeviceLegacyTypes(t *testing.T) {
|
||||
if dev.SharingMode != tc.wantSharingMode {
|
||||
t.Fatalf("SharingMode = %q, want %q", dev.SharingMode, tc.wantSharingMode)
|
||||
}
|
||||
if dev.Vendor != tc.wantVendor {
|
||||
t.Fatalf("Vendor = %q, want %q", dev.Vendor, tc.wantVendor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -266,6 +284,7 @@ func TestLLMPodIsolatedDeviceConfigFromSKU(t *testing.T) {
|
||||
out = append(out, &computeapi.IsolatedDeviceConfig{
|
||||
DevType: devs[i].DevType,
|
||||
SharingMode: devs[i].SharingMode,
|
||||
Vendor: devs[i].Vendor,
|
||||
Model: devs[i].Model,
|
||||
DevicePath: devs[i].DevicePath,
|
||||
MemoryMb: perDev,
|
||||
@@ -279,6 +298,9 @@ func TestLLMPodIsolatedDeviceConfigFromSKU(t *testing.T) {
|
||||
if out[1].DevType != computeapi.GPU_TYPE || out[1].SharingMode != computeapi.DEVICE_SHARING_MODE_UNLIMITED {
|
||||
t.Fatalf("device1 = %#v", out[1])
|
||||
}
|
||||
if out[1].Vendor != "NVIDIA" {
|
||||
t.Fatalf("device1 Vendor = %q, want NVIDIA", out[1].Vendor)
|
||||
}
|
||||
if out[0].MemoryRequest != perDev || out[1].MemoryRequest != perDev {
|
||||
t.Fatalf("MemoryRequest = %d,%d want %d", out[0].MemoryRequest, out[1].MemoryRequest, perDev)
|
||||
}
|
||||
@@ -315,3 +337,19 @@ func TestBuildIsolatedDeviceMemoryParamsExclusiveUsesUnused(t *testing.T) {
|
||||
t.Fatal("exclusive params should set unused")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildIsolatedDeviceMemoryParamsVendor(t *testing.T) {
|
||||
params := buildIsolatedDeviceMemoryParams(api.Device{
|
||||
DevType: computeapi.GPU_TYPE,
|
||||
SharingMode: computeapi.DEVICE_SHARING_MODE_EXCLUSIVE,
|
||||
Model: "BW",
|
||||
Vendor: "HYGON",
|
||||
})
|
||||
vendors, err := params.GetArray("vendor")
|
||||
if err != nil || len(vendors) != 1 {
|
||||
t.Fatalf("vendor = %v err=%v", params, err)
|
||||
}
|
||||
if s, _ := vendors[0].GetString(); s != "HYGON" {
|
||||
t.Fatalf("vendor = %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type LLMSkuBaseCreateOptions struct {
|
||||
// DiskOverlay string `help:"disk overlay, e.g. /opt/steam-data/base:/opt/steam-data/games"`
|
||||
TemplateId string
|
||||
PortMappings []string `help:"port mapping in the format of protocol:port[:prefix][:first_port_offset][:env_key=env_value], e.g. tcp:5555:192.168.0.0/16:5:WOLF_BASE_PORT=20000"`
|
||||
Devices []string `help:"device info in the format of model[:path[:dev_type[:sharing_mode]]], e.g. 'GeForce RTX 4060'"`
|
||||
Devices []string `help:"device info in the format of model[:path[:dev_type[:sharing_mode[:vendor]]]], e.g. 'GeForce RTX 4060' or 'BW::GPU:EXCLUSIVE:HYGON'"`
|
||||
HostPaths []string `json:"-" help:"host path mount in format path=<host_path>,type=<directory|file>,container_index=<index>,mount_path=<container_path>[,auto_create=<bool>][,read_only=<bool>][,propagation=<private|rslave|rshared>][,fs_user=<uid>][,fs_group=<gid>][,uid=<uid>][,gid=<gid>][,permissions=<mode>]; repeatable"`
|
||||
|
||||
Env []string `help:"env in format of key=value"`
|
||||
@@ -69,7 +69,7 @@ type LLMSkuBaseUpdateOptions struct {
|
||||
// Dpi *int
|
||||
// Fps *int
|
||||
PortMappings []string `help:"port mapping in the format of protocol:port[:prefix][:first_port_offset], e.g. tcp:5555:192.168.0.0/16,10.10.0.0/16:1000"`
|
||||
Devices []string `help:"device info in the format of model[:path[:dev_type[:sharing_mode]]], e.g. QuadraT2A:/dev/nvme1n1, Device::VASTAITECH_GPU"`
|
||||
Devices []string `help:"device info in the format of model[:path[:dev_type[:sharing_mode[:vendor]]]], e.g. QuadraT2A:/dev/nvme1n1, BW::GPU:EXCLUSIVE:HYGON"`
|
||||
HostPaths []string `json:"-" help:"host path mount in format path=<host_path>,type=<directory|file>,container_index=<index>,mount_path=<container_path>[,auto_create=<bool>][,read_only=<bool>][,propagation=<private|rslave|rshared>][,fs_user=<uid>][,fs_group=<gid>][,uid=<uid>][,gid=<gid>][,permissions=<mode>]; repeatable"`
|
||||
Env []string `help:"env in the format of key=value, e.g. AUTHENTICATION_PATH=/bupt-test/"`
|
||||
Property []string `help:"extra properties of key=value, e.g. tango32=true"`
|
||||
@@ -365,6 +365,7 @@ func fetchDevices(devStrs []string, dict *jsonutils.JSONDict) {
|
||||
devpath := ""
|
||||
devType := ""
|
||||
sharingMode := ""
|
||||
vendor := ""
|
||||
if len(segs) > 1 {
|
||||
devpath = segs[1]
|
||||
}
|
||||
@@ -374,11 +375,15 @@ func fetchDevices(devStrs []string, dict *jsonutils.JSONDict) {
|
||||
if len(segs) > 3 {
|
||||
sharingMode = segs[3]
|
||||
}
|
||||
if len(segs) > 4 {
|
||||
vendor = segs[4]
|
||||
}
|
||||
devs = append(devs, api.Device{
|
||||
Model: segs[0],
|
||||
DevicePath: devpath,
|
||||
DevType: devType,
|
||||
SharingMode: sharingMode,
|
||||
Vendor: vendor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ var All = []SMeasurement{
|
||||
system,
|
||||
vasmi,
|
||||
npuSmi,
|
||||
hysmi,
|
||||
|
||||
worker,
|
||||
serviceHttpCode,
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package measurements
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/apis/monitor"
|
||||
|
||||
var hysmi = SMeasurement{
|
||||
Context: []SMonitorContext{
|
||||
{
|
||||
"hysmi", "Hygon DCU metrics",
|
||||
monitor.METRIC_RES_TYPE_HOST, monitor.METRIC_DATABASE_TELE,
|
||||
},
|
||||
},
|
||||
Metrics: []SMetric{
|
||||
{
|
||||
"temperature_gpu", "DCU temperature", "",
|
||||
},
|
||||
{
|
||||
"power_draw", "DCU power draw", "",
|
||||
},
|
||||
{
|
||||
"power_cap", "DCU power cap", "",
|
||||
},
|
||||
{
|
||||
"utilization_gpu", "DCU utilization", monitor.METRIC_UNIT_PERCENT,
|
||||
},
|
||||
{
|
||||
"utilization_memory", "DCU memory utilization", monitor.METRIC_UNIT_PERCENT,
|
||||
},
|
||||
{
|
||||
"utilization_encoder", "DCU encoder utilization", monitor.METRIC_UNIT_PERCENT,
|
||||
},
|
||||
{
|
||||
"utilization_decoder", "DCU decoder utilization", monitor.METRIC_UNIT_PERCENT,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -257,6 +257,13 @@ Measurement,MeasurementNote,ResourceType,Database,Metric,MetricNote,MetricUnit
|
||||
"npu_smi","Ascend NPU metrics","host","telegraf","aicube_usage_rate","NPU aicube usage rate","%s"
|
||||
"npu_smi","Ascend NPU metrics","host","telegraf","aicpu_usage_rate","NPU aicpu usage rate","%s"
|
||||
"npu_smi","Ascend NPU metrics","host","telegraf","hbm_bandwidth_usage_rate","NPU hbm bandwidth usage rate","%s"
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","temperature_gpu","HCU temperature",""
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","power_draw","HCU power draw",""
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","power_cap","HCU power cap",""
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","utilization_gpu","HCU utilization","%"
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","utilization_memory","HCU memory utilization","%"
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","utilization_encoder","HCU encoder utilization","%"
|
||||
"hysmi","Hygon HCU metrics","host","telegraf","utilization_decoder","HCU decoder utilization","%"
|
||||
"worker","Worker queue","system","system","active_worker_cnt","Active Worker Count","NULL"
|
||||
"worker","Worker queue","system","system","max_worker_count","Max Worker Count","NULL"
|
||||
"worker","Worker queue","system","system","detach_worker_cnt","Detach worker Count","NULL"
|
||||
|
||||
|
Reference in New Issue
Block a user