diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 80ce384..75f10b4 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -7,6 +7,22 @@ Fully Supported Platforms - Operating Systems: Ubuntu 16.04 and newer, CentOS 7 and newer Note: svr-info may work on other micro-architectures and Linux distributions, but has not been thoroughly tested +2.3.2 +Features Added +- report L3 size from MSR, fallback to lscpu +- new field 'L3 per core' in CPU table +- if AMD 'frequency boost' detected, show 'enabled (AMD Frequency Boost)' in the Intel Turbo Boost field +Bugs Fixed +- Don't use "-tt" option with ssh commands that connect to remote sytems +- Fix location of 'extras' directory +- ARM collector binary now extracted for use at runtime +- Graviton 2 CPU architecture detected +Known Issues +- The storage micro-benchmark may not run on CentOS due to locale settings. +- HTML report may scroll out of view when menu is minimized and window is small. +- CPU cache sizes are reported in aggregate on Ubuntu 20.04 and newer. +- DRAM population may be incorrectly reported on public cloud IaaS VMs. + 2.3.1 Features Added - override local temporary directory used by svr-info using the -temp CLI option diff --git a/builder/Dockerfile b/builder/Dockerfile index bcdca53..9e5f9a4 100644 --- a/builder/Dockerfile +++ b/builder/Dockerfile @@ -26,7 +26,7 @@ RUN cp /usr/local/lib/libz.a /usr/lib/x86_64-linux-gnu/libz.a RUN curl -s https://gitlab.com/akihe/radamsa/uploads/a2228910d0d3c68d19c09cee3943d7e5/radamsa-0.6.c.gz | gzip -d | cc -O2 -x c -o /usr/local/bin/radamsa - # Install Go -ARG GO_VERSION="1.20.1" +ARG GO_VERSION="1.20.4" RUN wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz RUN tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz RUN rm go${GO_VERSION}.linux-amd64.tar.gz diff --git a/src/orchestrator/collection.go b/src/orchestrator/collection.go index 7735d18..78d8f51 100644 --- a/src/orchestrator/collection.go +++ b/src/orchestrator/collection.go @@ -224,7 +224,7 @@ func (c *Collection) getExtraFiles() (extras []string, err error) { if err != nil { return } - extrasDir := filepath.Join(exePath, "extras") + extrasDir := filepath.Join(filepath.Dir(exePath), "extras") dir, err := os.Open(extrasDir) if err != nil { return @@ -346,8 +346,11 @@ func (c *Collection) Collect() (err error) { tempDir, ) if err != nil { - log.Printf("failed to run collector for %s", c.target.GetName()) - log.Printf("collector error output for %s: %s", c.target.GetName(), c.stderr) + log.Printf("failed to run collector on %s, stderr: [%s]. "+ + "Override the temporary directory used by svr-info with the "+ + "--targettemp option if the target's temporary directory does "+ + "not support binary execution.", + c.target.GetName(), c.stderr) return } c.outputFilePath, err = c.getCollectorOutputFile(tempDir) @@ -386,8 +389,8 @@ func (c *Collection) Collect() (err error) { megaPath, ) if err != nil { - log.Printf("failed to run megadata collector for %s", c.target.GetName()) - log.Printf("megadata collector error output for %s: %s", c.target.GetName(), c.stderr) + log.Printf("failed to run megadata collector on %s, stderr: [%s]", + c.target.GetName(), c.stderr) return } megadataTarball := filepath.Join(tempDir, c.target.GetName()+"_megadata.tgz") diff --git a/src/orchestrator/main.go b/src/orchestrator/main.go index 8b1a588..389bf5e 100644 --- a/src/orchestrator/main.go +++ b/src/orchestrator/main.go @@ -353,7 +353,7 @@ func getLogfileName() string { } func (app *App) writeExecutableResources() (err error) { - toolNames := []string{"sshpass", "reporter", "collector", "collector_deps_amd64.tgz", "collector_deps_arm64.tgz"} + toolNames := []string{"sshpass", "reporter", "collector", "collector_arm64", "collector_deps_amd64.tgz", "collector_deps_arm64.tgz"} for _, toolName := range toolNames { // get the exe from our embedded resources var toolBytes []byte diff --git a/src/orchestrator/resources/collector_reports.yaml.tmpl b/src/orchestrator/resources/collector_reports.yaml.tmpl index 476972e..a3626cf 100644 --- a/src/orchestrator/resources/collector_reports.yaml.tmpl +++ b/src/orchestrator/resources/collector_reports.yaml.tmpl @@ -161,6 +161,11 @@ commands: superuser: true modprobe: msr parallel: true + - label: rdmsr 0xc90 + command: rdmsr 0xc90 + superuser: true + modprobe: msr + parallel: true - label: uncore cha count command: rdmsr 0x702 superuser: true diff --git a/src/pkg/cpu/cpu_test.go b/src/pkg/cpu/cpu_test.go index aa69ceb..6ce2f24 100644 --- a/src/pkg/cpu/cpu_test.go +++ b/src/pkg/cpu/cpu_test.go @@ -87,7 +87,7 @@ func TestFindCPU(t *testing.T) { if uarch != "HSW" { t.Fatal(fmt.Errorf("Found the wrong CPU")) } - uarch, err = cpu.GetMicroArchitecture("0", "1", "r3p1") // + uarch, err = cpu.GetMicroArchitecture("", "1", "r3p1") // if err != nil { t.Fatal(err) } diff --git a/src/pkg/cpu/resources/cpus.yaml b/src/pkg/cpu/resources/cpus.yaml index ccc9973..e35d8a7 100644 --- a/src/pkg/cpu/resources/cpus.yaml +++ b/src/pkg/cpu/resources/cpus.yaml @@ -164,14 +164,14 @@ ######### # AWS Graviton 2 - architecture: Neoverse N1 - family: 0 + family: model: 1 stepping: r3p1 channels: 8 # AWS Graviton 3 - architecture: Neoverse V1 - family: 0 + family: model: 1 stepping: r1p1 channels: 8 diff --git a/src/pkg/target/target.go b/src/pkg/target/target.go index 8384a27..264b756 100644 --- a/src/pkg/target/target.go +++ b/src/pkg/target/target.go @@ -87,9 +87,6 @@ func (t *RemoteTarget) getSSHFlags(scp bool) (flags []string) { "-o", "ControlPersist=1m", } - if scp == false { - flags = append(flags, "-tt") - } if t.key != "" { keyFlags := []string{ "-o", diff --git a/src/reporter/report_tables.go b/src/reporter/report_tables.go index 2dbeaba..ca6c42a 100644 --- a/src/reporter/report_tables.go +++ b/src/reporter/report_tables.go @@ -698,6 +698,7 @@ func newCPUTable(sources []*Source, cpusInfo *cpu.CPU, category TableCategory) ( sockets := source.valFromRegexSubmatch("lscpu", `^Socket\(.*:\s*(.+?)$`) capid4 := source.valFromRegexSubmatch("lspci bits", `^([0-9a-fA-F]+)`) devices := source.valFromRegexSubmatch("lspci devices", `^([0-9]+)`) + coresPerSocket := source.valFromRegexSubmatch("lscpu", `^Core\(s\) per socket.*:\s*(.+?)$`) var microarchitecture string var err error if family == "6" && (model == "143" /*SPR*/ || model == "207" /*EMR*/ || model == "173" /*GNR*/) { @@ -736,6 +737,7 @@ func newCPUTable(sources []*Source, cpusInfo *cpu.CPU, category TableCategory) ( "L1i Cache", "L2 Cache", "L3 Cache", + "L3 per Core", "Memory Channels", "Prefetchers", "Intel Turbo Boost", @@ -756,17 +758,18 @@ func newCPUTable(sources []*Source, cpusInfo *cpu.CPU, category TableCategory) ( source.valFromRegexSubmatch("lscpu", `^CPU\(.*:\s*(.+?)$`), source.valFromRegexSubmatch("lscpu", `^On-line CPU.*:\s*(.+?)$`), source.getHyperthreading(), - source.valFromRegexSubmatch("lscpu", `^Core\(s\) per socket.*:\s*(.+?)$`), + coresPerSocket, source.valFromRegexSubmatch("lscpu", `^Socket\(.*:\s*(.+?)$`), source.valFromRegexSubmatch("lscpu", `^NUMA node\(.*:\s*(.+?)$`), source.getNUMACPUList(), source.valFromRegexSubmatch("lscpu", `^L1d cache.*:\s*(.+?)$`), source.valFromRegexSubmatch("lscpu", `^L1i cache.*:\s*(.+?)$`), source.valFromRegexSubmatch("lscpu", `^L2 cache.*:\s*(.+?)$`), - source.valFromRegexSubmatch("lscpu", `^L3 cache.*:\s*(.+?)$`), + source.getL3(microarchitecture), + source.getL3PerCore(microarchitecture, coresPerSocket), channels, source.getPrefetchers(), - enabledIfValAndTrue(source.valFromRegexSubmatch("cpuid -1", `^Intel Turbo Boost Technology\s*= (.+?)$`)), + source.getTurboEnabled(family), source.valFromRegexSubmatch("lscpu", `^Virtualization.*:\s*(.+?)$`), source.getPPINs(), }, diff --git a/src/reporter/source.go b/src/reporter/source.go index 2beb8b7..327bf10 100644 --- a/src/reporter/source.go +++ b/src/reporter/source.go @@ -462,6 +462,75 @@ func (s *Source) getCHACount() (val string) { return } +func (s *Source) getCacheWays(uArch string) (cacheWays []int64) { + var wayCount int + if uArch == "SKX" || uArch == "CLX" { + wayCount = 11 + } else if uArch == "ICX" { + wayCount = 12 + } else if uArch == "SPR_MCC" || uArch == "SPR_XCC" { + wayCount = 15 + } else if uArch == "EMR" { + wayCount = 20 + } else { + return + } + var cacheSize int64 = 0 + // set wayCount bits in cacheSize + for i := 0; i < wayCount; i++ { + cacheSize = (cacheSize << 1) | 1 + } + var shift int64 = -1 + for i := 0; i < wayCount; i++ { + cacheWays = append([]int64{cacheSize}, cacheWays...) + shift = shift << 1 + cacheSize = cacheSize & shift + } + return +} + +func (s *Source) getL3(uArch string) (val string) { + l3MSRHex := s.getCommandOutputLine("rdmsr 0xc90") + l3MSR, err := strconv.ParseInt(l3MSRHex, 16, 64) + l3Lscpu := s.valFromRegexSubmatch("lscpu", `^L3 cache.*:\s*(.+?)$`) + if err != nil || l3MSR == 0 { + val = l3Lscpu + return + } + cpuL3SizeMB, err := strconv.ParseFloat(strings.Split(l3Lscpu, " ")[0], 64) + if err != nil { + return + } + cacheWays := s.getCacheWays(uArch) + if len(cacheWays) == 0 { + return + } + cpul3SizeGB := cpuL3SizeMB / 1024 + GBperWay := cpul3SizeGB / float64(len(cacheWays)) + for i, way := range cacheWays { + if way == l3MSR { + cacheMB := float64(i+1) * GBperWay * 1024 + val = fmt.Sprintf("%s MiB (1 instance)", strconv.FormatFloat(cacheMB, 'f', -1, 64)) + return + } + } + return +} + +func (s *Source) getL3PerCore(uArch string, coresPerSocketStr string) (val string) { + l3, err := strconv.ParseFloat(strings.Split(s.getL3(uArch), " ")[0], 64) + if err != nil { + return + } + coresPerSocket, err := strconv.Atoi(coresPerSocketStr) + if err != nil || coresPerSocket == 0 { + return + } + cacheMB := l3 / float64(coresPerSocket) + val = fmt.Sprintf("%s MiB", strconv.FormatFloat(cacheMB, 'f', -1, 64)) + return +} + func (s *Source) getPrefetchers() (val string) { prefetchers := s.valFromRegexSubmatch("rdmsr 0x1a4", `^([0-9a-fA-F]+)`) if prefetchers != "" { @@ -849,3 +918,16 @@ func (s *Source) getSystemFolded() (folded string) { } return } + +func (s *Source) getTurboEnabled(family string) (val string) { + if family == "6" { // Intel + val = enabledIfValAndTrue(s.valFromRegexSubmatch("cpuid -1", `^Intel Turbo Boost Technology\s*= (.+?)$`)) + return val + } else if family == "23" || family == "25" { // AMD + val = s.valFromRegexSubmatch("lscpu", `^Frequency boost.*:\s*(.+?)$`) + if val != "" { + val = val + " (AMD Frequency Boost)" + } + } + return +} diff --git a/version.txt b/version.txt index a625450..e703481 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.3.1 \ No newline at end of file +2.3.2 \ No newline at end of file