Skip to content

Commit 21839df

Browse files
jritterdiscordianfish
authored andcommitted
enhancement: Implement classes to read drm subsystem
Signed-off-by: Juerg Ritter <[email protected]>
1 parent a05af62 commit 21839df

File tree

4 files changed

+429
-90
lines changed

4 files changed

+429
-90
lines changed

sysfs/class_drm_amdgpu_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ func TestClassDRMCardAMDGPUStats(t *testing.T) {
4646
PowerDPMForcePerformanceLevel: "manual",
4747
UniqueID: "0123456789abcdef",
4848
},
49+
{
50+
Name: "card1",
51+
GPUBusyPercent: 0,
52+
MemoryGTTSize: 0,
53+
MemoryGTTUsed: 0,
54+
MemoryVisibleVRAMSize: 0,
55+
MemoryVisibleVRAMUsed: 0,
56+
MemoryVRAMSize: 0,
57+
MemoryVRAMUsed: 0,
58+
},
4959
}
5060

5161
if !reflect.DeepEqual(classDRMCardStats, drmTest) {

sysfs/class_drm_card.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2018 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
//go:build linux
15+
// +build linux
16+
17+
package sysfs
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
23+
"github.com/prometheus/procfs/internal/util"
24+
)
25+
26+
const drmClassPath = "class/drm"
27+
28+
// DrmCard contains info from files in /sys/class/drm for a
29+
// single DRM Card device.
30+
type DrmCard struct {
31+
Name string
32+
Driver string
33+
Ports map[string]DrmCardPort
34+
}
35+
36+
// DrmCardPort contains info from files in
37+
// /sys/class/drm/<Card>/<Card>-<Name>
38+
// for a single port of one DrmCard device.
39+
type DrmCardPort struct {
40+
Name string
41+
Status string
42+
Dpms string
43+
Enabled string
44+
}
45+
46+
// DrmCardClass is a collection of every Card device in
47+
// /sys/class/drm.
48+
//
49+
// The map keys are the names of the InfiniBand devices.
50+
type DrmCardClass map[string]DrmCard
51+
52+
// DrmCardClass returns infos for all Drm devices read from
53+
// /sys/class/drm.
54+
func (fs FS) DrmCardClass() (DrmCardClass, error) {
55+
56+
cards, err := filepath.Glob(fs.sys.Path("class/drm/card[0-9]"))
57+
58+
if err != nil {
59+
return nil, fmt.Errorf("failed to list DRM card ports at %q: %w", cards, err)
60+
}
61+
62+
drmCardClass := make(DrmCardClass, len(cards))
63+
for _, c := range cards {
64+
card, err := fs.parseDrmCard(filepath.Base(c))
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
drmCardClass[card.Name] = *card
70+
}
71+
72+
return drmCardClass, nil
73+
}
74+
75+
// Parse one DrmCard.
76+
func (fs FS) parseDrmCard(name string) (*DrmCard, error) {
77+
path := fs.sys.Path(drmClassPath, name)
78+
card := DrmCard{Name: name}
79+
80+
// Read the kernel module of the card
81+
cardDriverPath, err := filepath.EvalSymlinks(filepath.Join(path, "device/driver"))
82+
if err != nil {
83+
return nil, fmt.Errorf("failed to read driver: %w", err)
84+
}
85+
card.Driver = filepath.Base(cardDriverPath)
86+
87+
portsPath, err := filepath.Glob(filepath.Join(path, filepath.Base(path)+"-*-*"))
88+
89+
if err != nil {
90+
return nil, fmt.Errorf("failed to list DRM card ports at %q: %w", portsPath, err)
91+
}
92+
93+
card.Ports = make(map[string]DrmCardPort, len(portsPath))
94+
for _, d := range portsPath {
95+
port, err := parseDrmCardPort(d)
96+
if err != nil {
97+
return nil, err
98+
}
99+
100+
card.Ports[port.Name] = *port
101+
}
102+
103+
return &card, nil
104+
}
105+
106+
func parseDrmCardPort(port string) (*DrmCardPort, error) {
107+
portStatus, err := util.SysReadFile(filepath.Join(port, "status"))
108+
if err != nil {
109+
return nil, err
110+
}
111+
112+
drmCardPort := DrmCardPort{Name: filepath.Base(port), Status: portStatus}
113+
114+
portDpms, err := util.SysReadFile(filepath.Join(port, "dpms"))
115+
if err != nil {
116+
return nil, err
117+
}
118+
119+
drmCardPort.Dpms = portDpms
120+
121+
portEnabled, err := util.SysReadFile(filepath.Join(port, "enabled"))
122+
if err != nil {
123+
return nil, err
124+
}
125+
drmCardPort.Enabled = portEnabled
126+
127+
return &drmCardPort, nil
128+
}

sysfs/class_drm_card_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2021 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
//go:build linux
15+
// +build linux
16+
17+
package sysfs
18+
19+
import (
20+
"testing"
21+
22+
"github.com/google/go-cmp/cmp"
23+
)
24+
25+
func TestClassDRMCard(t *testing.T) {
26+
fs, err := NewFS(sysTestFixtures)
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
31+
got, err := fs.DrmCardClass()
32+
if err != nil {
33+
t.Fatal(err)
34+
}
35+
36+
want := DrmCardClass{
37+
"card0": DrmCard{
38+
Name: "card0",
39+
Driver: "amdgpu",
40+
Ports: map[string]DrmCardPort{},
41+
},
42+
"card1": DrmCard{
43+
Name: "card1",
44+
Driver: "i915",
45+
Ports: map[string]DrmCardPort{
46+
"card1-DP-1": {
47+
Name: "card1-DP-1",
48+
Dpms: "Off",
49+
Enabled: "disabled",
50+
Status: "disconnected",
51+
},
52+
"card1-DP-5": {
53+
Name: "card1-DP-5",
54+
Dpms: "On",
55+
Enabled: "enabled",
56+
Status: "connected",
57+
},
58+
},
59+
},
60+
}
61+
62+
if diff := cmp.Diff(want, got); diff != "" {
63+
t.Fatalf("unexpected DrmCard class (-want +got):\n%s", diff)
64+
}
65+
}

0 commit comments

Comments
 (0)