From 7f379b3e479a1377062e7574ebf5010f0ee00a6f Mon Sep 17 00:00:00 2001 From: ASAKURA Kazuki <32762324+Arthur1@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:57:22 +0900 Subject: [PATCH] use shirou/gopsutil for get cpuinfo --- go.mod | 1 + go.sum | 3 +- spec/linux/cpu.go | 79 +++-------- spec/linux/cpu_test.go | 300 ----------------------------------------- 4 files changed, 25 insertions(+), 358 deletions(-) delete mode 100644 spec/linux/cpu_test.go diff --git a/go.mod b/go.mod index 0e42e0a2e..94f99c106 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect diff --git a/go.sum b/go.sum index b4c467b9f..09ded4bcc 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,9 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= diff --git a/spec/linux/cpu.go b/spec/linux/cpu.go index 5943ed01c..3dd275de1 100644 --- a/spec/linux/cpu.go +++ b/spec/linux/cpu.go @@ -4,13 +4,12 @@ package linux import ( - "bufio" - "io" - "os" - "strings" + "fmt" + "strconv" "github.com/mackerelio/golib/logging" "github.com/mackerelio/mackerel-client-go" + "github.com/shirou/gopsutil/v3/cpu" ) // CPUGenerator collects CPU specs @@ -19,63 +18,29 @@ type CPUGenerator struct { var cpuLogger = logging.GetLogger("spec.cpu") -func (g *CPUGenerator) generate(file io.Reader) (any, error) { - scanner := bufio.NewScanner(file) - - var results mackerel.CPU - var cur map[string]any - var modelName string - - for scanner.Scan() { - line := scanner.Text() - kv := strings.SplitN(line, ":", 2) - if len(kv) < 2 { - continue - } - key := strings.TrimSpace(kv[0]) - val := strings.TrimSpace(kv[1]) - switch key { - case "processor": - cur = make(map[string]any) - if modelName != "" { - cur["model_name"] = modelName - } - results = append(results, cur) - case "Processor", "system type": - modelName = val - case "vendor_id", "model", "stepping", "physical id", "core id", "model name", "cache size": - cur[strings.Replace(key, " ", "_", -1)] = val - case "cpu family": - cur["family"] = val - case "cpu cores": - cur["cores"] = val - case "cpu MHz": - cur["mhz"] = val - } - } - if err := scanner.Err(); err != nil { - cpuLogger.Errorf("Failed (skip this spec): %s", err) - return nil, err - } - - // Old kernels with CONFIG_SMP disabled has no "processor: " line - if len(results) == 0 && modelName != "" { - cur = make(map[string]any) - cur["model_name"] = modelName - results = append(results, cur) - } - - return results, nil -} - // Generate cpu specs -func (g *CPUGenerator) Generate() (any, error) { - file, err := os.Open("/proc/cpuinfo") +func (g *CPUGenerator) Generate() (interface{}, error) { + infoStats, err := cpu.Info() if err != nil { cpuLogger.Errorf("Failed (skip this spec): %s", err) return nil, err } - defer file.Close() + results := make(mackerel.CPU, 0, len(infoStats)) + for _, infoStat := range infoStats { + result := map[string]any{ + "vendor_id": infoStat.VendorID, + "model": infoStat.Model, + "stepping": strconv.Itoa(int(infoStat.Stepping)), + "physical_id": infoStat.PhysicalID, + "core_id": infoStat.CoreID, + "cache_size": fmt.Sprintf("%d KB", infoStat.CacheSize), + "model_name": infoStat.ModelName, + "family": infoStat.Family, + "cores": strconv.Itoa(int(infoStat.Cores)), + "mhz": strconv.FormatFloat(infoStat.Mhz, 'f', -1, 64), + } + results = append(results, result) + } - return g.generate(file) + return results, nil } diff --git a/spec/linux/cpu_test.go b/spec/linux/cpu_test.go deleted file mode 100644 index 293059029..000000000 --- a/spec/linux/cpu_test.go +++ /dev/null @@ -1,300 +0,0 @@ -//go:build linux -// +build linux - -package linux - -import ( - "bytes" - "testing" - - "github.com/mackerelio/mackerel-client-go" -) - -func TestCPUGenerate(t *testing.T) { - g := &CPUGenerator{} - value, err := g.Generate() - if err != nil { - t.Errorf("should not raise error: %v", err) - } - - cpu, typeOk := value.(mackerel.CPU) - if !typeOk { - t.Errorf("value should be mackerel.CPU. %+v", value) - } - - if len(cpu) == 0 { - t.Fatal("should have at least 1 cpu") - } - - cpu1 := cpu[0] - if _, ok := cpu1["vendor_id"]; !ok { - t.Error("cpu should have vendor_id") - } - if _, ok := cpu1["family"]; !ok { - t.Error("cpu should have family") - } - if _, ok := cpu1["model"]; !ok { - t.Error("cpu should have model") - } - if _, ok := cpu1["stepping"]; !ok { - t.Error("cpu should have stepping") - } - if _, ok := cpu1["model_name"]; !ok { - t.Error("cpu should have model_name") - } - if _, ok := cpu1["mhz"]; !ok { - t.Error("cpu should have mhz") - } - if _, ok := cpu1["cache_size"]; !ok { - t.Error("cpu should have cache_size") - } -} - -func TestCPUgenerate_linux4_0_amd64(t *testing.T) { - cpuinfo := `processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 2 -model name : QEMU Virtual CPU version 1.1.2 -stepping : 3 -microcode : 0x1 -cpu MHz : 3392.292 -cache size : 4096 KB -physical id : 0 -siblings : 1 -core id : 0 -cpu cores : 1 -apicid : 0 -initial apicid : 0 -fpu : yes -fpu_exception : yes -cpuid level : 4 -wp : yes -flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse36 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervisor lahf_lm -bugs : -bogomips : 6784.58 -clflush size : 64 -cache_alignment : 64 -address sizes : 40 bits physical, 48 bits virtual -power management: - -processor : 1 -vendor_id : GenuineIntel -cpu family : 6 -model : 2 -model name : QEMU Virtual CPU version 1.1.2 -stepping : 3 -microcode : 0x1 -cpu MHz : 3392.292 -cache size : 4096 KB -physical id : 1 -siblings : 1 -core id : 0 -cpu cores : 1 -apicid : 1 -initial apicid : 1 -fpu : yes -fpu_exception : yes -cpuid level : 4 -wp : yes -flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse36 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervisor lahf_lm -bugs : -bogomips : 6784.58 -clflush size : 64 -cache_alignment : 64 -address sizes : 40 bits physical, 48 bits virtual -power management:` - - g := &CPUGenerator{} - value, err := g.generate(bytes.NewBufferString(cpuinfo)) - if err != nil { - t.Errorf("should not raise error: %v", err) - } - - cpus, typeOk := value.(mackerel.CPU) - if !typeOk { - t.Errorf("value should be mackerel.CPU. %+v", value) - } - - if len(cpus) != 2 { - t.Fatal("should have exactly 2 cpus") - } - - for _, cpu := range cpus { - modelName, ok := cpu["model_name"] - if !ok { - t.Error("cpu should have model_name") - } - if modelName != "QEMU Virtual CPU version 1.1.2" { - t.Error("cpu should have correct model_name") - } - - mhz, ok := cpu["mhz"] - if !ok { - t.Error("cpu should have mhz") - } - if mhz != "3392.292" { - t.Error("cpu should have correct mhz") - } - } -} - -func TestCPUgenerate_linux3_18_arm(t *testing.T) { - cpuinfo := `processor : 0 -model name : ARMv7 Processor rev 5 (v7l) -BogoMIPS : 38.40 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc07 -CPU revision : 5 - -processor : 1 -model name : ARMv7 Processor rev 5 (v7l) -BogoMIPS : 38.40 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc07 -CPU revision : 5 - -processor : 2 -model name : ARMv7 Processor rev 5 (v7l) -BogoMIPS : 38.40 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc07 -CPU revision : 5 - -processor : 3 -model name : ARMv7 Processor rev 5 (v7l) -BogoMIPS : 38.40 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc07 -CPU revision : 5 - -Hardware : BCM2709 -Revision : 1a01040` - - g := &CPUGenerator{} - value, err := g.generate(bytes.NewBufferString(cpuinfo)) - if err != nil { - t.Errorf("should not raise error: %v", err) - } - - cpus, typeOk := value.(mackerel.CPU) - if !typeOk { - t.Errorf("value should be mackerel.CPU. %+v", value) - } - - if len(cpus) != 4 { - t.Fatal("should have exactly 4 cpus") - } - - for _, cpu := range cpus { - modelName, ok := cpu["model_name"] - if !ok { - t.Error("cpu should have model_name") - } - if modelName != "ARMv7 Processor rev 5 (v7l)" { - t.Error("cpu should have correct model_name") - } - } -} - -func TestCPUgenerate_linux3_4_smp_arm(t *testing.T) { - cpuinfo := `Processor : ARMv7 Processor rev 0 (v7l) -processor : 0 -BogoMIPS : 38.40 - -processor : 1 -BogoMIPS : 38.40 - -processor : 2 -BogoMIPS : 38.40 - -processor : 3 -BogoMIPS : 38.40 - -Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt -CPU implementer : 0x51 -CPU architecture: 7 -CPU variant : 0x2 -CPU part : 0x06f -CPU revision : 0 - -Hardware : Qualcomm MSM 8974 (Flattened Device Tree) -Revision : 0000 -Serial : 0000000000000000` - - g := &CPUGenerator{} - value, err := g.generate(bytes.NewBufferString(cpuinfo)) - if err != nil { - t.Errorf("should not raise error: %v", err) - } - - cpus, typeOk := value.(mackerel.CPU) - if !typeOk { - t.Errorf("value should be mackerel.CPU. %+v", value) - } - - if len(cpus) != 4 { - t.Fatal("should have exactly 4 cpus") - } - - for _, cpu := range cpus { - modelName, ok := cpu["model_name"] - if !ok { - t.Error("cpu should have model_name") - } - if modelName != "ARMv7 Processor rev 0 (v7l)" { - t.Error("cpu should have correct model_name") - } - } -} - -func TestCPUgenerate_linux3_0_nosmp_arm(t *testing.T) { - cpuinfo := `Processor : Marvell PJ4Bv7 Processor rev 1 (v7l) -BogoMIPS : 1196.85 -Features : swp half thumb fastmult vfp edsp vfpv3 vfpv3d16 -CPU implementer : 0x56 -CPU architecture: 7 -CPU variant : 0x1 -CPU part : 0x581 -CPU revision : 1 - -Hardware : Marvell Armada-370 -Revision : 0000 -Serial : 0000000000000000` - - g := &CPUGenerator{} - value, err := g.generate(bytes.NewBufferString(cpuinfo)) - if err != nil { - t.Errorf("should not raise error: %v", err) - } - - cpus, typeOk := value.(mackerel.CPU) - if !typeOk { - t.Errorf("value should be mackerel.CPU. %+v", value) - } - - if len(cpus) != 1 { - t.Fatal("should have exactly 1 cpu") - } - - cpu1 := cpus[0] - modelName, ok := cpu1["model_name"] - if !ok { - t.Error("cpu should have model_name") - } - if modelName != "Marvell PJ4Bv7 Processor rev 1 (v7l)" { - t.Error("cpu should have correct model_name") - } -}