1+ //go:build linux
2+
3+ package gpuinfo
4+
5+ import (
6+ "bufio"
7+ "os"
8+ "path/filepath"
9+ "regexp"
10+ "sort"
11+ "strconv"
12+ "strings"
13+ )
14+
15+ // supportedAMDGPUs are the AMD GPU targets that should use ROCm
16+ var supportedAMDGPUs = map [string ]bool {
17+ "gfx908" : true ,
18+ "gfx90a" : true ,
19+ "gfx942" : true ,
20+ "gfx1010" : true ,
21+ "gfx1030" : true ,
22+ "gfx1100" : true ,
23+ "gfx1200" : true ,
24+ "gfx1201" : true ,
25+ "gfx1151" : true ,
26+ }
27+
28+ func hasSupportedAMDGPU () (bool , error ) {
29+ // Check if KFD topology directory exists
30+ topologyDir := "/sys/class/kfd/kfd/topology/nodes/"
31+ info , err := os .Stat (topologyDir )
32+ if err != nil || ! info .IsDir () {
33+ return false , nil // KFD not available
34+ }
35+
36+ entries , err := os .ReadDir (topologyDir )
37+ if err != nil {
38+ return false , err
39+ }
40+
41+ // Sort entries by name to maintain consistent order
42+ sort .Slice (entries , func (i , j int ) bool {
43+ return entries [i ].Name () < entries [j ].Name ()
44+ })
45+
46+ // Compile regex to match gfx_target_version lines
47+ reTarget := regexp .MustCompile (`gfx_target_version[ \t]+([0-9]+)` )
48+
49+ for _ , e := range entries {
50+ if ! e .IsDir () {
51+ continue
52+ }
53+ nodePath := filepath .Join (topologyDir , e .Name ())
54+ propPath := filepath .Join (nodePath , "properties" )
55+
56+ // Attempt to open the properties file directly; skip on error (e.g., permissions)
57+ f , err := os .Open (propPath )
58+ if err != nil {
59+ // Could be permission denied or file doesn't exist; just skip like the Python code
60+ continue
61+ }
62+
63+ sc := bufio .NewScanner (f )
64+ for sc .Scan () {
65+ line := sc .Text ()
66+ matches := reTarget .FindStringSubmatch (line )
67+ if len (matches ) < 2 {
68+ continue
69+ }
70+
71+ deviceIDStr := matches [1 ]
72+ deviceID , err := strconv .Atoi (deviceIDStr )
73+ if err != nil || deviceID == 0 {
74+ continue
75+ }
76+
77+ var majorVer , minorVer , steppingVer int
78+ if gfxOverride := os .Getenv ("HSA_OVERRIDE_GFX_VERSION" ); gfxOverride != "" {
79+ parts := strings .Split (strings .TrimSpace (gfxOverride ), "." )
80+ if len (parts ) != 3 {
81+ // Invalid format, skip
82+ continue
83+ }
84+ mv , err1 := strconv .Atoi (parts [0 ])
85+ nv , err2 := strconv .Atoi (parts [1 ])
86+ sv , err3 := strconv .Atoi (parts [2 ])
87+ if err1 != nil || err2 != nil || err3 != nil {
88+ // Invalid format, skip
89+ continue
90+ }
91+ if mv > 63 || nv > 255 || sv > 255 {
92+ // Invalid values, skip
93+ continue
94+ }
95+ majorVer , minorVer , steppingVer = mv , nv , sv
96+ } else {
97+ majorVer = (deviceID / 10000 ) % 100
98+ minorVer = (deviceID / 100 ) % 100
99+ steppingVer = deviceID % 100
100+ }
101+
102+ gfx := "gfx" +
103+ strconv .FormatInt (int64 (majorVer ), 10 ) +
104+ strconv .FormatInt (int64 (minorVer ), 16 ) +
105+ strconv .FormatInt (int64 (steppingVer ), 16 )
106+
107+ if supportedAMDGPUs [gfx ] {
108+ f .Close ()
109+ return true , nil // Found a supported AMD GPU
110+ }
111+ }
112+ f .Close ()
113+ }
114+
115+ return false , nil // No supported AMD GPU found
116+ }
0 commit comments