forked from Mellanox/rdmamap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rdma_stats.go
202 lines (173 loc) · 4.69 KB
/
rdma_stats.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package rdmamap
import (
"fmt"
"github.com/vishvananda/netns"
"io/ioutil"
"log"
"net"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
type RdmaStatEntry struct {
Name string
Value uint64
}
type RdmaPortStats struct {
HwStats []RdmaStatEntry /* /sys/class/infiniband/<dev>/<port>/hw_counters */
Stats []RdmaStatEntry /* /sys/class/infiniband/<dev>/<port>/counters */
Port int
}
type RdmaStats struct {
PortStats []RdmaPortStats
}
func readCounter(name string) uint64 {
fd, err := os.OpenFile(name, os.O_RDONLY, 0444)
if err != nil {
return 0
}
defer fd.Close()
fd.Seek(0, os.SEEK_SET)
data, err := ioutil.ReadAll(fd)
if err != nil {
return 0
}
dataStr := string(data)
dataStr = strings.Trim(dataStr, "\n")
value, _ := strconv.ParseUint(dataStr, 10, 64)
return value
}
func getCountersFromDir(path string) ([]RdmaStatEntry, error) {
var stats []RdmaStatEntry
fd, err := os.Open(path)
if err != nil {
return stats, err
}
fileInfos, err := fd.Readdir(-1)
defer fd.Close()
for _, file := range fileInfos {
if file.IsDir() {
continue
}
value := readCounter(filepath.Join(path, file.Name()))
entry := RdmaStatEntry{file.Name(), value}
stats = append(stats, entry)
}
return stats, nil
}
// Get RDMA Sysfs stats from counters directory of a port of a rdma device
// Port number starts from 1.
func GetRdmaSysfsStats(rdmaDevice string, port int) ([]RdmaStatEntry, error) {
path := filepath.Join(RdmaClassDir, rdmaDevice,
RdmaPortsdir, strconv.Itoa(port), RdmaCountersDir)
rdmastats, err := getCountersFromDir(path)
return rdmastats, err
}
// Get RDMA Sysfs stats from hw_counters directory of a port of a rdma device
// Port number starts from 1.
func GetRdmaSysfsHwStats(rdmaDevice string, port int) ([]RdmaStatEntry, error) {
path := filepath.Join(RdmaClassDir, rdmaDevice,
RdmaPortsdir, strconv.Itoa(port), RdmaHwCountersDir)
rdmastats, err := getCountersFromDir(path)
return rdmastats, err
}
// Get RDMA sysfs starts from counter and hw_counters directory for a requested
// port of a device.
func GetRdmaSysfsAllStats(rdmaDevice string, port int) (RdmaPortStats, error) {
var portstats RdmaPortStats
hwstats, err := GetRdmaSysfsHwStats(rdmaDevice, port)
if err != nil {
return portstats, nil
}
portstats.HwStats = hwstats
stats, err := GetRdmaSysfsStats(rdmaDevice, port)
if err != nil {
return portstats, nil
}
portstats.Stats = stats
portstats.Port = port
return portstats, nil
}
// Get RDMA sysfs starts from counter and hw_counters directory for a
// rdma device.
func GetRdmaSysfsAllPortsStats(rdmaDevice string) (RdmaStats, error) {
var allstats RdmaStats
path := filepath.Join(RdmaClassDir, rdmaDevice, RdmaPortsdir)
fd, err := os.Open(path)
if err != nil {
return allstats, err
}
fileInfos, err := fd.Readdir(-1)
defer fd.Close()
for i, file := range fileInfos {
if fileInfos[i].Name() == "." || fileInfos[i].Name() == ".." {
continue
}
if !file.IsDir() {
continue
}
port, _ := strconv.Atoi(file.Name())
portstats, err := GetRdmaSysfsAllStats(rdmaDevice, port)
if err != nil {
return allstats, err
}
allstats.PortStats = append(allstats.PortStats, portstats)
}
return allstats, nil
}
func printRdmaStats(device string, stats *RdmaStats) {
for _, portstats := range stats.PortStats {
fmt.Printf("device: %s, port: %d\n", device, portstats.Port)
fmt.Println("Hw stats:")
for _, entry := range portstats.HwStats {
fmt.Printf("%s: %d\n", entry.Name, entry.Value)
}
fmt.Println("Stats:")
for _, entry := range portstats.Stats {
fmt.Printf("%s: %d\n", entry.Name, entry.Value)
}
}
}
// Get RDMA statistics of a docker container.
// containerId is prefixed matched against the running docker containers,
// so a non ambiguous short identifier can be supplied as well.
func GetDockerContainerRdmaStats(containerId string) {
// Lock the OS Thread so we don't accidentally switch namespaces
runtime.LockOSThread()
defer runtime.UnlockOSThread()
originalHandle, err := netns.Get()
if err != nil {
log.Println("Fail to get handle of current net ns", err)
return
}
nsHandle, err := netns.GetFromDocker(containerId)
if err != nil {
log.Println("Invalid docker id: ", containerId)
return
}
netns.Set(nsHandle)
ifaces, err := net.Interfaces()
if err != nil {
netns.Set(originalHandle)
return
}
log.Printf("Net Interfaces: %v\n", ifaces)
for _, iface := range ifaces {
if iface.Name == "lo" {
continue
}
rdmadev, err := GetRdmaDeviceForNetdevice(iface.Name)
if err != nil {
continue
}
rdmastats, err := GetRdmaSysfsAllPortsStats(rdmadev)
if err != nil {
log.Println("Fail to query device stats: ", err)
continue
}
printRdmaStats(rdmadev, &rdmastats)
}
netns.Set(originalHandle)
}