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