[RFC] lscpu - CPU architecture information helper | |
| [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] | |
Hi, I propose a new tool lscpu to util-linux-ng, This program gathers CPU architecture information like number of CPUs, cores, sockets, NUMA nodes, information about CPU caches, SMT, CPU family, model and stepping from sysfs and /proc/cpuinfo, and prints it in human-readable format. Alternatively, it can print out in parsable format including how different caches are shared by different CPUs, which can also be fed to other programs. The output is like the following, $ /usr/bin/lscpu Processor(s): 2 CPU core(s): 2 CPU(s): 8 Vendor ID: GenuineIntel CPU family: Itanium 2 Model: 0 CPU MHz: 1598.000005 L1d cache: 16K L1i cache: 16K L2d cache: 256K L2i cache: 1024K L3 cache: 12288K SMT: Yes NUMA node(s): 1 $ /usr/bin/lscpu -p #The following is the parsable format, which can be fed to other #programs. The decimal numbers in the first column are CPU IDs #calculated from the bitmaps for each CPUs. Each CPU has one bit set, so #the first CPU's ID is 2^0, the second's is 2^1, and so on. The rest of #numbers are the sum of CPU IDs to indicate CPU and cache arrangement. #For example, if Core has both the first and the second CPU bit set (2^0 #+ 2^1), it means those two CPUs reside in the same CPU Core, i.e. #simultaneous multithreading (SMT). The same for caches, if one cache #has several CPUs' bits set, it means they share the same cache. # #CPU,Core,Socket,L1d,L1i,L2d,L2i,L3 1,3,15,3,3,3,15,15 2,3,15,3,3,3,15,15 4,12,15,12,12,12,15,15 8,12,15,12,12,12,15,15 16,48,240,48,48,48,240,240 32,48,240,48,48,48,240,240 64,192,240,192,192,192,240,240 128,192,240,192,192,192,240,240 Therefore, cache arrangement is like the following, _______________________________________________________________ | | | | | | | | | | cpu0 | | | | | | | | |______| core0 | | L1d | L1i | L2d | | | | | | | 16K | 16K | 256K | | | | cpu1 | | | | | | | | |______|_______| processor0 |_____|_____|______| L2i | L3 | | | | | | | | 1024K | 12288K | | cpu2 | | | | | | | | |______| core1 | | L1d | L1i | L2d | | | | | | | 16K | 16K | 256K | | | | cpu3 | | | | | | | | |______|_______|____________|_____|_____|______|_______|________| | | | | | | | | | | cpu4 | | | | | | | | |______| core2 | | L1d | L1i | L2d | | | | | | | 16K | 16K | 256K | | | | cpu5 | | | | | | | | |______|_______| processor1 |_____|_____|______| L2i | L3 | | | | | | | | 1024K | 12288K | | cpu6 | | | | | | | | |______| core3 | | L1d | L1i | L2d | | | | | | | 16K | 16K | 256K | | | | cpu7 | | | | | | | | |______|_______|____________|_____|_____|______|_______|________| The program has been tested successfully on around 40 different i386, x86_64 and ia64 machines. You could find the program in attachment. Thanks, CaiQian
#!/bin/bash
# lscpu - CPU architecture information helper
# Copyright (C) 2008 Cai Qian <qcai@xxxxxxxxxx>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
log()
{
local x=$1 n=2 l=-1
if [ "$2" != "" ]; then
n=${x}
x=$2
fi
while((x)); do
let l+=1 x/=n
done
echo ${l}
}
# Calculate on number of silbings from a hexadecimal mapping.
sibling()
{
local x=$1 l=0 n=0
while [ "${x}" -ne 0 ]; do
l=$((l + 1))
n=$(log 2 "${x}")
x=$((x - 2**n))
done
echo ${l}
}
# Calculate on decimal number (2^0 + 2^1 + 2^2 ...) from number of
# silbings.
decimal()
{
local i=$1 j=$2
m=${j}
k=$((i / j + 1))
sum=0
while [ "${j}" -ne 0 ]; do
sum=$((sum + base**(m * k - j)))
j=$((j - 1))
done
echo "${sum}"
}
usage()
{
cat <<EOF
Usage: $0 [OPTION]
CPU architecture information helper
-p, --parse print out in parsable instead of printable format.
-h, --help usage information
EOF
}
#=============
# Main program
#=============
# Command-line parsing
while [ $# -gt 0 ]; do
case "$1" in
-p | --parse)
parse=1
;;
-h | --help)
usage
exit 0
;;
*)
echo "Error: unknown option: $1" >&2
usage
exit 1
;;
esac
shift
done
arch=$(uname -m)
# Only i686, X86_64 and IA64 are supported at the moment.
if [ "${arch}" != "x86_64" ] && [ "${arch}" != "i686" ] \
&& [ "${arch}" != "ia64" ]; then
echo "Error: ${arch} is not supported." >&2
exit 1
fi
# Dom0 Kernel gives wrong information.
if grep "control_d" "/proc/xen/capabilities" >/dev/null 2>&1; then
echo "Error: Dom0 Kernel is not supported." >&2
exit 1
fi
# Read through sysfs.
syspath="/sys/devices/system"
if [ ! -d "${syspath}" ]; then
echo "Error: sysfs is not accessable." >&2
exit 1
fi
if [ -d "${syspath}/cpu/cpu0/topology" ]; then
have_topology=1
fi
if [ -d "${syspath}/cpu/cpu0/cache" ]; then
have_cache=1
fi
# Number of CPUs
cpu=$(find "${syspath}/cpu" -name 'cpu[0-9]*' -prune | wc -l)
if [ "${have_topology}" ]; then
# Number of threads
hex=$(sed 's/^[0,]*//' \
"${syspath}/cpu/cpu0/topology/thread_siblings")
map=$(printf "%d\n" "0x${hex}")
thread=$(sibling "${map}")
if [ ${thread} -ne 1 ]; then
smt="Yes"
else
smt="No"
fi
# Number of cores
hex=$(sed 's/^[0,]*//' \
"${syspath}/cpu/cpu0/topology/core_siblings")
map=$(printf "%d\n" "0x${hex}")
core=$(( $(sibling "${map}") / thread))
# Number of CPU sockets
socket=$((cpu / core / thread))
fi
# Read through cpuinfo.
vendor=$(grep -m 1 "vendor" /proc/cpuinfo | sed 's/.*: \(.*\)/\1/')
family=$(grep -m 1 "family" /proc/cpuinfo | sed 's/.*: \(.*\)/\1/')
model=$(grep -m 1 "model.[^n]" /proc/cpuinfo | sed 's/.*: \(.*\)/\1/')
stepping=$(grep -m 1 "stepping" /proc/cpuinfo | sed 's/.*: \(.*\)/\1/')
mhz=$(grep -m 1 "cpu MHz" /proc/cpuinfo | sed 's/.*: \(.*\)/\1/')
# Cache information
if [ "${have_cache}" ]; then
ncache=0
for i in $(ls "${syspath}/cpu/cpu0/cache"); do
ncache=$((ncache + 1))
level=$(cat "${syspath}/cpu/cpu0/cache/${i}/level")
type=$(cat "${syspath}/cpu/cpu0/cache/${i}/type")
if [ "${type}" = "Data" ]; then
caname[${ncache}]="L${level}d"
elif [ "${type}" = "Instruction" ]; then
caname[${ncache}]="L${level}i"
else
caname[${ncache}]="L${level}"
fi
camap[${ncache}]=$(sed 's/^[0,]*//' \
"${syspath}/cpu/cpu0/cache/${i}/shared_cpu_map")
casize[${ncache}]=$(cat "${syspath}/cpu/cpu0/cache/${i}/size")
done
fi
# Number of NUMA node
if [ -d "${syspath}/node" ]; then
numa=$(find "${syspath}/node" -name 'node[0-9]*' -prune | wc -l)
else
numa=1
fi
# Show time.
if [ "${parse}" ]; then
# Parsable format
if [ ! "${have_topology}" ]; then
echo "Error: CPU topology information is unavailable." >&2
exit 1
fi
cat <<EOF
#The following is the parsable format, which can be fed to other
#programs. The decimal numbers in the first column are CPU IDs
#calculated from the bitmaps for each CPUs. Each CPU has one bit set, so
#the first CPU's ID is 2^0, the second's is 2^1, and so on. The rest of
#numbers are the sum of CPU IDs to indicate CPU and cache arrangement.
#For example, if Core has both the first and the second CPU bit set (2^0
#+ 2^1), it means those two CPUs reside in the same CPU Core, i.e.
#simultaneous multithreading (SMT). The same for caches, if one cache
#has several CPUs' bits set, it means they share the same cache.
EOF
# Show comments.
echo "#"
echo -n "#CPU,Core,Socket"
if [ "${have_cache}" ]; then
m=0
while [ "${m}" -ne "${ncache}" ]; do
m=$((m + 1))
echo -n ",${caname[${m}]}"
done
fi
echo
base=2
for i in $(seq 0 "$((cpu - 1))"); do
pcpu[${i}]=$((base**i))
pcore[${i}]=$(decimal "${i}" "${thread}")
psock[${i}]=$(decimal "${i}" "$((core * thread))")
printf "%d,%d,%d" "${pcpu[${i}]}" "${pcore[${i}]}" \
"${psock[${i}]}"
# Cache information
if [ "${have_cache}" ]; then
m=0
while [ "${m}" -ne "${ncache}" ]; do
m=$((m + 1))
# If shared_cpu_map is 0, all CPUs share the same cache.
if [ "${camap[${m}]}" ]; then
map=$(printf "%d\n" "0x${camap[${m}]}")
j=$(sibling "${map}")
else
j=$((core * thread))
fi
pcache=$(decimal "${i}" "${j}")
printf ",%d" "${pcache}"
done
fi
echo
done
else
# Printable format
pad=17
if [ "${have_topology}" ]; then
printf "%-${pad}s%s\n" "Processor(s):" "${socket}"
printf "%-${pad}s%s\n" "CPU core(s):" "${core}"
fi
printf "%-${pad}s%s\n" "CPU(s):" "${cpu}"
printf "%-${pad}s%s\n" "Vendor ID:" "${vendor}"
printf "%-${pad}s%s\n" "CPU family:" "${family}"
if [ "${model}" ]; then
printf "%-${pad}s%s\n" "Model:" "${model}"
fi
if [ "${stepping}" ]; then
printf "%-${pad}s%s\n" "Stepping:" "${stepping}"
fi
printf "%-${pad}s%s\n" "CPU MHz:" "${mhz}"
if [ "${have_cache}" ]; then
i=0
while [ "${i}" -ne "${ncache}" ]; do
i=$((i + 1))
printf "%-${pad}s%s\n" "${caname[${i}]} cache:" "${casize[${i}]}"
done
fi
if [ "${have_topology}" ]; then
printf "%-${pad}s%s\n" "SMT:" "${smt}"
fi
printf "%-${pad}s%s\n" "NUMA node(s):" "${numa}"
fi
exit 0
[Site Home] [Netdev] [Ethernet Bridging] [Linux Wireless] [Kernel Newbies] [Memory] [Security] [Linux for Hams] [Netfilter] [Bugtraq] [Rubini] [Photo] [Yosemite] [Yosemite News] [MIPS Linux] [ARM Linux] [Linux RAID] [Linux Admin] [Samba] [Video 4 Linux] [Linux Resources]