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
<<< Multipart/Mixed; boundary="--BOUNDARY1(Fri_Jul__4_11_23_10_2008_773)--": Unrecognized >>>