diff options
Diffstat (limited to 'sys-utils/lscpu.c')
-rw-r--r-- | sys-utils/lscpu.c | 683 |
1 files changed, 410 insertions, 273 deletions
diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 77a3e5c2..74f5e781 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -31,28 +31,18 @@ #include <unistd.h> #include <stdarg.h> +#include "cpuset.h" #include "nls.h" #define CACHE_MAX 100 /* /sys paths */ -#define _PATH_SYS_SYSTEM "sys/devices/system" -#define _PATH_SYS_CPU0 _PATH_SYS_SYSTEM "/cpu/cpu0" -#define _PATH_PROC_XEN "proc/xen" +#define _PATH_SYS_SYSTEM "/sys/devices/system" +#define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu" +#define _PATH_PROC_XEN "/proc/xen" #define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities" -#define _PATH_PROC_CPUINFO "proc/cpuinfo" -#define _PATH_PROC_PCIDEVS "proc/bus/pci/devices" - -int have_topology; -int have_cache; -int have_node; - -/* cache(s) description */ -struct ca_desc { - char *caname; - char *casize; - int camap; -}; +#define _PATH_PROC_CPUINFO "/proc/cpuinfo" +#define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices" /* virtualization types */ enum { @@ -87,17 +77,17 @@ enum { MODE_LONG = (1 << 3) }; -/* CPU(s) description */ -struct cpu_desc { - /* counters */ - int ct_cpu; - int ct_thread; - int ct_core; - int ct_socket; - int ct_node; - int ct_cache; - - /* who is who */ +/* cache(s) description */ +struct cpu_cache { + char *name; + char *size; + + int nsharedmaps; + cpu_set_t **sharedmaps; +}; + +/* global description */ +struct lscpu_desc { char *arch; char *vendor; char *family; @@ -105,78 +95,137 @@ struct cpu_desc { char *virtflag; /* virtualization flag (vmx, svm) */ int hyper; /* hypervisor vendor ID */ int virtype; /* VIRT_PARA|FULL|NONE ? */ - - /* caches */ - struct ca_desc cache[CACHE_MAX]; - - /* misc */ char *mhz; char *stepping; char *flags; - int mode; /* rm, lm or/and tm */ - /* NUMA */ - int *nodecpu; + int ncpus; /* number of CPUs */ + + int nnodes; /* number of NUMA modes */ + cpu_set_t **nodemaps; /* array with NUMA nodes */ + + /* sockets -- based on core_siblings (internal kernel map of cpuX's + * hardware threads within the same physical_package_id (socket)) */ + int nsockets; /* number of all sockets */ + cpu_set_t **socketmaps; /* unique core_siblings */ + + /* cores -- based on thread_siblings (internel kernel map of cpuX's + * hardware threads within the same core as cpuX) */ + int ncores; /* number of all cores */ + cpu_set_t **coremaps; /* unique thread_siblings */ + + int nthreads; /* number of threads */ + + int ncaches; + struct cpu_cache *caches; }; -char pathbuf[PATH_MAX] = "/"; +static size_t sysrootlen; +static char pathbuf[PATH_MAX]; +static int maxcpus; /* size in bits of kernel cpu mask */ -static void path_scanstr(char *result, const char *path, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +static FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +static void path_getstr(char *result, size_t len, const char *path, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +static int path_getnum(const char *path, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); static int path_exist(const char *path, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -static int path_sibling(const char *path, ...) +static cpu_set_t *path_cpuset(const char *path, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +static const char * +path_vcreate(const char *path, va_list ap) +{ + if (sysrootlen) + vsnprintf(pathbuf + sysrootlen, + sizeof(pathbuf) - sysrootlen, path, ap); + else + vsnprintf(pathbuf, sizeof(pathbuf), path, ap); + return pathbuf; +} + static FILE * -xfopen(const char *path, const char *mode) +path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap) { - FILE *fd = fopen(path, mode); - if (!fd) - err(EXIT_FAILURE, _("error: %s"), path); - return fd; + FILE *f; + const char *p = path_vcreate(path, ap); + + f = fopen(p, mode); + if (!f && exit_on_error) + err(EXIT_FAILURE, _("error: cannot open %s"), p); + return f; } static FILE * -path_vfopen(const char *mode, const char *path, va_list ap) +path_fopen(const char *mode, int exit_on_error, const char *path, ...) { - vsnprintf(pathbuf, sizeof(pathbuf), path, ap); - return xfopen(pathbuf, mode); + FILE *fd; + va_list ap; + + va_start(ap, path); + fd = path_vfopen("r", exit_on_error, path, ap); + va_end(ap); + + return fd; } static void -path_scanstr(char *result, const char *path, ...) +path_getstr(char *result, size_t len, const char *path, ...) { FILE *fd; va_list ap; va_start(ap, path); - fd = path_vfopen("r", path, ap); + fd = path_vfopen("r", 1, path, ap); va_end(ap); - if (fscanf(fd, "%s", result) != 1) { + if (!fgets(result, len, fd)) + err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); + fclose(fd); + + len = strlen(result); + if (result[len - 1] == '\n') + result[len - 1] = '\0'; +} + +static int +path_getnum(const char *path, ...) +{ + FILE *fd; + va_list ap; + int result; + + va_start(ap, path); + fd = path_vfopen("r", 1, path, ap); + va_end(ap); + + if (fscanf(fd, "%d", &result) != 1) { if (ferror(fd)) - err(EXIT_FAILURE, _("error: %s"), pathbuf); + err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); else - errx(EXIT_FAILURE, _("error parse: %s"), pathbuf); + errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); } fclose(fd); + return result; } static int path_exist(const char *path, ...) { va_list ap; + const char *p; va_start(ap, path); - vsnprintf(pathbuf, sizeof(pathbuf), path, ap); + p = path_vcreate(path, ap); va_end(ap); - return access(pathbuf, F_OK) == 0; + return access(p, F_OK) == 0; } -char * +static char * xstrdup(const char *str) { char *s = strdup(str); @@ -185,33 +234,35 @@ xstrdup(const char *str) return s; } -/* count the set bit in a mapping file */ -static int -path_sibling(const char *path, ...) +static cpu_set_t * +path_cpuset(const char *path, ...) { - int c, n; - int result = 0; - char s[2]; - FILE *fp; + FILE *fd; va_list ap; + cpu_set_t *set; + size_t setsize, len = maxcpus * 7; + char buf[len]; va_start(ap, path); - fp = path_vfopen("r", path, ap); + fd = path_vfopen("r", 1, path, ap); va_end(ap); - 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); + if (!fgets(buf, len, fd)) + err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); + fclose(fd); - return result; + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + set = cpuset_alloc(maxcpus, &setsize, NULL); + if (!set) + err(EXIT_FAILURE, _("failed to callocate cpu set")); + + if (cpumask_parse(buf, set, setsize)) + errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf); + + return set; } /* Lookup a pattern and get the value from cpuinfo. @@ -256,53 +307,64 @@ int lookup(char *line, char *pattern, char **value) } static void -read_basicinfo(struct cpu_desc *cpu) +read_basicinfo(struct lscpu_desc *desc) { - FILE *fp = xfopen(_PATH_PROC_CPUINFO, "r"); + FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO); char buf[BUFSIZ]; struct utsname utsbuf; /* architecture */ if (uname(&utsbuf) == -1) err(EXIT_FAILURE, _("error: uname failed")); - cpu->arch = xstrdup(utsbuf.machine); + desc->arch = xstrdup(utsbuf.machine); /* count CPU(s) */ - while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", cpu->ct_cpu)) - cpu->ct_cpu++; + while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", desc->ncpus)) + desc->ncpus++; /* details */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* IA64 */ - if (lookup(buf, "vendor", &cpu->vendor)) ; - else if (lookup(buf, "vendor_id", &cpu->vendor)) ; + if (lookup(buf, "vendor", &desc->vendor)) ; + else if (lookup(buf, "vendor_id", &desc->vendor)) ; /* IA64 */ - else if (lookup(buf, "family", &cpu->family)) ; - else if (lookup(buf, "cpu family", &cpu->family)) ; - else if (lookup(buf, "model", &cpu->model)) ; - else if (lookup(buf, "stepping", &cpu->stepping)) ; - else if (lookup(buf, "cpu MHz", &cpu->mhz)) ; - else if (lookup(buf, "flags", &cpu->flags)) ; + else if (lookup(buf, "family", &desc->family)) ; + else if (lookup(buf, "cpu family", &desc->family)) ; + else if (lookup(buf, "model", &desc->model)) ; + else if (lookup(buf, "stepping", &desc->stepping)) ; + else if (lookup(buf, "cpu MHz", &desc->mhz)) ; + else if (lookup(buf, "flags", &desc->flags)) ; else continue; } - if (cpu->flags) { - snprintf(buf, sizeof(buf), " %s ", cpu->flags); + if (desc->flags) { + snprintf(buf, sizeof(buf), " %s ", desc->flags); if (strstr(buf, " svm ")) - cpu->virtflag = strdup("svm"); + desc->virtflag = strdup("svm"); else if (strstr(buf, " vmx ")) - cpu->virtflag = strdup("vmx"); + desc->virtflag = strdup("vmx"); if (strstr(buf, " rm ")) - cpu->mode |= MODE_REAL; + desc->mode |= MODE_REAL; if (strstr(buf, " tm ")) - cpu->mode |= MODE_TRANSPARENT; + desc->mode |= MODE_TRANSPARENT; if (strstr(buf, " lm ")) - cpu->mode |= MODE_LONG; + desc->mode |= MODE_LONG; } fclose(fp); + + if (path_exist(_PATH_SYS_SYSTEM "/cpu/kernel_max")) + maxcpus = path_getnum(_PATH_SYS_SYSTEM "/cpu/kernel_max"); + + else if (!sysrootlen) + /* the root is '/' so we are working with data from the current kernel */ + maxcpus = get_max_number_of_cpus(); + else + /* we are reading some /sys snapshot instead of the real /sys, + * let's use any crazy number... */ + maxcpus = desc->ncpus > 2048 ? desc->ncpus : 2048; } static int @@ -312,7 +374,7 @@ has_pci_device(int vendor, int device) int num, fn, ven, dev; int res = 1; - f = fopen(_PATH_PROC_PCIDEVS, "r"); + f = path_fopen("r", 0, _PATH_PROC_PCIDEVS); if (!f) return 0; @@ -364,7 +426,7 @@ cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, } static void -read_hypervisor_cpuid(struct cpu_desc *cpu) +read_hypervisor_cpuid(struct lscpu_desc *desc) { unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0; char hyper_vendor_id[13]; @@ -381,32 +443,32 @@ read_hypervisor_cpuid(struct cpu_desc *cpu) return; if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12)) - cpu->hyper = HYPER_XEN; + desc->hyper = HYPER_XEN; else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9)) - cpu->hyper = HYPER_KVM; + desc->hyper = HYPER_KVM; else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12)) - cpu->hyper = HYPER_MSHV; + desc->hyper = HYPER_MSHV; } #else /* ! __x86_64__ */ static void -read_hypervisor_cpuid(struct cpu_desc *cpu) +read_hypervisor_cpuid(struct lscpu_desc *desc) { } #endif static void -read_hypervisor(struct cpu_desc *cpu) +read_hypervisor(struct lscpu_desc *desc) { - read_hypervisor_cpuid(cpu); + read_hypervisor_cpuid(desc); - if (cpu->hyper) + if (desc->hyper) /* hvm */ - cpu->virtype = VIRT_FULL; + desc->virtype = VIRT_FULL; - else if (!access(_PATH_PROC_XEN, F_OK)) { + else if (path_exist(_PATH_PROC_XEN)) { /* Xen para-virt or dom0 */ - FILE *fd = fopen(_PATH_PROC_XENCAP, "r"); + FILE *fd = path_fopen("r", 0, _PATH_PROC_XENCAP); int dom0 = 0; if (fd) { @@ -417,123 +479,179 @@ read_hypervisor(struct cpu_desc *cpu) dom0 = 1; fclose(fd); } - cpu->virtype = dom0 ? VIRT_NONE : VIRT_PARA; - cpu->hyper = HYPER_XEN; + desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA; + desc->hyper = HYPER_XEN; } else if (has_pci_device(0x5853, 0x0001)) { /* Xen full-virt on non-x86_64 */ - cpu->hyper = HYPER_XEN; - cpu->virtype = VIRT_FULL; + desc->hyper = HYPER_XEN; + desc->virtype = VIRT_FULL; } } -static void -read_topology(struct cpu_desc *cpu) +/* add @set to the @ary, unnecesary set is deallocated. */ +static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set) { - /* number of threads */ - cpu->ct_thread = path_sibling( - _PATH_SYS_CPU0 "/topology/thread_siblings"); + int i; + size_t setsize = CPU_ALLOC_SIZE(maxcpus); - /* number of cores */ - cpu->ct_core = path_sibling( - _PATH_SYS_CPU0 "/topology/core_siblings") - / cpu->ct_thread; + if (!ary) + return -1; - /* number of sockets */ - cpu->ct_socket = cpu->ct_cpu / cpu->ct_core / cpu->ct_thread; + for (i = 0; i < *items; i++) { + if (CPU_EQUAL_S(setsize, set, ary[i])) + break; + } + if (i == *items) { + ary[*items] = set; + ++*items; + return 0; + } + CPU_FREE(set); + return 1; } static void -read_cache(struct cpu_desc *cpu) +read_topology(struct lscpu_desc *desc, int num) { - char buf[256]; - DIR *dp; - struct dirent *dir; - int level, type; + cpu_set_t *thread_siblings, *core_siblings; - dp = opendir(_PATH_SYS_CPU0 "/cache"); - if (dp == NULL) - err(EXIT_FAILURE, _("error: %s"), _PATH_SYS_CPU0 "/cache"); + if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num)) + return; - while ((dir = readdir(dp)) != NULL) { - if (!strcmp(dir->d_name, ".") - || !strcmp(dir->d_name, "..")) - continue; + thread_siblings = path_cpuset(_PATH_SYS_CPU + "/cpu%d/topology/thread_siblings", num); + core_siblings = path_cpuset(_PATH_SYS_CPU + "/cpu%d/topology/core_siblings", num); + if (num == 0) { + int ncores, nsockets, nthreads; + size_t setsize = CPU_ALLOC_SIZE(maxcpus); + + /* threads within one core */ + nthreads = CPU_COUNT_S(setsize, thread_siblings); + /* cores within one socket */ + ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads; + /* number of sockets */ + nsockets = desc->ncpus / nthreads / ncores; + /* all threads */ + desc->nthreads = nsockets * ncores * nthreads; + + desc->socketmaps = calloc(nsockets, sizeof(cpu_set_t *)); + if (!desc->socketmaps) + err(EXIT_FAILURE, _("error: calloc failed")); + desc->coremaps = calloc(ncores * nsockets, sizeof(cpu_set_t *)); + if (!desc->coremaps) + err(EXIT_FAILURE, _("error: calloc failed")); + } - /* cache type */ - path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/type", dir->d_name); - if (!strcmp(buf, "Data")) - type = 'd'; - else if (!strcmp(buf, "Instruction")) - type = 'i'; - else - type = 0; + add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings); + add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings); +} - /* cache level */ - path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/level", dir->d_name); - level = atoi(buf); +static int +cachecmp(const void *a, const void *b) +{ + struct cpu_cache *c1 = (struct cpu_cache *) a; + struct cpu_cache *c2 = (struct cpu_cache *) b; - if (type) - snprintf(buf, sizeof(buf), "L%d%c", level, type); - else - snprintf(buf, sizeof(buf), "L%d", level); + return strcmp(c2->name, c1->name); +} + +static void +read_cache(struct lscpu_desc *desc, int num) +{ + char buf[256]; + int i; - cpu->cache[cpu->ct_cache].caname = xstrdup(buf); + if (num == 0) { + while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d", + num, desc->ncaches)) + desc->ncaches++; - /* cache size */ - path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/size", dir->d_name); - cpu->cache[cpu->ct_cache].casize = xstrdup(buf); + if (!desc->ncaches) + return; + + desc->caches = calloc(desc->ncaches, sizeof(*desc->caches)); + if (!desc->caches) + err(EXIT_FAILURE, _("calloc failed")); + } + for (i = 0; i < desc->ncaches; i++) { + struct cpu_cache *ca = &desc->caches[i]; + cpu_set_t *map; + + if (!ca->name) { + int type, level; + + /* cache type */ + path_getstr(buf, sizeof(buf), + _PATH_SYS_CPU "/cpu%d/cache/index%d/type", + num, i); + if (!strcmp(buf, "Data")) + type = 'd'; + else if (!strcmp(buf, "Instruction")) + type = 'i'; + else + type = 0; + + /* cache level */ + level = path_getnum(_PATH_SYS_CPU "/cpu%d/cache/index%d/level", + num, i); + if (type) + snprintf(buf, sizeof(buf), "L%d%c", level, type); + else + snprintf(buf, sizeof(buf), "L%d", level); + + ca->name = xstrdup(buf); + + /* cache size */ + path_getstr(buf, sizeof(buf), + _PATH_SYS_CPU "/cpu%d/cache/index%d/size", + num, i); + ca->size = xstrdup(buf); + } /* information about how CPUs share different caches */ - cpu->cache[cpu->ct_cache].camap = path_sibling( - _PATH_SYS_CPU0 "/cache/%s/shared_cpu_map", - dir->d_name); - cpu->ct_cache++; + map = path_cpuset(_PATH_SYS_CPU "/cpu%d/cache/index%d/shared_cpu_map", + num, i); + + if (!ca->sharedmaps) { + ca->sharedmaps = calloc(desc->ncpus, sizeof(cpu_set_t *)); + if (!ca->sharedmaps) + err(EXIT_FAILURE, _("error: calloc failed")); + } + + add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map); } } static void -read_nodes(struct cpu_desc *cpu) +read_nodes(struct lscpu_desc *desc) { int i; /* number of NUMA node */ - while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", cpu->ct_node)) - cpu->ct_node++; + while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", desc->nnodes)) + desc->nnodes++; + + if (!desc->nnodes) + return; - cpu->nodecpu = (int *) malloc(cpu->ct_node * sizeof(int)); - if (!cpu->nodecpu) - err(EXIT_FAILURE, _("error: malloc failed")); + desc->nodemaps = calloc(desc->nnodes, sizeof(cpu_set_t *)); + if (!desc->nodemaps) + err(EXIT_FAILURE, _("error: calloc failed")); /* information about how nodes share different CPUs */ - for (i = 0; i < cpu->ct_node; i++) - cpu->nodecpu[i] = path_sibling( + for (i = 0; i < desc->nnodes; i++) + desc->nodemaps[i] = path_cpuset( _PATH_SYS_SYSTEM "/node/node%d/cpumap", i); } static void -check_system(void) -{ - /* Read through sysfs. */ - if (access(_PATH_SYS_SYSTEM, F_OK)) - errx(EXIT_FAILURE, - _("error: /sys filesystem is not accessable.")); - - if (!access(_PATH_SYS_SYSTEM "/node", F_OK)) - have_node = 1; - - if (!access(_PATH_SYS_CPU0 "/topology/thread_siblings", F_OK)) - have_topology = 1; - - if (!access(_PATH_SYS_CPU0 "/cache", F_OK)) - have_cache = 1; -} - -static void -print_parsable(struct cpu_desc *cpu) +print_parsable(struct lscpu_desc *desc) { int i, j; + size_t setsize = CPU_ALLOC_SIZE(maxcpus); printf(_( "# The following is the parsable format, which can be fed to other\n" @@ -541,50 +659,66 @@ print_parsable(struct cpu_desc *cpu) "# starting from zero.\n" "# CPU,Core,Socket,Node")); - if (have_cache) { + if (desc->ncaches) { /* separator between CPU topology and cache information */ putchar(','); - for (i = cpu->ct_cache - 1; i >= 0; i--) - printf(",%s", cpu->cache[i].caname); + for (i = desc->ncaches - 1; i >= 0; i--) + printf(",%s", desc->caches[i].name); } putchar('\n'); - for (i = 0; i < cpu->ct_cpu; i++) { + for (i = 0; i < desc->ncpus; i++) { + + /* #CPU */ printf("%d", i); - if (have_topology) - printf(",%d,%d", - i / cpu->ct_thread, - i / cpu->ct_core / cpu->ct_thread); - else - printf(",,"); + /* Core */ + for (j = 0; j < desc->ncores; j++) { + if (CPU_ISSET_S(i, setsize, desc->coremaps[j])) { + printf(",%d", j); + break; + } + } + if (j == desc->ncores) + putchar(','); - if (have_node) { - int c = 0; + /* Socket */ + for (j = 0; j < desc->nsockets; j++) { + if (CPU_ISSET_S(i, setsize, desc->socketmaps[j])) { + printf(",%d", j); + break; + } + } + if (j == desc->nsockets) + putchar(','); - for (j = 0; j < cpu->ct_node; j++) { - c += cpu->nodecpu[j]; - if (i < c) { - printf(",%d", j); - break; - } + /* Nodes */ + for (j = 0; j < desc->nnodes; j++) { + if (CPU_ISSET_S(i, setsize, desc->nodemaps[j])) { + printf(",%d", j); + break; } - } else + } + if (j == desc->nnodes) putchar(','); - if (have_cache) { + if (desc->ncaches) putchar(','); - for (j = cpu->ct_cache - 1; j >= 0; j--) { - /* If shared_cpu_map is 0, all CPUs share the same - cache. */ - if (cpu->cache[j].camap == 0) - cpu->cache[j].camap = cpu->ct_core * - cpu->ct_thread; + /* Caches */ + for (j = desc->ncaches - 1; j >= 0; j--) { + struct cpu_cache *ca = &desc->caches[j]; + int x; - printf(",%d", i / cpu->cache[j].camap); + for (x = 0; x < ca->nsharedmaps; x++) { + if (CPU_ISSET_S(i, setsize, ca->sharedmaps[x])) { + printf(",%d", x); + break; + } } + if (x == ca->nsharedmaps) + putchar(','); } putchar('\n'); } @@ -596,22 +730,25 @@ print_parsable(struct cpu_desc *cpu) #define print_n(_key, _val) printf("%-23s%d\n", _key, _val) static void -print_readable(struct cpu_desc *cpu) +print_readable(struct lscpu_desc *desc) { - print_s("Architecture:", cpu->arch); + char buf[512]; + int i; + + print_s(_("Architecture:"), desc->arch); - if (cpu->mode & (MODE_REAL | MODE_TRANSPARENT | MODE_LONG)) { + if (desc->mode & (MODE_REAL | MODE_TRANSPARENT | MODE_LONG)) { char buf[64], *p = buf; - if (cpu->mode & MODE_REAL) { + if (desc->mode & MODE_REAL) { strcpy(p, "16-bit, "); p += 8; } - if (cpu->mode & MODE_TRANSPARENT) { + if (desc->mode & MODE_TRANSPARENT) { strcpy(p, "32-bit, "); p += 8; } - if (cpu->mode & MODE_LONG) { + if (desc->mode & MODE_LONG) { strcpy(p, "64-bit, "); p += 8; } @@ -619,44 +756,57 @@ print_readable(struct cpu_desc *cpu) print_s(_("CPU op-mode(s):"), buf); } - print_n("CPU(s):", cpu->ct_cpu); + print_n(_("CPU(s):"), desc->ncpus); - if (have_topology) { - print_n(_("Thread(s) per core:"), cpu->ct_thread); - print_n(_("Core(s) per socket:"), cpu->ct_core); - print_n(_("CPU socket(s):"), cpu->ct_socket); + if (desc->nsockets) { + print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores); + print_n(_("Core(s) per socket:"), desc->ncores / desc->nsockets); + print_n(_("CPU socket(s):"), desc->nsockets); } - if (have_node) - print_n(_("NUMA node(s):"), cpu->ct_node); - if (cpu->vendor) - print_s(_("Vendor ID:"), cpu->vendor); - if (cpu->family) - print_s(_("CPU family:"), cpu->family); - if (cpu->model) - print_s(_("Model:"), cpu->model); - if (cpu->stepping) - print_s(_("Stepping:"), cpu->stepping); - if (cpu->mhz) - print_s(_("CPU MHz:"), cpu->mhz); - if (cpu->virtflag) { - if (!strcmp(cpu->virtflag, "svm")) + if (desc->nnodes) + print_n(_("NUMA node(s):"), desc->nnodes); + if (desc->vendor) + print_s(_("Vendor ID:"), desc->vendor); + if (desc->family) + print_s(_("CPU family:"), desc->family); + if (desc->model) + print_s(_("Model:"), desc->model); + if (desc->stepping) + print_s(_("Stepping:"), desc->stepping); + if (desc->mhz) + print_s(_("CPU MHz:"), desc->mhz); + if (desc->virtflag) { + if (!strcmp(desc->virtflag, "svm")) print_s(_("Virtualization:"), "AMD-V"); - else if (!strcmp(cpu->virtflag, "vmx")) + else if (!strcmp(desc->virtflag, "vmx")) print_s(_("Virtualization:"), "VT-x"); } - if (cpu->hyper) { - print_s(_("Hypervisor vendor:"), hv_vendors[cpu->hyper]); - print_s(_("Virtualization type:"), virt_types[cpu->virtype]); + if (desc->hyper) { + print_s(_("Hypervisor vendor:"), hv_vendors[desc->hyper]); + print_s(_("Virtualization type:"), virt_types[desc->virtype]); } - if (have_cache) { + if (desc->ncaches) { char buf[512]; int i; - for (i = cpu->ct_cache - 1; i >= 0; i--) { + for (i = desc->ncaches - 1; i >= 0; i--) { snprintf(buf, sizeof(buf), - _("%s cache:"), cpu->cache[i].caname); - print_s(buf, cpu->cache[i].casize); + _("%s cache:"), desc->caches[i].name); + print_s(buf, desc->caches[i].size); + } + } + + if (desc->nnodes) { + size_t setbuflen = 7 * maxcpus; + char setbuf[setbuflen]; + + for (i = 0; i < desc->nnodes; i++) { + snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), i); + print_s(buf, cpulist_create( + setbuf, setbuflen, + desc->nodemaps[i], + CPU_ALLOC_SIZE(maxcpus))); } } } @@ -673,19 +823,10 @@ void usage(int rc) exit(rc); } -static int -ca_compare(const void *a, const void *b) -{ - struct ca_desc *cache1 = (struct ca_desc *) a; - struct ca_desc *cache2 = (struct ca_desc *) b; - - return strcmp(cache2->caname, cache1->caname); -} - int main(int argc, char *argv[]) { - struct cpu_desc _cpu, *cpu = &_cpu; - int parsable = 0, c; + struct lscpu_desc _desc, *desc = &_desc; + int parsable = 0, c, i; struct option longopts[] = { { "help", no_argument, 0, 'h' }, @@ -694,7 +835,7 @@ int main(int argc, char *argv[]) { NULL, 0, 0, 0 } }; - setlocale(LC_MESSAGES, ""); + setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -706,39 +847,35 @@ int main(int argc, char *argv[]) parsable = 1; break; case 's': + sysrootlen = strlen(optarg); strncpy(pathbuf, optarg, sizeof(pathbuf)); + pathbuf[sizeof(pathbuf) - 1] = '\0'; break; default: usage(EXIT_FAILURE); } } - if (chdir(pathbuf) == -1) - errx(EXIT_FAILURE, - _("error: change working directory to %s."), pathbuf); + memset(desc, 0, sizeof(*desc)); - memset(cpu, 0, sizeof(*cpu)); + read_basicinfo(desc); - check_system(); + for (i = 0; i < desc->ncpus; i++) { + read_topology(desc, i); + read_cache(desc, i); + } - read_basicinfo(cpu); + qsort(desc->caches, desc->ncaches, sizeof(struct cpu_cache), cachecmp); - if (have_topology) - read_topology(cpu); - if (have_cache) { - read_cache(cpu); - qsort(cpu->cache, cpu->ct_cache, sizeof(struct ca_desc), ca_compare); - } - if (have_node) - read_nodes(cpu); + read_nodes(desc); - read_hypervisor(cpu); + read_hypervisor(desc); /* Show time! */ if (parsable) - print_parsable(cpu); + print_parsable(desc); else - print_readable(cpu); + print_readable(desc); return EXIT_SUCCESS; } |