Hi, I attached the ready-to-release version of this new tool, and its manpage. It has been tested successfully on various of machines including i686, x86_64, ia64, ppc64 and s390(x). The final output will like the following, $ /usr/bin/lscpu Architecture: x86_64 CPU(s): 8 Thread(s) per core: 1 Core(s) per socket: 4 CPU socket(s): 2 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 15 Stepping: 11 CPU MHz: 1862.010 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 4096K $ /usr/bin/lscpu -p #The following is the parsable format, which can be fed to other #programs. Each different item in every column has a unique ID #starting from zero. # #CPU,Core,Socket,Node,L1d,L1i,L2 0,0,0,0,0,0,0 1,1,0,0,1,1,0 2,2,0,0,2,2,1 3,3,0,0,3,3,1 4,4,1,0,4,4,2 5,5,1,0,5,5,2 6,6,1,0,6,6,3 7,7,1,0,7,7,3 Thanks, CaiQian
.\" Process this file with .\" groff -man -Tascii lscpu.1 .\" .TH LSCPU 1 "JULY 2008" Linux "User Manuals" .SH NAME lscpu \- CPU architecture information helper .SH SYNOPSIS .B lscpu [-hp] .SH DESCRIPTION .B lscpu gathers CPU architecture information like number of CPUs, threads, cores, sockets, NUMA nodes, information about CPU caches, 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. .SH OPTIONS .IP -h, --help Print a help message. .IP -p, --parse Print out in parsable instead of printable format. .SH BUGS The program at the moment does not handle the system installed with different types of physical processors. .SH AUTHOR Cai Qian <qcai@xxxxxxxxxx>
/* 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/>. */ #include <ctype.h> #include <dirent.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/utsname.h> #include <unistd.h> #define CACHE_MAX 100 /* count the set bit in a mapping file */ int sibling (char *file) { int c, n; int result = 0; char s[2]; FILE *fp; fp = fopen (file, "r"); if (fp == NULL) err (1, "fopen %s", file); while ((c = fgetc (fp)) != EOF) { if (isxdigit (c)) { s[0] = c; s[1] = '\0'; for (n = strtol (s, NULL, 16); n > 0; n /= 2) { if (n % 2) result++; } } } fclose (fp); return result; } /* Lookup a pattern and get the value from cpuinfo*/ int lookup (char *line, char *pattern, char **value) { char buf[BUFSIZ], buf2[BUFSIZ]; int i = 0, j = 0; /* empty line */ if (line[0] == '\0') return 0; snprintf (buf2, BUFSIZ, "%s : %%s", pattern); if (sscanf (line, buf2, buf) != 1) return 0; i = strcspn (line, ":"); strncpy (buf, line + i, strlen (line + i) + 1); /* Get the value. */ for (i = 0; isspace (buf[i]) || buf[i] == ':'; i++); for (j = strlen (buf) - 1; isspace (buf[j]); j--); buf[j + 1] = '\0'; *value = strdup (buf + i); if (*value == NULL) err (1, "strdup %s", buf + i); return 1; } void usage (void) { printf ( "Usage: lscpu [OPTION]\n" "CPU architecture information helper\n" "\n" " -h, --help usage information\n" " -p, --parse print out in parsable instead of printable format." "\n"); } int main (int argc, char *argv[]) { int c, i, j; int parsable = 0, have_topology = 0, have_cache = 0, have_node = 0; int cpu = 0, thread = 0, core = 0, socket = 0, node = 0, ncache = 0; int option_index, camap[CACHE_MAX], *nodecpu, pad = 23; char buf[BUFSIZ], buf2[BUFSIZ], buf3[BUFSIZ]; char *syspath = "/sys/devices/system", *cpu0path; char *arch, *vendor = NULL, *family = NULL, *model = NULL; char *mhz = NULL, *stepping = NULL, *flags = NULL; char *(caname[CACHE_MAX]), *(casize[CACHE_MAX]); FILE *fp; DIR *dp; struct dirent *dir; struct utsname utsbuf; struct stat info; struct option global[] = { {"help", no_argument, 0, 'h'}, {"parse", no_argument, 0, 'p'}, {0, 0, 0, 0} }; for (;;) { option_index = 0; c = getopt_long (argc, argv, "hp", global, &option_index); if (c == -1) break; switch (c) { /* --help */ case 'h': usage (); return 0; /* --parse */ case 'p': parsable = 1; break; default: usage (); exit (1); } } if (uname (&utsbuf) == -1) err (1, "uname"); arch = strdup (utsbuf.machine); if (arch == NULL) err (1, "strdup %s", utsbuf.machine); /* Dom0 Kernel gives wrong information. */ fp = fopen ("/proc/xen/capabilities", "r"); if (fp != NULL) { if (fscanf (fp, "%s", buf) == 1) { if (! strcmp (buf, "control_d")) errx (1, "error - Dom0 Kernel is not supported."); } fclose (fp); } /* Read through sysfs. */ if (stat (syspath, &info) == -1) errx (1, "error - sysfs is not accessable."); snprintf (buf, BUFSIZ, "%s/cpu/cpu0", syspath); cpu0path = strdup (buf); if (cpu0path == NULL) err (1, "strdup %s", buf); snprintf (buf, BUFSIZ, "%s/node", syspath); if (stat (buf, &info) == 0) have_node = 1; snprintf (buf, BUFSIZ, "%s/topology/thread_siblings", cpu0path); if (stat (buf, &info) == 0) have_topology = 1; snprintf (buf, BUFSIZ, "%s/cache", cpu0path); if (stat (buf, &info) == 0) have_cache = 1; /* number of CPUs */ for (;;) { snprintf (buf, BUFSIZ, "%s/cpu/cpu%d", syspath, cpu); if (stat (buf, &info) == 0) cpu++; else break; } if (have_topology) { /* number of threads */ snprintf (buf, BUFSIZ, "%s/topology/thread_siblings", cpu0path); thread = sibling (buf); /* number of cores */ snprintf (buf, BUFSIZ, "%s/topology/core_siblings", cpu0path); core = sibling (buf) / thread; /* number of sockets */ socket = cpu / core / thread; } /* Read through cpuinfo. */ fp = fopen ("/proc/cpuinfo", "r"); if (fp == NULL) err (1, "fopen cpuinfo"); while (fgets (buf2, BUFSIZ, fp) != NULL) { /* IA64 */ if (lookup (buf2, "vendor", &vendor)) ; else if (lookup (buf2, "vendor_id", &vendor)) ; /* IA64 */ else if (lookup (buf2, "family", &family)) ; else if (lookup (buf2, "cpu family", &family)) ; else if (lookup (buf2, "model", &model)) ; else if (lookup (buf2, "stepping", &stepping)) ; else if (lookup (buf2, "cpu MHz", &mhz)) ; else if (lookup (buf2, "flags", &flags)) ; else continue; } fclose (fp); /* cache infomation */ if (have_cache) { snprintf (buf, BUFSIZ, "%s/cache", cpu0path); dp = opendir (buf); if (dp == NULL) err (1, "opendir %s", buf); while ((dir = readdir (dp)) != NULL) { if (! strcmp (dir->d_name, ".") || ! strcmp (dir->d_name, "..")) continue; /* cache level */ snprintf (buf2, BUFSIZ, "%s/cache/%s/level", cpu0path, dir->d_name); fp = fopen (buf2, "r"); if (fp == NULL) err (1, "fopen %s", buf2); fscanf (fp, "%s", buf2); fclose (fp); /* cache type */ snprintf (buf3, BUFSIZ, "%s/cache/%s/type", cpu0path, dir->d_name); fp = fopen (buf3, "r"); if (fp == NULL) err (1, "fopen %s", buf3); fscanf (fp, "%s", buf3); fclose (fp); if (! strcmp (buf3, "Data")) { snprintf (buf, BUFSIZ, "L%sd", buf2); caname[ncache] = strdup (buf); if (caname[ncache] == NULL) err (1, "strdup %s", buf); } else if (! strcmp (buf3, "Instruction")) { snprintf (buf, BUFSIZ, "L%si", buf2); caname[ncache] = strdup (buf); if (caname[ncache] == NULL) err (1, "strdup %s", buf); } else { snprintf (buf, BUFSIZ, "L%s", buf2); caname[ncache] = strdup (buf); if (caname[ncache] == NULL) err (1, "strdup %s", buf); } /* cache size */ snprintf (buf, BUFSIZ, "%s/cache/%s/size", cpu0path, dir->d_name); fp = fopen (buf, "r"); if (fp == NULL) err (1, "fopen %s", buf); fscanf (fp, "%s", buf); casize[ncache] = strdup (buf); if (casize[ncache] == NULL) err (1, "strdup %s", buf); fclose (fp); /* information about how CPUs share different caches */ snprintf (buf, BUFSIZ, "%s/cache/%s/shared_cpu_map", cpu0path, dir->d_name); camap[ncache] = sibling (buf); ncache++; } } if (have_node) { /* number of NUMA node */ for (;;) { snprintf (buf, BUFSIZ, "%s/node/node%d", syspath, node); if (stat (buf, &info) == 0) node++; else break; } nodecpu = (int *) malloc (node * sizeof (int)); if (nodecpu == NULL) err (1, "malloc nodecpu"); /* information about how nodes share different CPUs */ for (i = 0; i < node; i++) { snprintf (buf, BUFSIZ, "%s/node/node%d/cpumap", syspath, i); nodecpu[i] = sibling (buf); } } /* Show time! */ if (parsable) { printf ( "#The following is the parsable format, which can be " "fed to other\n#programs. Each different item in " "every column has a unique ID\n#starting from zero.\n" "#\n" "#CPU,Core,Socket,Node"); if (have_cache) { for (i = ncache - 1; i >= 0; i--) printf (",%s", caname[i]); } putchar ('\n'); for (i = 0; i < cpu; i++) { printf ("%d", i); if (have_topology) printf (",%d,%d", (int) (i / thread), (int) (i / core / thread)); else printf (",,"); if (have_node) { c = 0; for (j = 0; j < node; j++) { c += nodecpu[j]; if (i < c) { printf (",%d", j); break; } } } else putchar (','); if (have_cache) { for (j = ncache - 1; j >= 0; j--) { /* If shared_cpu_map is 0, all CPUs share the same cache. */ if (camap[j] == 0) camap[j] = core * thread; printf (",%d", (int) (i / camap[j])); } } putchar ('\n'); } } else { printf ("%-*s%s\n", pad, "Architecture:", arch); printf ("%-*s%d\n", pad, "CPU(s):", cpu); if (have_topology) { printf ("%-*s%d\n", pad, "Thread(s) per core:", thread); printf ("%-*s%d\n", pad, "Core(s) per socket:", core); printf ("%-*s%d\n", pad, "CPU socket(s):", socket); } if (have_node) printf ("%-*s%d\n", pad, "NUMA node(s):", node); if (vendor != NULL) printf ("%-*s%s\n", pad, "Vendor ID:", vendor); if (family != NULL) printf ("%-*s%s\n", pad, "CPU family:", family); if (model != NULL) printf ("%-*s%s\n", pad, "Model:", model); if (stepping != NULL) printf ("%-*s%s\n", pad, "Stepping:", stepping); if (mhz != NULL) printf ("%-*s%s\n", pad, "CPU MHz:", mhz); if (flags != NULL) { snprintf (buf, BUFSIZ, " %s ", flags); if (strstr (buf, " svm ")) printf ("%-*s%s\n", pad, "Virtualization:", "AMD-V"); else if (strstr (buf, " vmx ")) printf ("%-*s%s\n", pad, "Virtualization:", "VT-x"); } if (have_cache) { for (i = ncache - 1; i >= 0; i--) { snprintf (buf, BUFSIZ, "%s cache:", caname[i]); printf ("%-*s%s\n", pad, buf, casize[i]); } } } return 0; }