go.d lmsensors improve performance (#18429)
Ilya Mashchenko committed
Aug 28, 2024 at 14:43 UTC
4c987bbd06f5cfb4337ec6e68728af522baad9c7
2 files changed
+111
-113
src/go/plugin/go.d/modules/sensors/lmsensors/scanner.go
+54
-56
@@ -2,7 +2,7 @@ package lmsensors
2
3
import (
4
"fmt"
5
- "io/ioutil"
5
+ "io/fs"
6
"os"
7
"path/filepath"
8
"strings"
@@ -13,7 +13,7 @@ type filesystem interface {
13
ReadFile(filename string) (string, error)
14
Readlink(name string) (string, error)
15
Stat(name string) (os.FileInfo, error)
16
- Walk(root string, walkFn filepath.WalkFunc) error
16
+ WalkDir(root string, walkFn fs.WalkDirFunc) error
17
}
18
19
// A Scanner scans for Devices, so data can be read from their Sensors.
@@ -30,30 +30,31 @@ func New() *Scanner {
30
31
// Scan scans for Devices and their Sensors.
32
func (s *Scanner) Scan() ([]*Device, error) {
33
- // Determine common device locations in Linux /sys filesystem.
33
paths, err := s.detectDevicePaths()
34
if err != nil {
35
return nil, err
36
}
37
38
var devices []*Device
40
- for _, p := range paths {
41
- d := &Device{}
42
- raw := make(map[string]map[string]string, 0)
39
+
40
+ for _, rootPath := range paths {
41
+ dev := &Device{}
42
+ raw := make(map[string]map[string]string)
43
44
// Walk filesystem paths to fetch devices and sensors
45
- err := s.fs.Walk(p, func(path string, info os.FileInfo, err error) error {
45
+ err := s.fs.WalkDir(rootPath, func(path string, de fs.DirEntry, err error) error {
46
if err != nil {
47
return err
48
}
49
50
- // Skip directories and anything that isn't a regular file
51
- if info.IsDir() || !info.Mode().IsRegular() {
50
+ if de.IsDir() || !de.Type().IsRegular() {
51
+ if de.IsDir() && path != rootPath {
52
+ return fs.SkipDir
53
+ }
54
return nil
55
}
56
55
- // Skip some files that can't be read or don't provide useful
56
- // sensor information
57
+ // Skip some files that can't be read or don't provide useful sensor information
58
file := filepath.Base(path)
59
if shouldSkip(file) {
60
return nil
@@ -64,48 +65,46 @@ func (s *Scanner) Scan() ([]*Device, error) {
65
return nil
66
}
67
67
- switch file {
68
- // Found name of device
69
- case "name":
70
- d.Name = s
68
+ if file == "name" {
69
+ dev.Name = s
70
+ return nil
71
}
72
73
// Sensor names in format "sensor#_foo", e.g. "temp1_input"
74
- fs := strings.SplitN(file, "_", 2)
75
- if len(fs) != 2 {
74
+ parts := strings.SplitN(file, "_", 2)
75
+ if len(parts) != 2 {
76
return nil
77
}
78
79
- // Gather sensor data into map for later processing
80
- if _, ok := raw[fs[0]]; !ok {
81
- raw[fs[0]] = make(map[string]string, 0)
79
+ if _, ok := raw[parts[0]]; !ok {
80
+ raw[parts[0]] = make(map[string]string)
81
}
82
84
- raw[fs[0]][fs[1]] = s
83
+ raw[parts[0]][parts[1]] = s
84
+
85
return nil
86
})
87
if err != nil {
88
return nil, err
89
}
90
91
- // Parse all possible sensors from raw data
91
sensors, err := parseSensors(raw)
92
if err != nil {
93
return nil, err
94
}
95
97
- d.Sensors = sensors
98
- devices = append(devices, d)
96
+ dev.Sensors = sensors
97
+ devices = append(devices, dev)
98
}
99
100
renameDevices(devices)
101
+
102
return devices, nil
103
}
104
105
-// renameDevices renames devices in place to prevent duplicate device names,
106
-// and to number each device.
105
+// renameDevices renames devices in place to prevent duplicate device names, and to number each device.
106
func renameDevices(devices []*Device) {
108
- nameCount := make(map[string]int, 0)
107
+ nameCount := make(map[string]int)
108
109
for i := range devices {
110
name := devices[i].Name
@@ -117,19 +116,17 @@ func renameDevices(devices []*Device) {
116
}
117
}
118
120
-// detectDevicePaths performs a filesystem walk to paths where devices may
121
-// reside on Linux.
119
+// detectDevicePaths performs a filesystem walk to paths where devices may reside on Linux.
120
func (s *Scanner) detectDevicePaths() ([]string, error) {
121
const lookPath = "/sys/class/hwmon"
122
123
var paths []string
126
- err := s.fs.Walk(lookPath, func(path string, info os.FileInfo, err error) error {
124
+ err := s.fs.WalkDir(lookPath, func(path string, de os.DirEntry, err error) error {
125
if err != nil {
126
return err
127
}
128
131
- // Skip anything that isn't a symlink
132
- if info.Mode()&os.ModeSymlink == 0 {
129
+ if de.Type()&os.ModeSymlink == 0 {
130
return nil
131
}
132
@@ -137,10 +134,10 @@ func (s *Scanner) detectDevicePaths() ([]string, error) {
134
if err != nil {
135
return err
136
}
137
+
138
dest = filepath.Join(lookPath, filepath.Clean(dest))
139
142
- // Symlink destination has a file called name, meaning a sensor exists
143
- // here and data can be retrieved
140
+ // Symlink destination has a file called name, meaning a sensor exists here and data can be retrieved
141
fi, err := s.fs.Stat(filepath.Join(dest, "name"))
142
if err != nil && !os.IsNotExist(err) {
143
return err
@@ -150,16 +147,14 @@ func (s *Scanner) detectDevicePaths() ([]string, error) {
147
return nil
148
}
149
153
- // Symlink destination has another symlink called device, which can be
154
- // read and used to retrieve data
150
+ // Symlink destination has another symlink called device, which can be read and used to retrieve data
151
device := filepath.Join(dest, "device")
152
fi, err = s.fs.Stat(device)
153
if err != nil {
158
- if os.IsNotExist(err) {
159
- return nil
154
+ if !os.IsNotExist(err) {
155
+ return err
156
}
161
-
162
- return err
157
+ return nil
158
}
159
160
if fi.Mode()&os.ModeSymlink != 0 {
@@ -170,27 +165,26 @@ func (s *Scanner) detectDevicePaths() ([]string, error) {
165
if err != nil {
166
return err
167
}
168
+
169
dest = filepath.Join(dest, filepath.Clean(device))
170
175
- // Symlink destination has a file called name, meaning a sensor exists
176
- // here and data can be retrieved
171
+ // Symlink destination has a file called name, meaning a sensor exists here and data can be retrieved
172
if _, err := s.fs.Stat(filepath.Join(dest, "name")); err != nil {
178
- if os.IsNotExist(err) {
179
- return nil
173
+ if !os.IsNotExist(err) {
174
+ return err
175
}
181
-
182
- return err
176
+ return nil
177
}
178
179
paths = append(paths, dest)
180
+
181
return nil
182
})
183
184
return paths, err
185
}
186
192
-// shouldSkip indicates if a given filename should be skipped during the
193
-// filesystem walk operation.
187
+// shouldSkip indicates if a given filename should be skipped during the filesystem walk operation.
188
func shouldSkip(file string) bool {
189
if strings.HasPrefix(file, "runtime_") {
190
return true
@@ -212,21 +206,25 @@ func shouldSkip(file string) bool {
206
207
var _ filesystem = &systemFilesystem{}
208
215
-// A systemFilesystem is a filesystem which uses operations on the host
216
-// filesystem.
209
+// A systemFilesystem is a filesystem which uses operations on the host filesystem.
210
type systemFilesystem struct{}
211
212
func (fs *systemFilesystem) ReadFile(filename string) (string, error) {
220
- b, err := ioutil.ReadFile(filename)
213
+ b, err := os.ReadFile(filename)
214
if err != nil {
215
return "", err
216
}
224
-
217
return strings.TrimSpace(string(b)), nil
218
}
219
228
-func (fs *systemFilesystem) Readlink(name string) (string, error) { return os.Readlink(name) }
229
-func (fs *systemFilesystem) Stat(name string) (os.FileInfo, error) { return os.Stat(name) }
230
-func (fs *systemFilesystem) Walk(root string, walkFn filepath.WalkFunc) error {
231
- return filepath.Walk(root, walkFn)
220
+func (fs *systemFilesystem) Readlink(name string) (string, error) {
221
+ return os.Readlink(name)
222
+}
223
+
224
+func (fs *systemFilesystem) Stat(name string) (os.FileInfo, error) {
225
+ return os.Stat(name)
226
+}
227
+
228
+func (fs *systemFilesystem) WalkDir(root string, walkFn fs.WalkDirFunc) error {
229
+ return filepath.WalkDir(root, walkFn)
230
}
src/go/plugin/go.d/modules/sensors/lmsensors/scanner_test.go
+57
-57
@@ -2,8 +2,8 @@ package lmsensors
2
3
import (
4
"fmt"
5
+ "io/fs"
6
"os"
6
- "path/filepath"
7
"reflect"
8
"strings"
9
"testing"
@@ -30,19 +30,19 @@ func TestScannerScan(t *testing.T) {
30
files: []memoryFile{
31
{
32
name: "/sys/class/hwmon",
33
- info: &memoryFileInfo{
33
+ dirEntry: &memoryDirEntry{
34
isDir: true,
35
},
36
},
37
{
38
name: "/sys/class/hwmon/hwmon0",
39
- info: &memoryFileInfo{
39
+ dirEntry: &memoryDirEntry{
40
mode: os.ModeSymlink,
41
},
42
},
43
{
44
name: "/sys/devices/LNXSYSTM:00/device:00/ACPI0000:00",
45
- info: &memoryFileInfo{
45
+ dirEntry: &memoryDirEntry{
46
isDir: true,
47
},
48
},
@@ -51,8 +51,8 @@ func TestScannerScan(t *testing.T) {
51
err: os.ErrNotExist,
52
},
53
{
54
- name: "/sys/devices/LNXSYSTM:00/device:00/ACPI0000:00/hwmon/hwmon0/device",
55
- info: &memoryFileInfo{
54
+ name: "/sys/devices/LNXSYSTM:00/device:00/ACPI0000:00/hwmon/hwmon0/device",
55
+ dirEntry: &memoryDirEntry{
56
// mode: os.ModeSymlink,
57
},
58
},
@@ -110,19 +110,19 @@ func TestScannerScan(t *testing.T) {
110
files: []memoryFile{
111
{
112
name: "/sys/class/hwmon",
113
- info: &memoryFileInfo{
113
+ dirEntry: &memoryDirEntry{
114
isDir: true,
115
},
116
},
117
{
118
name: "/sys/class/hwmon/hwmon0",
119
- info: &memoryFileInfo{
119
+ dirEntry: &memoryDirEntry{
120
mode: os.ModeSymlink,
121
},
122
},
123
{
124
name: "/sys/devices/virtual/hwmon/hwmon0",
125
- info: &memoryFileInfo{
125
+ dirEntry: &memoryDirEntry{
126
isDir: true,
127
},
128
},
@@ -162,19 +162,19 @@ func TestScannerScan(t *testing.T) {
162
files: []memoryFile{
163
{
164
name: "/sys/class/hwmon",
165
- info: &memoryFileInfo{
165
+ dirEntry: &memoryDirEntry{
166
isDir: true,
167
},
168
},
169
{
170
name: "/sys/class/hwmon/hwmon1",
171
- info: &memoryFileInfo{
171
+ dirEntry: &memoryDirEntry{
172
mode: os.ModeSymlink,
173
},
174
},
175
{
176
name: "/sys/devices/platform/coretemp.0",
177
- info: &memoryFileInfo{
177
+ dirEntry: &memoryDirEntry{
178
isDir: true,
179
},
180
},
@@ -183,8 +183,8 @@ func TestScannerScan(t *testing.T) {
183
err: os.ErrNotExist,
184
},
185
{
186
- name: "/sys/devices/platform/coretemp.0/hwmon/hwmon1/device",
187
- info: &memoryFileInfo{
186
+ name: "/sys/devices/platform/coretemp.0/hwmon/hwmon1/device",
187
+ dirEntry: &memoryDirEntry{
188
// mode: os.ModeSymlink,
189
},
190
},
@@ -266,19 +266,19 @@ func TestScannerScan(t *testing.T) {
266
files: []memoryFile{
267
{
268
name: "/sys/class/hwmon",
269
- info: &memoryFileInfo{
269
+ dirEntry: &memoryDirEntry{
270
isDir: true,
271
},
272
},
273
{
274
name: "/sys/class/hwmon/hwmon2",
275
- info: &memoryFileInfo{
275
+ dirEntry: &memoryDirEntry{
276
mode: os.ModeSymlink,
277
},
278
},
279
{
280
name: "/sys/devices/platform/it87.2608",
281
- info: &memoryFileInfo{
281
+ dirEntry: &memoryDirEntry{
282
isDir: true,
283
},
284
},
@@ -287,8 +287,8 @@ func TestScannerScan(t *testing.T) {
287
err: os.ErrNotExist,
288
},
289
{
290
- name: "/sys/devices/platform/it87.2608/hwmon/hwmon2/device",
291
- info: &memoryFileInfo{
290
+ name: "/sys/devices/platform/it87.2608/hwmon/hwmon2/device",
291
+ dirEntry: &memoryDirEntry{
292
// mode: os.ModeSymlink,
293
},
294
},
@@ -426,25 +426,25 @@ func TestScannerScan(t *testing.T) {
426
files: []memoryFile{
427
{
428
name: "/sys/class/hwmon",
429
- info: &memoryFileInfo{
429
+ dirEntry: &memoryDirEntry{
430
isDir: true,
431
},
432
},
433
{
434
name: "/sys/class/hwmon/hwmon1",
435
- info: &memoryFileInfo{
435
+ dirEntry: &memoryDirEntry{
436
mode: os.ModeSymlink,
437
},
438
},
439
{
440
name: "/sys/class/hwmon/hwmon2",
441
- info: &memoryFileInfo{
441
+ dirEntry: &memoryDirEntry{
442
mode: os.ModeSymlink,
443
},
444
},
445
{
446
name: "/sys/devices/platform/coretemp.0",
447
- info: &memoryFileInfo{
447
+ dirEntry: &memoryDirEntry{
448
isDir: true,
449
},
450
},
@@ -453,8 +453,8 @@ func TestScannerScan(t *testing.T) {
453
err: os.ErrNotExist,
454
},
455
{
456
- name: "/sys/devices/platform/coretemp.0/hwmon/hwmon1/device",
457
- info: &memoryFileInfo{
456
+ name: "/sys/devices/platform/coretemp.0/hwmon/hwmon1/device",
457
+ dirEntry: &memoryDirEntry{
458
// mode: os.ModeSymlink,
459
},
460
},
@@ -504,7 +504,7 @@ func TestScannerScan(t *testing.T) {
504
},
505
{
506
name: "/sys/devices/platform/coretemp.1",
507
- info: &memoryFileInfo{
507
+ dirEntry: &memoryDirEntry{
508
isDir: true,
509
},
510
},
@@ -513,8 +513,8 @@ func TestScannerScan(t *testing.T) {
513
err: os.ErrNotExist,
514
},
515
{
516
- name: "/sys/devices/platform/coretemp.1/hwmon/hwmon2/device",
517
- info: &memoryFileInfo{
516
+ name: "/sys/devices/platform/coretemp.1/hwmon/hwmon2/device",
517
+ dirEntry: &memoryDirEntry{
518
// mode: os.ModeSymlink,
519
},
520
},
@@ -619,19 +619,19 @@ func TestScannerScan(t *testing.T) {
619
files: []memoryFile{
620
{
621
name: "/sys/class/hwmon",
622
- info: &memoryFileInfo{
622
+ dirEntry: &memoryDirEntry{
623
isDir: true,
624
},
625
},
626
{
627
name: "/sys/class/hwmon/hwmon0",
628
- info: &memoryFileInfo{
628
+ dirEntry: &memoryDirEntry{
629
mode: os.ModeSymlink,
630
},
631
},
632
{
633
name: "/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0",
634
- info: &memoryFileInfo{
634
+ dirEntry: &memoryDirEntry{
635
isDir: true,
636
},
637
},
@@ -640,8 +640,8 @@ func TestScannerScan(t *testing.T) {
640
err: os.ErrNotExist,
641
},
642
{
643
- name: "/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0/hwmon/hwmon0/device",
644
- info: &memoryFileInfo{
643
+ name: "/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0/hwmon/hwmon0/device",
644
+ dirEntry: &memoryDirEntry{
645
// mode: os.ModeSymlink,
646
},
647
},
@@ -747,11 +747,11 @@ func (fs *memoryFilesystem) Readlink(name string) (string, error) {
747
func (fs *memoryFilesystem) Stat(name string) (os.FileInfo, error) {
748
for _, f := range fs.files {
749
if f.name == name {
750
- info := f.info
751
- if info == nil {
752
- info = &memoryFileInfo{}
750
+ de := f.dirEntry
751
+ if de == nil {
752
+ de = &memoryDirEntry{}
753
}
754
-
754
+ info, _ := de.Info()
755
return info, f.err
756
}
757
}
@@ -759,7 +759,7 @@ func (fs *memoryFilesystem) Stat(name string) (os.FileInfo, error) {
759
return nil, fmt.Errorf("stat: file %q not in memory", name)
760
}
761
762
-func (fs *memoryFilesystem) Walk(root string, walkFn filepath.WalkFunc) error {
762
+func (fs *memoryFilesystem) WalkDir(root string, walkFn fs.WalkDirFunc) error {
763
if _, err := fs.Stat(root); err != nil {
764
return err
765
}
@@ -770,12 +770,12 @@ func (fs *memoryFilesystem) Walk(root string, walkFn filepath.WalkFunc) error {
770
continue
771
}
772
773
- info := f.info
774
- if info == nil {
775
- info = &memoryFileInfo{}
773
+ de := f.dirEntry
774
+ if de == nil {
775
+ de = &memoryDirEntry{}
776
}
777
778
- if err := walkFn(f.name, info, nil); err != nil {
778
+ if err := walkFn(f.name, de, nil); err != nil {
779
return err
780
}
781
}
@@ -787,24 +787,24 @@ func (fs *memoryFilesystem) Walk(root string, walkFn filepath.WalkFunc) error {
787
type memoryFile struct {
788
name string
789
contents string
790
- info os.FileInfo
790
+ dirEntry fs.DirEntry
791
err error
792
}
793
794
-var _ os.FileInfo = &memoryFileInfo{}
794
+var _ fs.DirEntry = &memoryDirEntry{}
795
796
-// A memoryFileInfo is an os.FileInfo used by memoryFiles.
797
-type memoryFileInfo struct {
798
- name string
799
- size int64
800
- mode os.FileMode
801
- modTime time.Time
802
- isDir bool
796
+// A memoryDirEntry is a fs.DirEntry used by memoryFiles.
797
+type memoryDirEntry struct {
798
+ name string
799
+ mode os.FileMode
800
+ isDir bool
801
}
802
805
-func (fi *memoryFileInfo) Name() string { return fi.name }
806
-func (fi *memoryFileInfo) Size() int64 { return fi.size }
807
-func (fi *memoryFileInfo) Mode() os.FileMode { return fi.mode }
808
-func (fi *memoryFileInfo) ModTime() time.Time { return fi.modTime }
809
-func (fi *memoryFileInfo) IsDir() bool { return fi.isDir }
810
-func (fi *memoryFileInfo) Sys() interface{} { return nil }
803
+func (fi *memoryDirEntry) Name() string { return fi.name }
804
+func (fi *memoryDirEntry) Type() os.FileMode { return fi.mode }
805
+func (fi *memoryDirEntry) IsDir() bool { return fi.isDir }
806
+func (fi *memoryDirEntry) Info() (fs.FileInfo, error) { return fi, nil }
807
+func (fi *memoryDirEntry) Sys() interface{} { return nil }
808
+func (fi *memoryDirEntry) Size() int64 { return 0 }
809
+func (fi *memoryDirEntry) Mode() os.FileMode { return fi.Type() }
810
+func (fi *memoryDirEntry) ModTime() time.Time { return time.Now() }