]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu.c
lscpu: add online state to output
[thirdparty/util-linux.git] / sys-utils / lscpu.c
CommitLineData
5dd7507c
CQ
1/*
2 * lscpu - CPU architecture information helper
3 *
4 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
5 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
6 *
80dde62f 7 * This program is free software; you can redistribute it and/or modify
5dd7507c 8 * it under the terms of the GNU General Public License as published by
80dde62f 9 * the Free Software Foundation; either version 2 of the License, or
5dd7507c
CQ
10 * (at your option) any later version.
11 *
80dde62f 12 * This program is distributed in the hope that it would be useful,
5dd7507c
CQ
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
80dde62f
KZ
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5dd7507c
CQ
20 */
21
22#include <ctype.h>
23#include <dirent.h>
5dd7507c
CQ
24#include <errno.h>
25#include <fcntl.h>
26#include <getopt.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/utsname.h>
31#include <unistd.h>
32#include <stdarg.h>
39561c70
KZ
33#include <sys/types.h>
34#include <sys/stat.h>
5dd7507c 35
7e03f383 36#include "cpuset.h"
5dd7507c 37#include "nls.h"
4581647a 38#include "xalloc.h"
eb76ca98 39#include "c.h"
477251f8
KZ
40#include "strutils.h"
41#include "bitops.h"
ba45d8c1 42#include "tt.h"
477251f8 43
5dd7507c
CQ
44#define CACHE_MAX 100
45
46/* /sys paths */
d50363cd 47#define _PATH_SYS_SYSTEM "/sys/devices/system"
7e03f383 48#define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu"
d50363cd 49#define _PATH_PROC_XEN "/proc/xen"
c8b64f6d 50#define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
d50363cd
KZ
51#define _PATH_PROC_CPUINFO "/proc/cpuinfo"
52#define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
b8ec7bdf 53#define _PATH_PROC_SYSINFO "/proc/sysinfo"
5dd7507c 54
c8b64f6d
KZ
55/* virtualization types */
56enum {
57 VIRT_NONE = 0,
58 VIRT_PARA,
59 VIRT_FULL
60};
61const char *virt_types[] = {
62 [VIRT_NONE] = N_("none"),
63 [VIRT_PARA] = N_("para"),
64 [VIRT_FULL] = N_("full")
65};
66
67/* hypervisor vendors */
68enum {
69 HYPER_NONE = 0,
70 HYPER_XEN,
71 HYPER_KVM,
99fbc877 72 HYPER_MSHV,
b8ec7bdf
HC
73 HYPER_VMWARE,
74 HYPER_IBM
c8b64f6d
KZ
75};
76const char *hv_vendors[] = {
77 [HYPER_NONE] = NULL,
78 [HYPER_XEN] = "Xen",
79 [HYPER_KVM] = "KVM",
99fbc877 80 [HYPER_MSHV] = "Microsoft",
b8ec7bdf
HC
81 [HYPER_VMWARE] = "VMware",
82 [HYPER_IBM] = "IBM"
c8b64f6d
KZ
83};
84
f633ad4e 85/* CPU modes */
79e8b41a 86enum {
f633ad4e
KZ
87 MODE_32BIT = (1 << 1),
88 MODE_64BIT = (1 << 2)
79e8b41a 89};
c8b64f6d 90
e8aa16ee
KZ
91/* cache(s) description */
92struct cpu_cache {
7e03f383
KZ
93 char *name;
94 char *size;
95
96 int nsharedmaps;
97 cpu_set_t **sharedmaps;
e8aa16ee
KZ
98};
99
a0fff77e
HC
100/* dispatching modes */
101enum {
102 DISP_HORIZONTAL = 0,
103 DISP_VERTICAL = 1
104};
105
106const char *disp_modes[] = {
107 [DISP_HORIZONTAL] = N_("horizontal"),
108 [DISP_VERTICAL] = N_("vertical")
109};
110
2b8fcb81
HC
111/* cpu polarization */
112enum {
113 POLAR_UNKNOWN = 0,
114 POLAR_VLOW,
115 POLAR_VMEDIUM,
116 POLAR_VHIGH,
117 POLAR_HORIZONTAL
118};
119
8005924a
KZ
120struct polarization_modes {
121 char *parsable;
122 char *readable;
123};
124
125struct polarization_modes polar_modes[] = {
126 [POLAR_UNKNOWN] = {"U", "-"},
127 [POLAR_VLOW] = {"VL", "vert-low"},
128 [POLAR_VMEDIUM] = {"VM", "vert-medium"},
129 [POLAR_VHIGH] = {"VH", "vert-high"},
130 [POLAR_HORIZONTAL] = {"H", "horizontal"},
2b8fcb81
HC
131};
132
e8aa16ee
KZ
133/* global description */
134struct lscpu_desc {
5dd7507c
CQ
135 char *arch;
136 char *vendor;
137 char *family;
138 char *model;
c8b64f6d
KZ
139 char *virtflag; /* virtualization flag (vmx, svm) */
140 int hyper; /* hypervisor vendor ID */
141 int virtype; /* VIRT_PARA|FULL|NONE ? */
5dd7507c
CQ
142 char *mhz;
143 char *stepping;
9b8d4d5f 144 char *bogomips;
5dd7507c 145 char *flags;
a0fff77e 146 int dispatching; /* none, horizontal or vertical */
79e8b41a
KZ
147 int mode; /* rm, lm or/and tm */
148
7e03f383 149 int ncpus; /* number of CPUs */
aac1e59e 150 cpu_set_t *online; /* mask with online CPUs */
7e03f383
KZ
151
152 int nnodes; /* number of NUMA modes */
153 cpu_set_t **nodemaps; /* array with NUMA nodes */
154
56baaa4e
HC
155 /* books -- based on book_siblings (internal kernel map of cpuX's
156 * hardware threads within the same book */
157 int nbooks; /* number of all online books */
158 cpu_set_t **bookmaps; /* unique book_siblings */
159
7e03f383
KZ
160 /* sockets -- based on core_siblings (internal kernel map of cpuX's
161 * hardware threads within the same physical_package_id (socket)) */
e282eec2 162 int nsockets; /* number of all online sockets */
7e03f383
KZ
163 cpu_set_t **socketmaps; /* unique core_siblings */
164
165 /* cores -- based on thread_siblings (internel kernel map of cpuX's
166 * hardware threads within the same core as cpuX) */
e282eec2 167 int ncores; /* number of all online cores */
7e03f383
KZ
168 cpu_set_t **coremaps; /* unique thread_siblings */
169
e282eec2 170 int nthreads; /* number of online threads */
7e03f383
KZ
171
172 int ncaches;
173 struct cpu_cache *caches;
2b8fcb81
HC
174
175 int *polarization; /* cpu polarization */
596b8845 176 int *addresses; /* physical cpu addresses */
d231eea1 177 int *configured; /* cpu configured */
5dd7507c
CQ
178};
179
8005924a
KZ
180enum {
181 OUTPUT_SUMMARY = 0, /* default */
182 OUTPUT_PARSABLE, /* -p */
ba45d8c1 183 OUTPUT_READABLE, /* -e */
8005924a
KZ
184};
185
186struct lscpu_modifier {
a7e5300c
HC
187 int mode; /* OUTPUT_* */
188 unsigned int hex:1, /* print CPU masks rather than CPU lists */
189 compat:1, /* use backwardly compatible format */
190 allcpus:1; /* print all CPUs */
8005924a
KZ
191};
192
d50363cd
KZ
193static size_t sysrootlen;
194static char pathbuf[PATH_MAX];
7e03f383 195static int maxcpus; /* size in bits of kernel cpu mask */
5dd7507c 196
aac1e59e
KZ
197#define is_cpu_online(_d, _cpu) \
198 ((_d) && (_d)->online ? \
199 CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
200
d50363cd
KZ
201static FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...)
202 __attribute__ ((__format__ (__printf__, 3, 4)));
ef173bde
KZ
203static void path_getstr(char *result, size_t len, const char *path, ...)
204 __attribute__ ((__format__ (__printf__, 3, 4)));
205static int path_getnum(const char *path, ...)
206 __attribute__ ((__format__ (__printf__, 1, 2)));
5dd7507c
CQ
207static int path_exist(const char *path, ...)
208 __attribute__ ((__format__ (__printf__, 1, 2)));
7e03f383 209static cpu_set_t *path_cpuset(const char *path, ...)
5dd7507c
CQ
210 __attribute__ ((__format__ (__printf__, 1, 2)));
211
477251f8
KZ
212/*
213 * Parsable output
214 */
215enum {
216 COL_CPU,
217 COL_CORE,
218 COL_SOCKET,
219 COL_NODE,
220 COL_BOOK,
2b8fcb81 221 COL_CACHE,
596b8845 222 COL_POLARIZATION,
d231eea1
HC
223 COL_ADDRESS,
224 COL_CONFIGURED,
a7e5300c 225 COL_ONLINE,
477251f8
KZ
226};
227
228static const char *colnames[] =
229{
230 [COL_CPU] = "CPU",
231 [COL_CORE] = "Core",
232 [COL_SOCKET] = "Socket",
233 [COL_NODE] = "Node",
234 [COL_BOOK] = "Book",
2b8fcb81 235 [COL_CACHE] = "Cache",
596b8845 236 [COL_POLARIZATION] = "Polarization",
d231eea1
HC
237 [COL_ADDRESS] = "Address",
238 [COL_CONFIGURED] = "Configured",
a7e5300c 239 [COL_ONLINE] = "Online",
477251f8
KZ
240};
241
242
243static int column_name_to_id(const char *name, size_t namesz)
244{
329fd1c3 245 size_t i;
477251f8
KZ
246
247 for (i = 0; i < ARRAY_SIZE(colnames); i++) {
248 const char *cn = colnames[i];
249
250 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
251 return i;
252 }
253 warnx(_("unknown column: %s"), name);
254 return -1;
255}
256
d50363cd
KZ
257static const char *
258path_vcreate(const char *path, va_list ap)
259{
260 if (sysrootlen)
261 vsnprintf(pathbuf + sysrootlen,
262 sizeof(pathbuf) - sysrootlen, path, ap);
263 else
264 vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
265 return pathbuf;
266}
267
5dd7507c 268static FILE *
d50363cd 269path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
5dd7507c 270{
d50363cd
KZ
271 FILE *f;
272 const char *p = path_vcreate(path, ap);
273
274 f = fopen(p, mode);
275 if (!f && exit_on_error)
276 err(EXIT_FAILURE, _("error: cannot open %s"), p);
277 return f;
5dd7507c
CQ
278}
279
280static FILE *
d50363cd 281path_fopen(const char *mode, int exit_on_error, const char *path, ...)
5dd7507c 282{
d50363cd
KZ
283 FILE *fd;
284 va_list ap;
285
286 va_start(ap, path);
fe81c7d1 287 fd = path_vfopen(mode, exit_on_error, path, ap);
d50363cd
KZ
288 va_end(ap);
289
290 return fd;
5dd7507c
CQ
291}
292
293static void
ef173bde
KZ
294path_getstr(char *result, size_t len, const char *path, ...)
295{
296 FILE *fd;
297 va_list ap;
298
299 va_start(ap, path);
d50363cd 300 fd = path_vfopen("r", 1, path, ap);
ef173bde
KZ
301 va_end(ap);
302
303 if (!fgets(result, len, fd))
304 err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
305 fclose(fd);
306
307 len = strlen(result);
308 if (result[len - 1] == '\n')
309 result[len - 1] = '\0';
310}
311
312static int
313path_getnum(const char *path, ...)
5dd7507c
CQ
314{
315 FILE *fd;
316 va_list ap;
ef173bde 317 int result;
5dd7507c
CQ
318
319 va_start(ap, path);
d50363cd 320 fd = path_vfopen("r", 1, path, ap);
5dd7507c
CQ
321 va_end(ap);
322
ef173bde 323 if (fscanf(fd, "%d", &result) != 1) {
5dd7507c 324 if (ferror(fd))
d50363cd 325 err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
5dd7507c 326 else
d50363cd 327 errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
5dd7507c
CQ
328 }
329 fclose(fd);
ef173bde 330 return result;
5dd7507c
CQ
331}
332
333static int
334path_exist(const char *path, ...)
335{
336 va_list ap;
d50363cd 337 const char *p;
5dd7507c
CQ
338
339 va_start(ap, path);
d50363cd 340 p = path_vcreate(path, ap);
5dd7507c
CQ
341 va_end(ap);
342
d50363cd 343 return access(p, F_OK) == 0;
5dd7507c
CQ
344}
345
7e03f383 346static cpu_set_t *
aac1e59e 347path_cpuparse(int islist, const char *path, va_list ap)
5dd7507c 348{
7e03f383 349 FILE *fd;
7e03f383
KZ
350 cpu_set_t *set;
351 size_t setsize, len = maxcpus * 7;
352 char buf[len];
5dd7507c 353
7e03f383 354 fd = path_vfopen("r", 1, path, ap);
5dd7507c 355
7e03f383
KZ
356 if (!fgets(buf, len, fd))
357 err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
358 fclose(fd);
5dd7507c 359
7e03f383
KZ
360 len = strlen(buf);
361 if (buf[len - 1] == '\n')
362 buf[len - 1] = '\0';
363
364 set = cpuset_alloc(maxcpus, &setsize, NULL);
365 if (!set)
366 err(EXIT_FAILURE, _("failed to callocate cpu set"));
367
aac1e59e 368 if (islist) {
b16f615a 369 if (cpulist_parse(buf, set, setsize, 0))
aac1e59e
KZ
370 errx(EXIT_FAILURE, _("failed to parse CPU list %s"), buf);
371 } else {
372 if (cpumask_parse(buf, set, setsize))
373 errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf);
374 }
375 return set;
376}
377
378static cpu_set_t *
379path_cpuset(const char *path, ...)
380{
381 va_list ap;
382 cpu_set_t *set;
383
384 va_start(ap, path);
385 set = path_cpuparse(0, path, ap);
386 va_end(ap);
387
388 return set;
389}
390
391static cpu_set_t *
392path_cpulist(const char *path, ...)
393{
394 va_list ap;
395 cpu_set_t *set;
396
397 va_start(ap, path);
398 set = path_cpuparse(1, path, ap);
399 va_end(ap);
7e03f383
KZ
400
401 return set;
5dd7507c
CQ
402}
403
404/* Lookup a pattern and get the value from cpuinfo.
405 * Format is:
406 *
407 * "<pattern> : <key>"
408 */
409int lookup(char *line, char *pattern, char **value)
410{
411 char *p, *v;
412 int len = strlen(pattern);
413
414 if (!*line)
415 return 0;
416
417 /* pattern */
418 if (strncmp(line, pattern, len))
419 return 0;
420
421 /* white spaces */
422 for (p = line + len; isspace(*p); p++);
423
424 /* separator */
425 if (*p != ':')
426 return 0;
427
428 /* white spaces */
429 for (++p; isspace(*p); p++);
430
431 /* value */
432 if (!*p)
433 return 0;
434 v = p;
435
436 /* end of value */
437 len = strlen(line) - 1;
438 for (p = line + len; isspace(*(p-1)); p--);
439 *p = '\0';
440
441 *value = xstrdup(v);
442 return 1;
443}
444
f633ad4e
KZ
445/* Don't init the mode for platforms where we are not able to
446 * detect that CPU supports 64-bit mode.
447 */
448static int
449init_mode(void)
450{
451 int m = 0;
452
4e740fd8
KZ
453 if (sysrootlen)
454 /* reading info from any /{sys,proc} dump, don't mix it with
455 * information about our real CPU */
456 return 0;
457
f633ad4e
KZ
458#if defined(__alpha__) || defined(__ia64__)
459 m |= MODE_64BIT; /* 64bit platforms only */
460#endif
461 /* platforms with 64bit flag in /proc/cpuinfo, define
462 * 32bit default here */
463#if defined(__i386__) || defined(__x86_64__) || \
c487c90c 464 defined(__s390x__) || defined(__s390__) || defined(__sparc_v9__)
f633ad4e
KZ
465 m |= MODE_32BIT;
466#endif
467 return m;
468}
469
5dd7507c 470static void
e8aa16ee 471read_basicinfo(struct lscpu_desc *desc)
5dd7507c 472{
d50363cd 473 FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO);
5dd7507c
CQ
474 char buf[BUFSIZ];
475 struct utsname utsbuf;
476
477 /* architecture */
478 if (uname(&utsbuf) == -1)
479 err(EXIT_FAILURE, _("error: uname failed"));
e8aa16ee 480 desc->arch = xstrdup(utsbuf.machine);
5dd7507c
CQ
481
482 /* count CPU(s) */
7e03f383
KZ
483 while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", desc->ncpus))
484 desc->ncpus++;
5dd7507c
CQ
485
486 /* details */
487 while (fgets(buf, sizeof(buf), fp) != NULL) {
e8aa16ee
KZ
488 if (lookup(buf, "vendor", &desc->vendor)) ;
489 else if (lookup(buf, "vendor_id", &desc->vendor)) ;
e8aa16ee
KZ
490 else if (lookup(buf, "family", &desc->family)) ;
491 else if (lookup(buf, "cpu family", &desc->family)) ;
492 else if (lookup(buf, "model", &desc->model)) ;
493 else if (lookup(buf, "stepping", &desc->stepping)) ;
494 else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
f633ad4e
KZ
495 else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */
496 else if (lookup(buf, "features", &desc->flags)) ; /* s390 */
c487c90c 497 else if (lookup(buf, "type", &desc->flags)) ; /* sparc64 */
9b8d4d5f 498 else if (lookup(buf, "bogomips", &desc->bogomips)) ;
abcd6368 499 else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
5dd7507c
CQ
500 else
501 continue;
502 }
c8b64f6d 503
f633ad4e
KZ
504 desc->mode = init_mode();
505
e8aa16ee
KZ
506 if (desc->flags) {
507 snprintf(buf, sizeof(buf), " %s ", desc->flags);
c8b64f6d 508 if (strstr(buf, " svm "))
e8aa16ee 509 desc->virtflag = strdup("svm");
c8b64f6d 510 else if (strstr(buf, " vmx "))
e8aa16ee 511 desc->virtflag = strdup("vmx");
79e8b41a 512 if (strstr(buf, " lm "))
f633ad4e
KZ
513 desc->mode |= MODE_32BIT | MODE_64BIT; /* x86_64 */
514 if (strstr(buf, " zarch "))
515 desc->mode |= MODE_32BIT | MODE_64BIT; /* s390x */
c487c90c
KZ
516 if (strstr(buf, " sun4v ") || strstr(buf, " sun4u "))
517 desc->mode |= MODE_32BIT | MODE_64BIT; /* sparc64 */
c8b64f6d
KZ
518 }
519
5dd7507c 520 fclose(fp);
7e03f383
KZ
521
522 if (path_exist(_PATH_SYS_SYSTEM "/cpu/kernel_max"))
3d6e5c35
GR
523 /* note that kernel_max is maximum index [NR_CPUS-1] */
524 maxcpus = path_getnum(_PATH_SYS_SYSTEM "/cpu/kernel_max") + 1;
7e03f383
KZ
525
526 else if (!sysrootlen)
527 /* the root is '/' so we are working with data from the current kernel */
528 maxcpus = get_max_number_of_cpus();
529 else
d0bb6987 530 /* we are reading some /sys snapshot instead of the real /sys,
7e03f383
KZ
531 * let's use any crazy number... */
532 maxcpus = desc->ncpus > 2048 ? desc->ncpus : 2048;
aac1e59e
KZ
533
534 /* get mask for online CPUs */
e282eec2
KZ
535 if (path_exist(_PATH_SYS_SYSTEM "/cpu/online")) {
536 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
5d4ba40d 537 desc->online = path_cpulist(_PATH_SYS_SYSTEM "/cpu/online");
e282eec2
KZ
538 desc->nthreads = CPU_COUNT_S(setsize, desc->online);
539 }
a0fff77e
HC
540
541 /* get dispatching mode */
542 if (path_exist(_PATH_SYS_SYSTEM "/cpu/dispatching"))
543 desc->dispatching = path_getnum(_PATH_SYS_SYSTEM "/cpu/dispatching");
544 else
545 desc->dispatching = -1;
5dd7507c
CQ
546}
547
c8b64f6d
KZ
548static int
549has_pci_device(int vendor, int device)
550{
551 FILE *f;
552 int num, fn, ven, dev;
553 int res = 1;
554
d50363cd 555 f = path_fopen("r", 0, _PATH_PROC_PCIDEVS);
c8b64f6d
KZ
556 if (!f)
557 return 0;
558
559 /* for more details about bus/pci/devices format see
560 * drivers/pci/proc.c in linux kernel
561 */
562 while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
563 &num, &fn, &ven, &dev) == 4) {
564
565 if (ven == vendor && dev == device)
566 goto found;
567 }
568
569 res = 0;
570found:
571 fclose(f);
572 return res;
573}
574
575#if defined(__x86_64__) || defined(__i386__)
576
577/*
578 * This CPUID leaf returns the information about the hypervisor.
579 * EAX : maximum input value for CPUID supported by the hypervisor.
580 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
581 */
582#define HYPERVISOR_INFO_LEAF 0x40000000
583
584static inline void
585cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
586 unsigned int *ecx, unsigned int *edx)
587{
c9239f23
MF
588 __asm__(
589#if defined(__PIC__) && defined(__i386__)
590 /* x86 PIC cannot clobber ebx -- gcc bitches */
591 "pushl %%ebx;"
592 "cpuid;"
593 "movl %%ebx, %%esi;"
594 "popl %%ebx;"
595 : "=S" (*ebx),
596#else
597 "cpuid;"
598 : "=b" (*ebx),
599#endif
600 "=a" (*eax),
c8b64f6d
KZ
601 "=c" (*ecx),
602 "=d" (*edx)
bc54770d 603 : "1" (op), "c"(0));
c8b64f6d
KZ
604}
605
606static void
e8aa16ee 607read_hypervisor_cpuid(struct lscpu_desc *desc)
c8b64f6d
KZ
608{
609 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
610 char hyper_vendor_id[13];
611
612 memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
613
614 cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
615 memcpy(hyper_vendor_id + 0, &ebx, 4);
616 memcpy(hyper_vendor_id + 4, &ecx, 4);
617 memcpy(hyper_vendor_id + 8, &edx, 4);
618 hyper_vendor_id[12] = '\0';
619
620 if (!hyper_vendor_id[0])
621 return;
622
623 if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
e8aa16ee 624 desc->hyper = HYPER_XEN;
c8b64f6d 625 else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
e8aa16ee 626 desc->hyper = HYPER_KVM;
c8b64f6d 627 else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
e8aa16ee 628 desc->hyper = HYPER_MSHV;
99fbc877
SH
629 else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
630 desc->hyper = HYPER_VMWARE;
c8b64f6d
KZ
631}
632
633#else /* ! __x86_64__ */
634static void
e8aa16ee 635read_hypervisor_cpuid(struct lscpu_desc *desc)
c8b64f6d
KZ
636{
637}
638#endif
639
640static void
e8aa16ee 641read_hypervisor(struct lscpu_desc *desc)
c8b64f6d 642{
e8aa16ee 643 read_hypervisor_cpuid(desc);
c8b64f6d 644
e8aa16ee 645 if (desc->hyper)
c8b64f6d 646 /* hvm */
e8aa16ee 647 desc->virtype = VIRT_FULL;
c8b64f6d 648
d50363cd 649 else if (path_exist(_PATH_PROC_XEN)) {
c8b64f6d 650 /* Xen para-virt or dom0 */
d50363cd 651 FILE *fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
c8b64f6d
KZ
652 int dom0 = 0;
653
654 if (fd) {
655 char buf[256];
656
657 if (fscanf(fd, "%s", buf) == 1 &&
658 !strcmp(buf, "control_d"))
659 dom0 = 1;
660 fclose(fd);
661 }
e8aa16ee
KZ
662 desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
663 desc->hyper = HYPER_XEN;
c8b64f6d
KZ
664
665 } else if (has_pci_device(0x5853, 0x0001)) {
666 /* Xen full-virt on non-x86_64 */
e8aa16ee
KZ
667 desc->hyper = HYPER_XEN;
668 desc->virtype = VIRT_FULL;
b8ec7bdf
HC
669 } else if (path_exist(_PATH_PROC_SYSINFO)) {
670 FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
671 char buf[BUFSIZ];
672
673 desc->hyper = HYPER_IBM;
674 desc->virtype = VIRT_FULL;
675 while (fgets(buf, sizeof(buf), fd) != NULL) {
676 if (!strstr(buf, "Control Program:"))
677 continue;
678 if (!strstr(buf, "KVM"))
679 desc->hyper = HYPER_IBM;
680 else
681 desc->hyper = HYPER_KVM;
682 }
683 fclose(fd);
c8b64f6d
KZ
684 }
685}
686
7e03f383
KZ
687/* add @set to the @ary, unnecesary set is deallocated. */
688static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set)
689{
690 int i;
691 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
692
693 if (!ary)
694 return -1;
695
696 for (i = 0; i < *items; i++) {
697 if (CPU_EQUAL_S(setsize, set, ary[i]))
698 break;
699 }
700 if (i == *items) {
701 ary[*items] = set;
702 ++*items;
703 return 0;
704 }
705 CPU_FREE(set);
706 return 1;
707}
708
5dd7507c 709static void
7e03f383 710read_topology(struct lscpu_desc *desc, int num)
5dd7507c 711{
56baaa4e 712 cpu_set_t *thread_siblings, *core_siblings, *book_siblings;
7e03f383
KZ
713
714 if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num))
715 return;
5dd7507c 716
7e03f383
KZ
717 thread_siblings = path_cpuset(_PATH_SYS_CPU
718 "/cpu%d/topology/thread_siblings", num);
719 core_siblings = path_cpuset(_PATH_SYS_CPU
720 "/cpu%d/topology/core_siblings", num);
56baaa4e
HC
721 book_siblings = NULL;
722 if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num)) {
723 book_siblings = path_cpuset(_PATH_SYS_CPU
724 "/cpu%d/topology/book_siblings", num);
725 }
aac1e59e
KZ
726
727 if (!desc->coremaps) {
56baaa4e 728 int nbooks, nsockets, ncores, nthreads;
7e03f383
KZ
729 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
730
731 /* threads within one core */
732 nthreads = CPU_COUNT_S(setsize, thread_siblings);
733 /* cores within one socket */
734 ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads;
32a46618
HC
735 /* number of sockets within one book.
736 * Because of odd / non-present cpu maps and to keep
737 * calculation easy we make sure that nsockets and
738 * nbooks is at least 1.
739 */
740 nsockets = desc->ncpus / nthreads / ncores ?: 1;
56baaa4e 741 /* number of books */
32a46618 742 nbooks = desc->ncpus / nthreads / ncores / nsockets ?: 1;
e282eec2
KZ
743
744 /* all threads, see also read_basicinfo()
32a46618 745 * -- fallback for kernels without
e282eec2
KZ
746 * /sys/devices/system/cpu/online.
747 */
748 if (!desc->nthreads)
32a46618 749 desc->nthreads = nbooks * nsockets * ncores * nthreads;
9d1a3a18
HC
750 /* For each map we make sure that it can have up to ncpus
751 * entries. This is because we cannot reliably calculate the
752 * number of cores, sockets and books on all architectures.
753 * E.g. completely virtualized architectures like s390 may
754 * have multiple sockets of different sizes.
755 */
756 desc->coremaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
757 desc->socketmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
08de16d0 758 if (book_siblings)
9d1a3a18 759 desc->bookmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
7e03f383 760 }
5dd7507c 761
7e03f383
KZ
762 add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
763 add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings);
56baaa4e
HC
764 if (book_siblings)
765 add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings);
7e03f383 766}
2b8fcb81
HC
767static void
768read_polarization(struct lscpu_desc *desc, int num)
769{
770 char mode[64];
771
772 if (desc->dispatching < 0)
773 return;
774 if (!path_exist(_PATH_SYS_CPU "/cpu%d/polarization", num))
775 return;
776 if (!desc->polarization)
777 desc->polarization = xcalloc(desc->ncpus, sizeof(int));
778 path_getstr(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num);
779 if (strncmp(mode, "vertical:low", sizeof(mode)) == 0)
780 desc->polarization[num] = POLAR_VLOW;
781 else if (strncmp(mode, "vertical:medium", sizeof(mode)) == 0)
782 desc->polarization[num] = POLAR_VMEDIUM;
783 else if (strncmp(mode, "vertical:high", sizeof(mode)) == 0)
784 desc->polarization[num] = POLAR_VHIGH;
785 else if (strncmp(mode, "horizontal", sizeof(mode)) == 0)
786 desc->polarization[num] = POLAR_HORIZONTAL;
787 else
788 desc->polarization[num] = POLAR_UNKNOWN;
789}
7e03f383 790
596b8845
HC
791static void
792read_address(struct lscpu_desc *desc, int num)
793{
794 if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num))
795 return;
796 if (!desc->addresses)
797 desc->addresses = xcalloc(desc->ncpus, sizeof(int));
798 desc->addresses[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/address", num);
799}
7e03f383 800
d231eea1
HC
801static void
802read_configured(struct lscpu_desc *desc, int num)
803{
804 if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num))
805 return;
806 if (!desc->configured)
807 desc->configured = xcalloc(desc->ncpus, sizeof(int));
808 desc->configured[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", num);
809}
810
7e03f383
KZ
811static int
812cachecmp(const void *a, const void *b)
813{
814 struct cpu_cache *c1 = (struct cpu_cache *) a;
815 struct cpu_cache *c2 = (struct cpu_cache *) b;
816
817 return strcmp(c2->name, c1->name);
5dd7507c
CQ
818}
819
820static void
7e03f383 821read_cache(struct lscpu_desc *desc, int num)
5dd7507c
CQ
822{
823 char buf[256];
7e03f383 824 int i;
5dd7507c 825
aac1e59e 826 if (!desc->ncaches) {
7e03f383
KZ
827 while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
828 num, desc->ncaches))
829 desc->ncaches++;
5dd7507c 830
7e03f383
KZ
831 if (!desc->ncaches)
832 return;
5dd7507c 833
08de16d0 834 desc->caches = xcalloc(desc->ncaches, sizeof(*desc->caches));
7e03f383
KZ
835 }
836 for (i = 0; i < desc->ncaches; i++) {
837 struct cpu_cache *ca = &desc->caches[i];
838 cpu_set_t *map;
839
dcdead42
HC
840 if (!path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
841 num, i))
842 continue;
7e03f383
KZ
843 if (!ca->name) {
844 int type, level;
845
846 /* cache type */
847 path_getstr(buf, sizeof(buf),
848 _PATH_SYS_CPU "/cpu%d/cache/index%d/type",
849 num, i);
850 if (!strcmp(buf, "Data"))
851 type = 'd';
852 else if (!strcmp(buf, "Instruction"))
853 type = 'i';
854 else
855 type = 0;
856
857 /* cache level */
858 level = path_getnum(_PATH_SYS_CPU "/cpu%d/cache/index%d/level",
859 num, i);
860 if (type)
861 snprintf(buf, sizeof(buf), "L%d%c", level, type);
862 else
863 snprintf(buf, sizeof(buf), "L%d", level);
864
865 ca->name = xstrdup(buf);
866
867 /* cache size */
868 path_getstr(buf, sizeof(buf),
869 _PATH_SYS_CPU "/cpu%d/cache/index%d/size",
870 num, i);
871 ca->size = xstrdup(buf);
872 }
5dd7507c 873
7e03f383
KZ
874 /* information about how CPUs share different caches */
875 map = path_cpuset(_PATH_SYS_CPU "/cpu%d/cache/index%d/shared_cpu_map",
876 num, i);
5dd7507c 877
08de16d0
DB
878 if (!ca->sharedmaps)
879 ca->sharedmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
7e03f383 880 add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
5dd7507c
CQ
881 }
882}
883
884static void
e8aa16ee 885read_nodes(struct lscpu_desc *desc)
5dd7507c
CQ
886{
887 int i;
888
889 /* number of NUMA node */
7e03f383
KZ
890 while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", desc->nnodes))
891 desc->nnodes++;
892
893 if (!desc->nnodes)
894 return;
5dd7507c 895
08de16d0 896 desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *));
5dd7507c
CQ
897
898 /* information about how nodes share different CPUs */
7e03f383
KZ
899 for (i = 0; i < desc->nnodes; i++)
900 desc->nodemaps[i] = path_cpuset(
5dd7507c
CQ
901 _PATH_SYS_SYSTEM "/node/node%d/cpumap",
902 i);
903}
904
e3b3a2f3
KZ
905static char *
906get_cell_data(struct lscpu_desc *desc, int cpu, int col,
907 struct lscpu_modifier *mod,
908 char *buf, size_t bufsz)
5dd7507c 909{
7e03f383 910 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
e9d659ea 911 size_t idx;
e3b3a2f3
KZ
912
913 *buf = '\0';
5dd7507c 914
477251f8
KZ
915 switch (col) {
916 case COL_CPU:
e3b3a2f3 917 snprintf(buf, bufsz, "%d", cpu);
477251f8
KZ
918 break;
919 case COL_CORE:
e9d659ea
KZ
920 if (cpuset_ary_isset(cpu, desc->coremaps,
921 desc->ncores, setsize, &idx) == 0)
e3b3a2f3 922 snprintf(buf, bufsz, "%zd", idx);
477251f8
KZ
923 break;
924 case COL_SOCKET:
e9d659ea
KZ
925 if (cpuset_ary_isset(cpu, desc->socketmaps,
926 desc->nsockets, setsize, &idx) == 0)
e3b3a2f3 927 snprintf(buf, bufsz, "%zd", idx);
477251f8
KZ
928 break;
929 case COL_NODE:
e9d659ea
KZ
930 if (cpuset_ary_isset(cpu, desc->nodemaps,
931 desc->nnodes, setsize, &idx) == 0)
e3b3a2f3 932 snprintf(buf, bufsz, "%zd", idx);
477251f8
KZ
933 break;
934 case COL_BOOK:
e9d659ea
KZ
935 if (cpuset_ary_isset(cpu, desc->bookmaps,
936 desc->nbooks, setsize, &idx) == 0)
e3b3a2f3 937 snprintf(buf, bufsz, "%zd", idx);
477251f8
KZ
938 break;
939 case COL_CACHE:
e3b3a2f3
KZ
940 {
941 char *p = buf;
942 size_t sz = bufsz;
943 int j;
944
7e03f383
KZ
945 for (j = desc->ncaches - 1; j >= 0; j--) {
946 struct cpu_cache *ca = &desc->caches[j];
e9d659ea
KZ
947
948 if (cpuset_ary_isset(cpu, ca->sharedmaps,
e3b3a2f3
KZ
949 ca->nsharedmaps, setsize, &idx) == 0) {
950 int x = snprintf(p, sz, "%zd", idx);
951 if (x <= 0 || (size_t) x + 2 >= sz)
952 return NULL;
953 p += x;
954 sz -= x;
955 }
956 if (j != 0) {
957 *p++ = mod->compat ? ',' : ':';
958 *p = '\0';
959 sz++;
960 }
5dd7507c 961 }
477251f8 962 break;
e3b3a2f3 963 }
2b8fcb81 964 case COL_POLARIZATION:
ba45d8c1
KZ
965 if (desc->polarization) {
966 int x = desc->polarization[cpu];
967
e3b3a2f3 968 snprintf(buf, bufsz, "%s",
ba45d8c1
KZ
969 mod->mode == OUTPUT_PARSABLE ?
970 polar_modes[x].parsable :
971 polar_modes[x].readable);
972 }
2b8fcb81 973 break;
596b8845
HC
974 case COL_ADDRESS:
975 if (desc->addresses)
e3b3a2f3 976 snprintf(buf, bufsz, "%d", desc->addresses[cpu]);
596b8845 977 break;
d231eea1
HC
978 case COL_CONFIGURED:
979 if (desc->configured)
980 snprintf(buf, bufsz,
981 desc->configured[cpu] ? _("Y") : _("N"));
982 break;
a7e5300c
HC
983 case COL_ONLINE:
984 if (desc->online)
985 snprintf(buf, bufsz, is_cpu_online(desc, cpu) ? _("Y") : _("N"));
986 break;
477251f8 987 }
e3b3a2f3
KZ
988 return buf;
989}
990
991static char *
992get_cell_header(struct lscpu_desc *desc, int col,
993 struct lscpu_modifier *mod,
994 char *buf, size_t bufsz)
995{
996 *buf = '\0';
997
998 if (col == COL_CACHE) {
999 char *p = buf;
1000 size_t sz = bufsz;
1001 int i;
1002
1003 for (i = desc->ncaches - 1; i >= 0; i--) {
1004 int x = snprintf(p, sz, "%s", desc->caches[i].name);
1005 if (x <= 0 || (size_t) x + 2 > sz)
1006 return NULL;
1007 sz -= x;
1008 p += x;
1009 if (i > 0) {
1010 *p++ = mod->compat ? ',' : ':';
1011 *p = '\0';
1012 sz++;
1013 }
1014 }
1015 if (desc->ncaches)
1016 return buf;
1017 }
1018 snprintf(buf, bufsz, colnames[col]);
1019 return buf;
477251f8
KZ
1020}
1021
1022/*
ba45d8c1 1023 * [-p] backend, we support two parsable formats:
477251f8
KZ
1024 *
1025 * 1) "compatible" -- this format is compatible with the original lscpu(1)
1026 * output and it contains fixed set of the columns. The CACHE columns are at
1027 * the end of the line and the CACHE is not printed if the number of the caches
1028 * is zero. The CACHE columns are separated by two commas, for example:
1029 *
1030 * $ lscpu --parse
1031 * # CPU,Core,Socket,Node,,L1d,L1i,L2
1032 * 0,0,0,0,,0,0,0
1033 * 1,1,0,0,,1,1,0
1034 *
1035 * 2) "user defined output" -- this format prints always all columns without
1036 * special prefix for CACHE column. If there are not CACHEs then the column is
1037 * empty and the header "Cache" is printed rather than a real name of the cache.
1038 * The CACHE columns are separated by ':'.
1039 *
1040 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
1041 * # CPU,Core,Socket,Node,L1d:L1i:L2
1042 * 0,0,0,0,0:0:0
1043 * 1,1,0,0,1:1:0
1044 */
1045static void
8005924a
KZ
1046print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
1047 struct lscpu_modifier *mod)
477251f8 1048{
e3b3a2f3
KZ
1049 char buf[BUFSIZ], *data;
1050 int i;
477251f8 1051
e3b3a2f3
KZ
1052 /*
1053 * Header
1054 */
477251f8
KZ
1055 printf(_(
1056 "# The following is the parsable format, which can be fed to other\n"
1057 "# programs. Each different item in every column has an unique ID\n"
1058 "# starting from zero.\n"));
1059
1060 fputs("# ", stdout);
1061 for (i = 0; i < ncols; i++) {
1062 if (cols[i] == COL_CACHE) {
8005924a 1063 if (mod->compat && !desc->ncaches)
477251f8 1064 continue;
8005924a 1065 if (mod->compat && i != 0)
477251f8 1066 putchar(',');
477251f8 1067 }
e3b3a2f3
KZ
1068 if (i > 0)
1069 putchar(',');
1070
1071 data = get_cell_header(desc, cols[i], mod, buf, sizeof(buf));
1072 fputs(data && *data ? data : "", stdout);
477251f8
KZ
1073 }
1074 putchar('\n');
1075
e3b3a2f3
KZ
1076 /*
1077 * Data
1078 */
477251f8 1079 for (i = 0; i < desc->ncpus; i++) {
e3b3a2f3
KZ
1080 int c;
1081
a7e5300c 1082 if (!mod->allcpus && desc->online && !is_cpu_online(desc, i))
477251f8
KZ
1083 continue;
1084 for (c = 0; c < ncols; c++) {
8005924a 1085 if (mod->compat && cols[c] == COL_CACHE) {
477251f8
KZ
1086 if (!desc->ncaches)
1087 continue;
1088 if (c > 0)
1089 putchar(',');
1090 }
1091 if (c > 0)
1092 putchar(',');
e3b3a2f3
KZ
1093
1094 data = get_cell_data(desc, i, cols[c], mod,
1095 buf, sizeof(buf));
1096 fputs(data && *data ? data : "", stdout);
477251f8 1097 }
5dd7507c
CQ
1098 putchar('\n');
1099 }
1100}
1101
ba45d8c1
KZ
1102/*
1103 * [-e] backend
1104 */
1105static void
1106print_readable(struct lscpu_desc *desc, int cols[], int ncols,
1107 struct lscpu_modifier *mod)
1108{
1109 int i;
1110 char buf[BUFSIZ], *data;
1111 struct tt *tt = tt_new_table(0);
1112
1113 if (!tt)
1114 err(EXIT_FAILURE, _("failed to initialize output table"));
1115
1116 for (i = 0; i < ncols; i++) {
1117 char *p = data = get_cell_header(desc, cols[i],
1118 mod, buf, sizeof(buf));
1119 while (p && *p != '\0')
1120 *p++ = toupper((unsigned int) *p);
1121 tt_define_column(tt, xstrdup(data), 0, 0);
1122 }
1123
1124 for (i = 0; i < desc->ncpus; i++) {
1125 int c;
1126 struct tt_line *line;
1127
a7e5300c 1128 if (!mod->allcpus && desc->online && !is_cpu_online(desc, i))
ba45d8c1
KZ
1129 continue;
1130
1131 line = tt_add_line(tt, NULL);
1132
1133 for (c = 0; c < ncols; c++) {
1134 data = get_cell_data(desc, i, cols[c], mod,
1135 buf, sizeof(buf));
a7e5300c 1136 tt_line_set_data(line, c, data && *data ? xstrdup(data) : "-");
ba45d8c1
KZ
1137 }
1138 }
1139
1140 tt_print_table(tt);
1141}
5dd7507c
CQ
1142
1143/* output formats "<key> <value>"*/
1144#define print_s(_key, _val) printf("%-23s%s\n", _key, _val)
1145#define print_n(_key, _val) printf("%-23s%d\n", _key, _val)
1146
1147static void
4f912c6a
KZ
1148print_cpuset(const char *key, cpu_set_t *set, int hex)
1149{
1150 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
1151 size_t setbuflen = 7 * maxcpus;
1152 char setbuf[setbuflen], *p;
1153
1154 if (hex) {
1155 p = cpumask_create(setbuf, setbuflen, set, setsize);
1156 printf("%-23s0x%s\n", key, p);
1157 } else {
1158 p = cpulist_create(setbuf, setbuflen, set, setsize);
1159 print_s(key, p);
1160 }
1161
1162}
1163
ba45d8c1
KZ
1164/*
1165 * default output
1166 */
4f912c6a 1167static void
8005924a 1168print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
5dd7507c 1169{
7e03f383
KZ
1170 char buf[512];
1171 int i;
aac1e59e 1172 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
7e03f383 1173
e6b0611b 1174 print_s(_("Architecture:"), desc->arch);
79e8b41a 1175
f633ad4e 1176 if (desc->mode) {
79e8b41a
KZ
1177 char buf[64], *p = buf;
1178
f633ad4e 1179 if (desc->mode & MODE_32BIT) {
79e8b41a
KZ
1180 strcpy(p, "32-bit, ");
1181 p += 8;
1182 }
f633ad4e 1183 if (desc->mode & MODE_64BIT) {
79e8b41a
KZ
1184 strcpy(p, "64-bit, ");
1185 p += 8;
1186 }
1187 *(p - 2) = '\0';
1188 print_s(_("CPU op-mode(s):"), buf);
1189 }
aabe2441 1190#if !defined(WORDS_BIGENDIAN)
9b8d4d5f
DB
1191 print_s(_("Byte Order:"), "Little Endian");
1192#else
1193 print_s(_("Byte Order:"), "Big Endian");
9b8d4d5f 1194#endif
4a939e04 1195 print_n(_("CPU(s):"), desc->ncpus);
4f912c6a 1196
5d4ba40d 1197 if (desc->online)
8005924a
KZ
1198 print_cpuset(mod->hex ? _("On-line CPU(s) mask:") :
1199 _("On-line CPU(s) list:"),
1200 desc->online, mod->hex);
4f912c6a 1201
5d4ba40d 1202 if (desc->online && CPU_COUNT_S(setsize, desc->online) != desc->ncpus) {
4f912c6a
KZ
1203 cpu_set_t *set;
1204
1205 /* Linux kernel provides cpuset of off-line CPUs that contains
1206 * all configured CPUs (see /sys/devices/system/cpu/offline),
1207 * but want to print real (present in system) off-line CPUs only.
1208 */
1209 set = cpuset_alloc(maxcpus, NULL, NULL);
1210 if (!set)
1211 err(EXIT_FAILURE, _("failed to callocate cpu set"));
1212 CPU_ZERO_S(setsize, set);
1213 for (i = 0; i < desc->ncpus; i++) {
1214 if (!is_cpu_online(desc, i))
1215 CPU_SET_S(i, setsize, set);
1216 }
8005924a
KZ
1217 print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") :
1218 _("Off-line CPU(s) list:"),
1219 set, mod->hex);
4f912c6a
KZ
1220 cpuset_free(set);
1221 }
5dd7507c 1222
7e03f383 1223 if (desc->nsockets) {
8648ca96
HC
1224 int cores_per_socket, sockets_per_book, books;
1225
1226 cores_per_socket = sockets_per_book = books = 0;
1227 /* s390 detects its cpu topology via /proc/sysinfo, if present.
1228 * Using simply the cpu topology masks in sysfs will not give
1229 * usable results since everything is virtualized. E.g.
1230 * virtual core 0 may have only 1 cpu, but virtual core 2 may
1231 * five cpus.
1232 * If the cpu topology is not exported (e.g. 2nd level guest)
1233 * fall back to old calculation scheme.
1234 */
1235 if (path_exist(_PATH_PROC_SYSINFO)) {
1236 FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
1237 char buf[BUFSIZ];
1238 int t0, t1, t2;
1239
1240 while (fgets(buf, sizeof(buf), fd) != NULL) {
1241 if (sscanf(buf, "CPU Topology SW:%d%d%d%d%d%d",
1242 &t0, &t1, &t2, &books, &sockets_per_book,
1243 &cores_per_socket) == 6)
1244 break;
1245 }
1246 }
7e03f383 1247 print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores);
8648ca96
HC
1248 print_n(_("Core(s) per socket:"),
1249 cores_per_socket ?: desc->ncores / desc->nsockets);
56baaa4e 1250 if (desc->nbooks) {
8648ca96
HC
1251 print_n(_("Socket(s) per book:"),
1252 sockets_per_book ?: desc->nsockets / desc->nbooks);
1253 print_n(_("Book(s):"), books ?: desc->nbooks);
56baaa4e 1254 } else {
8648ca96 1255 print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets);
56baaa4e 1256 }
5dd7507c 1257 }
7e03f383
KZ
1258 if (desc->nnodes)
1259 print_n(_("NUMA node(s):"), desc->nnodes);
e8aa16ee
KZ
1260 if (desc->vendor)
1261 print_s(_("Vendor ID:"), desc->vendor);
1262 if (desc->family)
1263 print_s(_("CPU family:"), desc->family);
1264 if (desc->model)
1265 print_s(_("Model:"), desc->model);
1266 if (desc->stepping)
1267 print_s(_("Stepping:"), desc->stepping);
1268 if (desc->mhz)
1269 print_s(_("CPU MHz:"), desc->mhz);
9b8d4d5f
DB
1270 if (desc->bogomips)
1271 print_s(_("BogoMIPS:"), desc->bogomips);
e8aa16ee
KZ
1272 if (desc->virtflag) {
1273 if (!strcmp(desc->virtflag, "svm"))
5dd7507c 1274 print_s(_("Virtualization:"), "AMD-V");
e8aa16ee 1275 else if (!strcmp(desc->virtflag, "vmx"))
5dd7507c
CQ
1276 print_s(_("Virtualization:"), "VT-x");
1277 }
e8aa16ee
KZ
1278 if (desc->hyper) {
1279 print_s(_("Hypervisor vendor:"), hv_vendors[desc->hyper]);
1280 print_s(_("Virtualization type:"), virt_types[desc->virtype]);
c8b64f6d 1281 }
a0fff77e
HC
1282 if (desc->dispatching >= 0)
1283 print_s(_("Dispatching mode:"), disp_modes[desc->dispatching]);
7e03f383 1284 if (desc->ncaches) {
c8b64f6d 1285 char buf[512];
5dd7507c
CQ
1286 int i;
1287
7e03f383 1288 for (i = desc->ncaches - 1; i >= 0; i--) {
5dd7507c 1289 snprintf(buf, sizeof(buf),
7e03f383
KZ
1290 _("%s cache:"), desc->caches[i].name);
1291 print_s(buf, desc->caches[i].size);
1292 }
1293 }
1294
4f912c6a
KZ
1295 for (i = 0; i < desc->nnodes; i++) {
1296 snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), i);
8005924a 1297 print_cpuset(buf, desc->nodemaps[i], mod->hex);
5dd7507c
CQ
1298 }
1299}
1300
39561c70 1301static void __attribute__((__noreturn__)) usage(FILE *out)
5dd7507c 1302{
7f1ec5e8
KZ
1303 fputs(_("\nUsage:\n"), out);
1304 fprintf(out,
1305 _(" %s [options]\n"), program_invocation_short_name);
1306
1307 fputs(_("\nOptions:\n"), out);
8005924a
KZ
1308 fputs(_(" -h, --help print this help\n"
1309 " -p, --parse[=<list>] print out a parsable format\n"
ba45d8c1 1310 " -e, --extended[=<list>] print out a extended readable format\n"
8005924a
KZ
1311 " -s, --sysroot <dir> use directory DIR as system root\n"
1312 " -x, --hex print hexadecimal masks rather than lists of CPUs\n"
1313 " -V, --version print version information and exit\n\n"), out);
4f912c6a 1314
39561c70 1315 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
5dd7507c
CQ
1316}
1317
1318int main(int argc, char *argv[])
1319{
8005924a
KZ
1320 struct lscpu_modifier _mod = { .mode = OUTPUT_SUMMARY }, *mod = &_mod;
1321 struct lscpu_desc _desc = { .flags = 0 }, *desc = &_desc;
1322 int c, i;
477251f8 1323 int columns[ARRAY_SIZE(colnames)], ncolumns = 0;
5dd7507c 1324
6c7d5ae9 1325 static const struct option longopts[] = {
47b6e8b6 1326 { "help", no_argument, 0, 'h' },
ba45d8c1 1327 { "extended", optional_argument, 0, 'e' },
477251f8 1328 { "parse", optional_argument, 0, 'p' },
47b6e8b6 1329 { "sysroot", required_argument, 0, 's' },
4f912c6a 1330 { "hex", no_argument, 0, 'x' },
44de912c 1331 { "version", no_argument, 0, 'V' },
5dd7507c
CQ
1332 { NULL, 0, 0, 0 }
1333 };
1334
2f8f1388 1335 setlocale(LC_ALL, "");
5dd7507c
CQ
1336 bindtextdomain(PACKAGE, LOCALEDIR);
1337 textdomain(PACKAGE);
1338
ba45d8c1
KZ
1339 while ((c = getopt_long(argc, argv, "e::hp::s:xV", longopts, NULL)) != -1) {
1340
1341 if (mod->mode != OUTPUT_SUMMARY && strchr("ep", c))
1342 errx(EXIT_FAILURE,
1343 _("extended and parsable are mutually exclusive"));
1344
5dd7507c
CQ
1345 switch (c) {
1346 case 'h':
39561c70 1347 usage(stdout);
5dd7507c 1348 case 'p':
ba45d8c1 1349 case 'e':
477251f8
KZ
1350 if (optarg) {
1351 if (*optarg == '=')
1352 optarg++;
1353 ncolumns = string_to_idarray(optarg,
1354 columns, ARRAY_SIZE(columns),
1355 column_name_to_id);
1356 if (ncolumns < 0)
1357 return EXIT_FAILURE;
477251f8 1358 }
ba45d8c1 1359 mod->mode = c == 'p' ? OUTPUT_PARSABLE : OUTPUT_READABLE;
5dd7507c 1360 break;
47b6e8b6 1361 case 's':
d50363cd 1362 sysrootlen = strlen(optarg);
47b6e8b6 1363 strncpy(pathbuf, optarg, sizeof(pathbuf));
d50363cd 1364 pathbuf[sizeof(pathbuf) - 1] = '\0';
47b6e8b6 1365 break;
4f912c6a 1366 case 'x':
8005924a 1367 mod->hex = 1;
4f912c6a 1368 break;
44de912c
HC
1369 case 'V':
1370 printf(_("%s from %s\n"), program_invocation_short_name,
1371 PACKAGE_STRING);
1372 return EXIT_SUCCESS;
5dd7507c 1373 default:
39561c70 1374 usage(stderr);
5dd7507c
CQ
1375 }
1376 }
1377
e8aa16ee 1378 read_basicinfo(desc);
5dd7507c 1379
7e03f383 1380 for (i = 0; i < desc->ncpus; i++) {
5d4ba40d 1381 if (desc->online && !is_cpu_online(desc, i))
aac1e59e 1382 continue;
7e03f383
KZ
1383 read_topology(desc, i);
1384 read_cache(desc, i);
2b8fcb81 1385 read_polarization(desc, i);
596b8845 1386 read_address(desc, i);
d231eea1 1387 read_configured(desc, i);
47b6e8b6 1388 }
7e03f383
KZ
1389
1390 qsort(desc->caches, desc->ncaches, sizeof(struct cpu_cache), cachecmp);
1391
1392 read_nodes(desc);
e8aa16ee 1393 read_hypervisor(desc);
c8b64f6d 1394
8005924a 1395 switch(mod->mode) {
ba45d8c1
KZ
1396 case OUTPUT_SUMMARY:
1397 print_summary(desc, mod);
1398 break;
1399 case OUTPUT_PARSABLE:
1400 if (!ncolumns) {
1401 columns[ncolumns++] = COL_CPU;
1402 columns[ncolumns++] = COL_CORE;
1403 columns[ncolumns++] = COL_SOCKET;
1404 columns[ncolumns++] = COL_NODE;
1405 columns[ncolumns++] = COL_CACHE;
1406 mod->compat = 1;
1407 }
1408 print_parsable(desc, columns, ncolumns, mod);
1409 break;
1410 case OUTPUT_READABLE:
a7e5300c 1411 mod->allcpus = 1;
ba45d8c1
KZ
1412 if (!ncolumns) {
1413 /* No list was given. Just print whatever is there. */
1414 columns[ncolumns++] = COL_CPU;
1415 if (desc->nodemaps)
8005924a 1416 columns[ncolumns++] = COL_NODE;
ba45d8c1
KZ
1417 if (desc->bookmaps)
1418 columns[ncolumns++] = COL_BOOK;
1419 if (desc->socketmaps)
1420 columns[ncolumns++] = COL_SOCKET;
1421 if (desc->coremaps)
1422 columns[ncolumns++] = COL_CORE;
1423 if (desc->caches)
8005924a 1424 columns[ncolumns++] = COL_CACHE;
a7e5300c
HC
1425 if (desc->online)
1426 columns[ncolumns++] = COL_ONLINE;
d231eea1
HC
1427 if (desc->configured)
1428 columns[ncolumns++] = COL_CONFIGURED;
ba45d8c1
KZ
1429 if (desc->polarization)
1430 columns[ncolumns++] = COL_POLARIZATION;
1431 if (desc->addresses)
1432 columns[ncolumns++] = COL_ADDRESS;
1433 }
1434 print_readable(desc, columns, ncolumns, mod);
1435 break;
8005924a 1436 }
5dd7507c 1437
cf474aac 1438 return EXIT_SUCCESS;
5dd7507c 1439}