Improve the system-info.sh script to report CPU and RAM meta-data. (#7815)

* Add CPU information collection for Linux and FreeBSD.

This adds logic to system.info.sh to collect info about the system's CPU.

It adds the following keys to the output of the script:

* NETDATA_CPU_LOGICAL_CPU_COUNT: This reports the number of logical CPU
  cores the system is actually using (including offline ones). This may
  differ from the CPU's advertised core count, but is what most people
  actually care about.
* NETDATA_CPU_VENDOR: This reports the CPU manufacturer. This is needed
  because some systems do not include the manufacturer name in the CPU
  model name.
* NETDATA_CPU_MODEL: This reports the CPU model. It may or may not
  include any of a model number, intended operating frequency, and
  manufacturer name.
* NETDATA_CPU_FREQ: This reports a best guess at the design frequency
  for the CPU. It may instead be the max boost frequency. This is
  reported as a number with associated units, which will usually be
  either hertz or megahertz.
* NETDATA_CPU_DETECTION: This reports the method used to detect the CPU
  information, It will be either 'none' if no detection was successful,
  or a space-separated list of detection methods.

This may potentially use any of the following detection methods:

* lscpu: Uses a mix of information from across the system. Requires the
  `lscpu` command to be installed.
* dmidecode: Uses the information from the DMI tables. Requires hardware
  support as well as the `dmidecode` command.
* nproc: Uses the `nproc` command from the GNU coreutils to get a count
  of logical processors.
* sysctl: Uses the `sysctl` command on FreeBSD to fetch information.
* sysfs: Uses /sys on Linux to fetch information.
* procfs: Uses /proc/cpuinfo on Linux to fetch information.
* uname: Uses the `uname` command from the GNU coreutils to get CPU
  model and vendor information.

All values tht were not successfully detected should read back as
'unknown'. Some values may have spaces present, and thus are quoted in
the output.

* Collect total system RAM info in system-info.sh

This collects info about the total usable system RAM in the system-info.sh
script.

It adds the following two keys to the output of the script:

* NETDATA_TOTAL_RAM: Reports the total usable system RAM as a number
  with an associated unit, usually as bytes or kilobytes. Reports
  'unknown' if this couldn't be determined.
* NETDATA_RAM_DETECTION: Indicates how we detected the total RAM, or
  'none' if we couldn't figure out the total RAM.

* Make lscpu output parsing more robust.

* Remove extra quotes.

The output is not parsed as shell variables, but using a special parser
that just reads everything from the `=` to EOL as the value.

* Coerce output to base units.

This properly converts the output for CPU frequencies and RAM sizes to
use base units of Hertz or bytes, allowing for simpler parsing of the
output.

* Fix incorrect number handling in total RAM parsing.

* Correctly fix incorrect number handling in total RAM parsing.

* Fix parsing of `lscpu` output.

This properly recognizes the CPU frequency value as MHz and truncates
the value to an integer.
This commit is contained in:
Austin S. Hemmelgarn 2020-01-24 10:04:27 -05:00 committed by GitHub
parent d1eafad8b0
commit db265d6f63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 124 additions and 0 deletions

View File

@ -169,6 +169,123 @@ else
fi
fi
# -------------------------------------------------------------------------------------------------
# Detect information about the CPU
LCPU_COUNT="unknown"
CPU_MODEL="unknown"
CPU_VENDOR="unknown"
CPU_FREQ="unknown"
CPU_INFO_SOURCE="none"
possible_cpu_freq=""
nproc="$(command -v nproc)"
lscpu="$(command -v lscpu)"
lscpu_output=""
dmidecode="$(command -v dmidecode)"
dmidecode_output=""
if [ -n "${lscpu}" ] && lscpu >/dev/null 2>&1 ; then
lscpu_output="$(LC_NUMERIC=C ${lscpu} 2>/dev/null)"
CPU_INFO_SOURCE="lscpu"
LCPU_COUNT="$(echo "${lscpu_output}" | grep "^CPU(s):" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
CPU_VENDOR="$(echo "${lscpu_output}" | grep "^Vendor ID:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
CPU_MODEL="$(echo "${lscpu_output}" | grep "^Model name:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
possible_cpu_freq="$(echo "${lscpu_output}" | grep -F "CPU max MHz:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | grep -o '^[0-9]*') MHz"
elif [ -n "${dmidecode}" ] && dmidecode -t processor >/dev/null 2>&1 ; then
dmidecode_output="$(${dmidecode} -t processor 2>/dev/null)"
CPU_INFO_SOURCE="dmidecode"
LCPU_COUNT="$(echo "${dmidecode_output}" | grep -F "Thread Count:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
CPU_VENDOR="$(echo "${dmidecode_output}" | grep -F "Manufacturer:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
CPU_MODEL="$(echo "${dmidecode_output}" | grep -F "Version:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
possible_cpu_freq="$(echo "${dmidecode_output}" | grep -F "Current Speed:" | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
else
if [ -n "${nproc}" ] ; then
CPU_INFO_SOURCE="nproc"
LCPU_COUNT="$(${nproc})"
elif [ "${KERNEL_NAME}" = FreeBSD ] ; then
CPU_INFO_SOURCE="sysctl"
LCPU_COUNT="$(sysctl -n kern.smp.cpus)"
elif [ -d /sys/devices/system/cpu ] ; then
CPU_INFO_SOURCE="sysfs"
# This is potentially more accurate than checking `/proc/cpuinfo`.
LCPU_COUNT="$(find /sys/devices/system/cpu -mindepth 1 -maxdepth 1 -type d -name 'cpu*' | grep -cEv 'idle|freq')"
elif [ -r /proc/cpuinfo ] ; then
CPU_INFO_SOURCE="procfs"
LCPU_COUNT="$(grep -c ^processor /proc/cpuinfo)"
fi
# If we have GNU uname, we can use that to get CPU info (probably).
if unmae --version 2>/dev/null | grep -qF 'GNU coreutils' ; then
CPU_INFO_SOURCE="${CPU_INFO_SOURCE} uname"
CPU_MODEL="$(uname -p)"
CPU_VENDOR="$(uname -i)"
elif [ "${KERNEL_NAME}" = FreeBSD ] ; then
if ( echo "${CPU_INFO_SOURCE}" | grep -qv sysctl ) ; then
CPU_INFO_SOURCE="${CPU_INFO_SOURCE} sysctl"
fi
CPU_MODEL="$(sysctl -n hw.model)"
elif [ -r /proc/cpuinfo ] ; then
if ( echo "${CPU_INFO_SOURCE}" | grep -qv procfs ) ; then
CPU_INFO_SOURCE="${CPU_INFO_SOURCE} procfs"
fi
CPU_MODEL="$(grep -F "model name" /proc/cpuinfo | head -n 1 | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
CPU_VENDOR="$(grep -F "vendor_id" /proc/cpuinfo | head -n 1 | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
fi
fi
if [ -r /sys/devices/system/cpu/cpu0/cpufreq/base_frequency ] ; then
if ( echo "${CPU_INFO_SOURCE}" | grep -qv sysfs ) ; then
CPU_INFO_SOURCE="${CPU_INFO_SOURCE} sysfs"
fi
CPU_FREQ="$(cat /sys/devices/system/cpu/cpu0/cpufreq/base_frequency)"
elif [ -n "${possible_cpu_freq}" ] ; then
CPU_FREQ="${possible_cpu_freq}"
elif [ -r /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq ] ; then
if ( echo "${CPU_INFO_SOURCE}" | grep -qv sysfs ) ; then
CPU_INFO_SOURCE="${CPU_INFO_SOURCE} sysfs"
fi
CPU_FREQ="$(cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq)"
fi
freq_units="$(echo "${CPU_FREQ}" | cut -f 2 -d ' ')"
case "${freq_units}" in
GHz)
value="$(echo "${CPU_FREQ}" | cut -f 1 -d ' ')"
CPU_FREQ="$((value*1000*1000*1000))"
;;
MHz)
value="$(echo "${CPU_FREQ}" | cut -f 1 -d ' ')"
CPU_FREQ="$((value*1000*1000))"
;;
KHz)
value="$(echo "${CPU_FREQ}" | cut -f 1 -d ' ')"
CPU_FREQ="$((value*1000))"
;;
*)
;;
esac
# -------------------------------------------------------------------------------------------------
# Detect the total system RAM
TOTAL_RAM="unknown"
RAM_DETECTION="none"
if [ "${KERNEL_NAME}" = FreeBSD ] ; then
RAM_DETECTION="sysctl"
TOTAL_RAM="$(sysctl -n hw.physmem)"
elif [ -r /proc/meminfo ] ; then
RAM_DETECTION="procfs"
TOTAL_RAM="$(grep -F MemTotal /proc/meminfo | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | cut -f 1 -d ' ')"
TOTAL_RAM="$((TOTAL_RAM*1024))"
fi
echo "NETDATA_CONTAINER_OS_NAME=${CONTAINER_NAME}"
echo "NETDATA_CONTAINER_OS_ID=${CONTAINER_ID}"
@ -189,4 +306,11 @@ echo "NETDATA_SYSTEM_VIRTUALIZATION=${VIRTUALIZATION}"
echo "NETDATA_SYSTEM_VIRT_DETECTION=${VIRT_DETECTION}"
echo "NETDATA_SYSTEM_CONTAINER=${CONTAINER}"
echo "NETDATA_SYSTEM_CONTAINER_DETECTION=${CONT_DETECTION}"
echo "NETDATA_CPU_LOGICAL_CPU_COUNT=${LCPU_COUNT}"
echo "NETDATA_CPU_VENDOR=${CPU_VENDOR}"
echo "NETDATA_CPU_MODEL=${CPU_MODEL}"
echo "NETDATA_CPU_FREQ=${CPU_FREQ}"
echo "NETDATA_CPU_DETECTION=${CPU_INFO_SOURCE}"
echo "NETDATA_TOTAL_RAM=${TOTAL_RAM}"
echo "NETDATA_RAM_DETECTION=${RAM_DETECTION}"