Skip to content

Commit

Permalink
enhancement: Implement classes to read drm subsystem
Browse files Browse the repository at this point in the history
Signed-off-by: Juerg Ritter <[email protected]>
  • Loading branch information
jritter committed Jul 15, 2024
1 parent 0e0b4b1 commit f73189b
Show file tree
Hide file tree
Showing 4 changed files with 429 additions and 90 deletions.
10 changes: 10 additions & 0 deletions sysfs/class_drm_amdgpu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ func TestClassDRMCardAMDGPUStats(t *testing.T) {
PowerDPMForcePerformanceLevel: "manual",
UniqueID: "0123456789abcdef",
},
{
Name: "card1",
GPUBusyPercent: 0,
MemoryGTTSize: 0,
MemoryGTTUsed: 0,
MemoryVisibleVRAMSize: 0,
MemoryVisibleVRAMUsed: 0,
MemoryVRAMSize: 0,
MemoryVRAMUsed: 0,
},
}

if !reflect.DeepEqual(classDRMCardStats, drmTest) {
Expand Down
128 changes: 128 additions & 0 deletions sysfs/class_drm_card.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2018 The Prometheus Authors
// 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.

//go:build linux
// +build linux

package sysfs

import (
"fmt"
"path/filepath"

"github.com/prometheus/procfs/internal/util"
)

const drmClassPath = "class/drm"

// DrmCard contains info from files in /sys/class/drm for a
// single DRM Card device.
type DrmCard struct {
Name string
Driver string
Ports map[string]DrmCardPort
}

// DrmCardPort contains info from files in
// /sys/class/drm/<Card>/<Card>-<Name>
// for a single port of one DrmCard device.
type DrmCardPort struct {
Name string
Status string
Dpms string
Enabled string
}

// DrmCardClass is a collection of every Card device in
// /sys/class/drm.
//
// The map keys are the names of the InfiniBand devices.
type DrmCardClass map[string]DrmCard

// DrmCardClass returns infos for all Drm devices read from
// /sys/class/drm.
func (fs FS) DrmCardClass() (DrmCardClass, error) {

cards, err := filepath.Glob(fs.sys.Path("class/drm/card[0-9]"))

if err != nil {
return nil, fmt.Errorf("failed to list DRM card ports at %q: %w", cards, err)
}

drmCardClass := make(DrmCardClass, len(cards))
for _, c := range cards {
card, err := fs.parseDrmCard(filepath.Base(c))
if err != nil {
return nil, err
}

drmCardClass[card.Name] = *card
}

return drmCardClass, nil
}

// Parse one DrmCard.
func (fs FS) parseDrmCard(name string) (*DrmCard, error) {
path := fs.sys.Path(drmClassPath, name)
card := DrmCard{Name: name}

// Read the kernel module of the card
cardDriverPath, err := filepath.EvalSymlinks(filepath.Join(path, "device/driver"))
if err != nil {
return nil, fmt.Errorf("failed to read driver: %w", err)
}
card.Driver = filepath.Base(cardDriverPath)

portsPath, err := filepath.Glob(filepath.Join(path, filepath.Base(path)+"-*-*"))

if err != nil {
return nil, fmt.Errorf("failed to list DRM card ports at %q: %w", portsPath, err)
}

card.Ports = make(map[string]DrmCardPort, len(portsPath))
for _, d := range portsPath {
port, err := parseDrmCardPort(d)
if err != nil {
return nil, err
}

card.Ports[port.Name] = *port
}

return &card, nil
}

func parseDrmCardPort(port string) (*DrmCardPort, error) {
portStatus, err := util.SysReadFile(filepath.Join(port, "status"))
if err != nil {
return nil, err
}

drmCardPort := DrmCardPort{Name: filepath.Base(port), Status: portStatus}

portDpms, err := util.SysReadFile(filepath.Join(port, "dpms"))
if err != nil {
return nil, err
}

drmCardPort.Dpms = portDpms

portEnabled, err := util.SysReadFile(filepath.Join(port, "enabled"))
if err != nil {
return nil, err
}
drmCardPort.Enabled = portEnabled

return &drmCardPort, nil
}
65 changes: 65 additions & 0 deletions sysfs/class_drm_card_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2021 The Prometheus Authors
// 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.

//go:build linux
// +build linux

package sysfs

import (
"testing"

"github.com/google/go-cmp/cmp"
)

func TestClassDRMCard(t *testing.T) {
fs, err := NewFS(sysTestFixtures)
if err != nil {
t.Fatal(err)
}

got, err := fs.DrmCardClass()
if err != nil {
t.Fatal(err)
}

want := DrmCardClass{
"card0": DrmCard{
Name: "card0",
Driver: "amdgpu",
Ports: map[string]DrmCardPort{},
},
"card1": DrmCard{
Name: "card1",
Driver: "i915",
Ports: map[string]DrmCardPort{
"card1-DP-1": {
Name: "card1-DP-1",
Dpms: "Off",
Enabled: "disabled",
Status: "disconnected",
},
"card1-DP-5": {
Name: "card1-DP-5",
Dpms: "On",
Enabled: "enabled",
Status: "connected",
},
},
},
}

if diff := cmp.Diff(want, got); diff != "" {
t.Fatalf("unexpected DrmCard class (-want +got):\n%s", diff)
}
}
Loading

0 comments on commit f73189b

Please sign in to comment.