]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/lscpu.c
libsmartcols: clean up flags usage
[thirdparty/util-linux.git] / sys-utils / lscpu.c
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 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
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 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.
20 */
21
22 #include <ctype.h>
23 #include <dirent.h>
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>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include <libsmartcols.h>
37
38 #include "cpuset.h"
39 #include "nls.h"
40 #include "xalloc.h"
41 #include "c.h"
42 #include "strutils.h"
43 #include "bitops.h"
44 #include "path.h"
45 #include "closestream.h"
46 #include "optutils.h"
47 #include "lscpu.h"
48
49 #define CACHE_MAX 100
50
51 /* /sys paths */
52 #define _PATH_SYS_SYSTEM "/sys/devices/system"
53 #define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu"
54 #define _PATH_SYS_NODE _PATH_SYS_SYSTEM "/node"
55 #define _PATH_PROC_XEN "/proc/xen"
56 #define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
57 #define _PATH_PROC_CPUINFO "/proc/cpuinfo"
58 #define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
59 #define _PATH_PROC_SYSINFO "/proc/sysinfo"
60 #define _PATH_PROC_STATUS "/proc/self/status"
61 #define _PATH_PROC_VZ "/proc/vz"
62 #define _PATH_PROC_BC "/proc/bc"
63 #define _PATH_DEV_MEM "/dev/mem"
64
65 /* virtualization types */
66 enum {
67 VIRT_NONE = 0,
68 VIRT_PARA,
69 VIRT_FULL,
70 VIRT_CONT
71 };
72 const char *virt_types[] = {
73 [VIRT_NONE] = N_("none"),
74 [VIRT_PARA] = N_("para"),
75 [VIRT_FULL] = N_("full"),
76 [VIRT_CONT] = N_("container"),
77 };
78
79 const char *hv_vendors[] = {
80 [HYPER_NONE] = NULL,
81 [HYPER_XEN] = "Xen",
82 [HYPER_KVM] = "KVM",
83 [HYPER_MSHV] = "Microsoft",
84 [HYPER_VMWARE] = "VMware",
85 [HYPER_IBM] = "IBM",
86 [HYPER_VSERVER] = "Linux-VServer",
87 [HYPER_UML] = "User-mode Linux",
88 [HYPER_INNOTEK] = "Innotek GmbH",
89 [HYPER_HITACHI] = "Hitachi",
90 [HYPER_PARALLELS] = "Parallels"
91 };
92
93 /* CPU modes */
94 enum {
95 MODE_32BIT = (1 << 1),
96 MODE_64BIT = (1 << 2)
97 };
98
99 /* cache(s) description */
100 struct cpu_cache {
101 char *name;
102 char *size;
103
104 int nsharedmaps;
105 cpu_set_t **sharedmaps;
106 };
107
108 /* dispatching modes */
109 enum {
110 DISP_HORIZONTAL = 0,
111 DISP_VERTICAL = 1
112 };
113
114 const char *disp_modes[] = {
115 [DISP_HORIZONTAL] = N_("horizontal"),
116 [DISP_VERTICAL] = N_("vertical")
117 };
118
119 /* cpu polarization */
120 enum {
121 POLAR_UNKNOWN = 0,
122 POLAR_VLOW,
123 POLAR_VMEDIUM,
124 POLAR_VHIGH,
125 POLAR_HORIZONTAL
126 };
127
128 struct polarization_modes {
129 char *parsable;
130 char *readable;
131 };
132
133 struct polarization_modes polar_modes[] = {
134 [POLAR_UNKNOWN] = {"U", "-"},
135 [POLAR_VLOW] = {"VL", "vert-low"},
136 [POLAR_VMEDIUM] = {"VM", "vert-medium"},
137 [POLAR_VHIGH] = {"VH", "vert-high"},
138 [POLAR_HORIZONTAL] = {"H", "horizontal"},
139 };
140
141 /* global description */
142 struct lscpu_desc {
143 char *arch;
144 char *vendor;
145 char *family;
146 char *model;
147 char *modelname;
148 char *virtflag; /* virtualization flag (vmx, svm) */
149 char *hypervisor; /* hypervisor software */
150 int hyper; /* hypervisor vendor ID */
151 int virtype; /* VIRT_PARA|FULL|NONE ? */
152 char *mhz;
153 char **maxmhz; /* maximum mega hertz */
154 char **minmhz; /* minimum mega hertz */
155 char *stepping;
156 char *bogomips;
157 char *flags;
158 int dispatching; /* none, horizontal or vertical */
159 int mode; /* rm, lm or/and tm */
160
161 int ncpuspos; /* maximal possible CPUs */
162 int ncpus; /* number of present CPUs */
163 cpu_set_t *present; /* mask with present CPUs */
164 cpu_set_t *online; /* mask with online CPUs */
165
166 int nthreads; /* number of online threads */
167
168 int ncaches;
169 struct cpu_cache *caches;
170
171 /*
172 * All maps are sequentially indexed (0..ncpuspos), the array index
173 * does not have match with cpuX number as presented by kernel. You
174 * have to use real_cpu_num() to get the real cpuX number.
175 *
176 * For example, the possible system CPUs are: 1,3,5, it means that
177 * ncpuspos=3, so all arrays are in range 0..3.
178 */
179 int *idx2cpunum; /* mapping index to CPU num */
180
181 int nnodes; /* number of NUMA modes */
182 int *idx2nodenum; /* Support for discontinuous nodes */
183 cpu_set_t **nodemaps; /* array with NUMA nodes */
184
185 /* books -- based on book_siblings (internal kernel map of cpuX's
186 * hardware threads within the same book */
187 int nbooks; /* number of all online books */
188 cpu_set_t **bookmaps; /* unique book_siblings */
189
190 /* sockets -- based on core_siblings (internal kernel map of cpuX's
191 * hardware threads within the same physical_package_id (socket)) */
192 int nsockets; /* number of all online sockets */
193 cpu_set_t **socketmaps; /* unique core_siblings */
194
195 /* cores -- based on thread_siblings (internel kernel map of cpuX's
196 * hardware threads within the same core as cpuX) */
197 int ncores; /* number of all online cores */
198 cpu_set_t **coremaps; /* unique thread_siblings */
199
200 int *polarization; /* cpu polarization */
201 int *addresses; /* physical cpu addresses */
202 int *configured; /* cpu configured */
203 };
204
205 enum {
206 OUTPUT_SUMMARY = 0, /* default */
207 OUTPUT_PARSABLE, /* -p */
208 OUTPUT_READABLE, /* -e */
209 };
210
211 enum {
212 SYSTEM_LIVE = 0, /* analyzing a live system */
213 SYSTEM_SNAPSHOT, /* analyzing a snapshot of a different system */
214 };
215
216 struct lscpu_modifier {
217 int mode; /* OUTPUT_* */
218 int system; /* SYSTEM_* */
219 unsigned int hex:1, /* print CPU masks rather than CPU lists */
220 compat:1, /* use backwardly compatible format */
221 online:1, /* print online CPUs */
222 offline:1; /* print offline CPUs */
223 };
224
225 static int maxcpus; /* size in bits of kernel cpu mask */
226
227 #define is_cpu_online(_d, _cpu) \
228 ((_d) && (_d)->online ? \
229 CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
230 #define is_cpu_present(_d, _cpu) \
231 ((_d) && (_d)->present ? \
232 CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->present) : 0)
233
234 #define real_cpu_num(_d, _i) ((_d)->idx2cpunum[(_i)])
235
236 /*
237 * IDs
238 */
239 enum {
240 COL_CPU,
241 COL_CORE,
242 COL_SOCKET,
243 COL_NODE,
244 COL_BOOK,
245 COL_CACHE,
246 COL_POLARIZATION,
247 COL_ADDRESS,
248 COL_CONFIGURED,
249 COL_ONLINE,
250 COL_MAXMHZ,
251 COL_MINMHZ,
252 };
253
254 /* column description
255 */
256 struct lscpu_coldesc {
257 const char *name;
258 const char *help;
259
260 unsigned int is_abbr:1; /* name is abbreviation */
261 };
262
263 static struct lscpu_coldesc coldescs[] =
264 {
265 [COL_CPU] = { "CPU", N_("logical CPU number"), 1 },
266 [COL_CORE] = { "CORE", N_("logical core number") },
267 [COL_SOCKET] = { "SOCKET", N_("logical socket number") },
268 [COL_NODE] = { "NODE", N_("logical NUMA node number") },
269 [COL_BOOK] = { "BOOK", N_("logical book number") },
270 [COL_CACHE] = { "CACHE", N_("shows how caches are shared between CPUs") },
271 [COL_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
272 [COL_ADDRESS] = { "ADDRESS", N_("physical address of a CPU") },
273 [COL_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") },
274 [COL_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU") },
275 [COL_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU") },
276 [COL_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU") }
277 };
278
279 static int
280 column_name_to_id(const char *name, size_t namesz)
281 {
282 size_t i;
283
284 for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
285 const char *cn = coldescs[i].name;
286
287 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
288 return i;
289 }
290 warnx(_("unknown column: %s"), name);
291 return -1;
292 }
293
294 /* Lookup a pattern and get the value from cpuinfo.
295 * Format is:
296 *
297 * "<pattern> : <key>"
298 */
299 static int
300 lookup(char *line, char *pattern, char **value)
301 {
302 char *p, *v;
303 int len = strlen(pattern);
304
305 if (!*line)
306 return 0;
307
308 /* pattern */
309 if (strncmp(line, pattern, len))
310 return 0;
311
312 /* white spaces */
313 for (p = line + len; isspace(*p); p++);
314
315 /* separator */
316 if (*p != ':')
317 return 0;
318
319 /* white spaces */
320 for (++p; isspace(*p); p++);
321
322 /* value */
323 if (!*p)
324 return 0;
325 v = p;
326
327 /* end of value */
328 len = strlen(line) - 1;
329 for (p = line + len; isspace(*(p-1)); p--);
330 *p = '\0';
331
332 *value = xstrdup(v);
333 return 1;
334 }
335
336 /* Don't init the mode for platforms where we are not able to
337 * detect that CPU supports 64-bit mode.
338 */
339 static int
340 init_mode(struct lscpu_modifier *mod)
341 {
342 int m = 0;
343
344 if (mod->system == SYSTEM_SNAPSHOT)
345 /* reading info from any /{sys,proc} dump, don't mix it with
346 * information about our real CPU */
347 return 0;
348
349 #if defined(__alpha__) || defined(__ia64__)
350 m |= MODE_64BIT; /* 64bit platforms only */
351 #endif
352 /* platforms with 64bit flag in /proc/cpuinfo, define
353 * 32bit default here */
354 #if defined(__i386__) || defined(__x86_64__) || \
355 defined(__s390x__) || defined(__s390__) || defined(__sparc_v9__)
356 m |= MODE_32BIT;
357 #endif
358 return m;
359 }
360
361 static void
362 read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
363 {
364 FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO);
365 char buf[BUFSIZ];
366 struct utsname utsbuf;
367 size_t setsize;
368
369 /* architecture */
370 if (uname(&utsbuf) == -1)
371 err(EXIT_FAILURE, _("error: uname failed"));
372 desc->arch = xstrdup(utsbuf.machine);
373
374 /* details */
375 while (fgets(buf, sizeof(buf), fp) != NULL) {
376 if (lookup(buf, "vendor", &desc->vendor)) ;
377 else if (lookup(buf, "vendor_id", &desc->vendor)) ;
378 else if (lookup(buf, "family", &desc->family)) ;
379 else if (lookup(buf, "cpu family", &desc->family)) ;
380 else if (lookup(buf, "model", &desc->model)) ;
381 else if (lookup(buf, "model name", &desc->modelname)) ;
382 else if (lookup(buf, "stepping", &desc->stepping)) ;
383 else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
384 else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */
385 else if (lookup(buf, "features", &desc->flags)) ; /* s390 */
386 else if (lookup(buf, "type", &desc->flags)) ; /* sparc64 */
387 else if (lookup(buf, "bogomips", &desc->bogomips)) ;
388 else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
389 else
390 continue;
391 }
392
393 desc->mode = init_mode(mod);
394
395 if (desc->flags) {
396 snprintf(buf, sizeof(buf), " %s ", desc->flags);
397 if (strstr(buf, " svm "))
398 desc->virtflag = xstrdup("svm");
399 else if (strstr(buf, " vmx "))
400 desc->virtflag = xstrdup("vmx");
401 if (strstr(buf, " lm "))
402 desc->mode |= MODE_32BIT | MODE_64BIT; /* x86_64 */
403 if (strstr(buf, " zarch "))
404 desc->mode |= MODE_32BIT | MODE_64BIT; /* s390x */
405 if (strstr(buf, " sun4v ") || strstr(buf, " sun4u "))
406 desc->mode |= MODE_32BIT | MODE_64BIT; /* sparc64 */
407 }
408
409 if (desc->arch && mod->system != SYSTEM_SNAPSHOT) {
410 if (strcmp(desc->arch, "ppc64") == 0)
411 desc->mode |= MODE_32BIT | MODE_64BIT;
412 else if (strcmp(desc->arch, "ppc") == 0)
413 desc->mode |= MODE_32BIT;
414 }
415
416 fclose(fp);
417
418 if (path_exist(_PATH_SYS_CPU "/kernel_max"))
419 /* note that kernel_max is maximum index [NR_CPUS-1] */
420 maxcpus = path_read_s32(_PATH_SYS_CPU "/kernel_max") + 1;
421
422 else if (mod->system == SYSTEM_LIVE)
423 /* the root is '/' so we are working with data from the current kernel */
424 maxcpus = get_max_number_of_cpus();
425
426 if (maxcpus <= 0)
427 /* error or we are reading some /sys snapshot instead of the
428 * real /sys, let's use any crazy number... */
429 maxcpus = 2048;
430
431 setsize = CPU_ALLOC_SIZE(maxcpus);
432
433 if (path_exist(_PATH_SYS_CPU "/possible")) {
434 cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/possible");
435 int num, idx;
436
437 desc->ncpuspos = CPU_COUNT_S(setsize, tmp);
438 desc->idx2cpunum = xcalloc(desc->ncpuspos, sizeof(int));
439
440 for (num = 0, idx = 0; num < maxcpus; num++) {
441 if (CPU_ISSET(num, tmp))
442 desc->idx2cpunum[idx++] = num;
443 }
444 cpuset_free(tmp);
445 } else
446 err(EXIT_FAILURE, _("failed to determine number of CPUs: %s"),
447 _PATH_SYS_CPU "/possible");
448
449
450 /* get mask for present CPUs */
451 if (path_exist(_PATH_SYS_CPU "/present")) {
452 desc->present = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/present");
453 desc->ncpus = CPU_COUNT_S(setsize, desc->present);
454 }
455
456 /* get mask for online CPUs */
457 if (path_exist(_PATH_SYS_CPU "/online")) {
458 desc->online = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/online");
459 desc->nthreads = CPU_COUNT_S(setsize, desc->online);
460 }
461
462 /* get dispatching mode */
463 if (path_exist(_PATH_SYS_CPU "/dispatching"))
464 desc->dispatching = path_read_s32(_PATH_SYS_CPU "/dispatching");
465 else
466 desc->dispatching = -1;
467 }
468
469 static int
470 has_pci_device(unsigned int vendor, unsigned int device)
471 {
472 FILE *f;
473 unsigned int num, fn, ven, dev;
474 int res = 1;
475
476 f = path_fopen("r", 0, _PATH_PROC_PCIDEVS);
477 if (!f)
478 return 0;
479
480 /* for more details about bus/pci/devices format see
481 * drivers/pci/proc.c in linux kernel
482 */
483 while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
484 &num, &fn, &ven, &dev) == 4) {
485
486 if (ven == vendor && dev == device)
487 goto found;
488 }
489
490 res = 0;
491 found:
492 fclose(f);
493 return res;
494 }
495
496 #if defined(__x86_64__) || defined(__i386__)
497
498 /*
499 * This CPUID leaf returns the information about the hypervisor.
500 * EAX : maximum input value for CPUID supported by the hypervisor.
501 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
502 */
503 #define HYPERVISOR_INFO_LEAF 0x40000000
504
505 static inline void
506 cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
507 unsigned int *ecx, unsigned int *edx)
508 {
509 __asm__(
510 #if defined(__PIC__) && defined(__i386__)
511 /* x86 PIC cannot clobber ebx -- gcc bitches */
512 "pushl %%ebx;"
513 "cpuid;"
514 "movl %%ebx, %%esi;"
515 "popl %%ebx;"
516 : "=S" (*ebx),
517 #else
518 "cpuid;"
519 : "=b" (*ebx),
520 #endif
521 "=a" (*eax),
522 "=c" (*ecx),
523 "=d" (*edx)
524 : "1" (op), "c"(0));
525 }
526
527 static void
528 read_hypervisor_cpuid(struct lscpu_desc *desc)
529 {
530 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
531 char hyper_vendor_id[13];
532
533 memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
534
535 cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
536 memcpy(hyper_vendor_id + 0, &ebx, 4);
537 memcpy(hyper_vendor_id + 4, &ecx, 4);
538 memcpy(hyper_vendor_id + 8, &edx, 4);
539 hyper_vendor_id[12] = '\0';
540
541 if (!hyper_vendor_id[0])
542 return;
543
544 if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
545 desc->hyper = HYPER_XEN;
546 else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
547 desc->hyper = HYPER_KVM;
548 else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
549 desc->hyper = HYPER_MSHV;
550 else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
551 desc->hyper = HYPER_VMWARE;
552 }
553
554 #else /* ! __x86_64__ */
555 static void
556 read_hypervisor_cpuid(struct lscpu_desc *desc __attribute__((__unused__)))
557 {
558 }
559 #endif
560
561 static void
562 read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
563 {
564 FILE *fd;
565
566 if (mod->system != SYSTEM_SNAPSHOT) {
567 read_hypervisor_cpuid(desc);
568 if (!desc->hyper)
569 desc->hyper = read_hypervisor_dmi();
570 }
571
572 if (desc->hyper)
573 desc->virtype = VIRT_FULL;
574
575 /* Xen para-virt or dom0 */
576 else if (path_exist(_PATH_PROC_XEN)) {
577 int dom0 = 0;
578 fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
579
580 if (fd) {
581 char buf[256];
582
583 if (fscanf(fd, "%s", buf) == 1 &&
584 !strcmp(buf, "control_d"))
585 dom0 = 1;
586 fclose(fd);
587 }
588 desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
589 desc->hyper = HYPER_XEN;
590
591 /* Xen full-virt on non-x86_64 */
592 } else if (has_pci_device(0x5853, 0x0001)) {
593 desc->hyper = HYPER_XEN;
594 desc->virtype = VIRT_FULL;
595
596 /* IBM PR/SM */
597 } else if (path_exist(_PATH_PROC_SYSINFO)) {
598 FILE *sysinfo_fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
599 char buf[BUFSIZ];
600
601 if (!sysinfo_fd)
602 return;
603 desc->hyper = HYPER_IBM;
604 desc->hypervisor = "PR/SM";
605 desc->virtype = VIRT_FULL;
606 while (fgets(buf, sizeof(buf), sysinfo_fd) != NULL) {
607 char *str;
608
609 if (!strstr(buf, "Control Program:"))
610 continue;
611 if (!strstr(buf, "KVM"))
612 desc->hyper = HYPER_IBM;
613 else
614 desc->hyper = HYPER_KVM;
615 str = strchr(buf, ':');
616 if (!str)
617 continue;
618 xasprintf(&str, "%s", str + 1);
619
620 /* remove leading, trailing and repeating whitespace */
621 while (*str == ' ')
622 str++;
623 desc->hypervisor = str;
624 str += strlen(str) - 1;
625 while ((*str == '\n') || (*str == ' '))
626 *(str--) = '\0';
627 while ((str = strstr(desc->hypervisor, " ")))
628 memmove(str, str + 1, strlen(str));
629 }
630 fclose(sysinfo_fd);
631 }
632
633 /* OpenVZ/Virtuozzo - /proc/vz dir should exist
634 * /proc/bc should not */
635 else if (path_exist(_PATH_PROC_VZ) && !path_exist(_PATH_PROC_BC)) {
636 desc->hyper = HYPER_PARALLELS;
637 desc->virtype = VIRT_CONT;
638
639 /* IBM */
640 } else if (desc->vendor &&
641 (strcmp(desc->vendor, "PowerVM Lx86") == 0 ||
642 strcmp(desc->vendor, "IBM/S390") == 0)) {
643 desc->hyper = HYPER_IBM;
644 desc->virtype = VIRT_FULL;
645
646 /* User-mode-linux */
647 } else if (desc->modelname && strstr(desc->modelname, "UML")) {
648 desc->hyper = HYPER_UML;
649 desc->virtype = VIRT_PARA;
650
651 /* Linux-VServer */
652 } else if (path_exist(_PATH_PROC_STATUS)) {
653 char buf[BUFSIZ];
654 char *val = NULL;
655
656 fd = path_fopen("r", 1, _PATH_PROC_STATUS);
657 while (fgets(buf, sizeof(buf), fd) != NULL) {
658 if (lookup(buf, "VxID", &val))
659 break;
660 }
661 fclose(fd);
662
663 if (val) {
664 while (isdigit(*val))
665 ++val;
666 if (!*val) {
667 desc->hyper = HYPER_VSERVER;
668 desc->virtype = VIRT_CONT;
669 }
670 }
671 }
672 }
673
674 /* add @set to the @ary, unnecessary set is deallocated. */
675 static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set)
676 {
677 int i;
678 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
679
680 if (!ary)
681 return -1;
682
683 for (i = 0; i < *items; i++) {
684 if (CPU_EQUAL_S(setsize, set, ary[i]))
685 break;
686 }
687 if (i == *items) {
688 ary[*items] = set;
689 ++*items;
690 return 0;
691 }
692 CPU_FREE(set);
693 return 1;
694 }
695
696 static void
697 read_topology(struct lscpu_desc *desc, int idx)
698 {
699 cpu_set_t *thread_siblings, *core_siblings, *book_siblings;
700 int num = real_cpu_num(desc, idx);
701
702 if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num))
703 return;
704
705 thread_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
706 "/cpu%d/topology/thread_siblings", num);
707 core_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
708 "/cpu%d/topology/core_siblings", num);
709 book_siblings = NULL;
710 if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num))
711 book_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
712 "/cpu%d/topology/book_siblings", num);
713
714 if (!desc->coremaps) {
715 int nbooks, nsockets, ncores, nthreads;
716 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
717
718 /* threads within one core */
719 nthreads = CPU_COUNT_S(setsize, thread_siblings);
720 if (!nthreads)
721 nthreads = 1;
722
723 /* cores within one socket */
724 ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads;
725 if (!ncores)
726 ncores = 1;
727
728 /* number of sockets within one book. Because of odd /
729 * non-present cpu maps and to keep calculation easy we make
730 * sure that nsockets and nbooks is at least 1.
731 */
732 nsockets = desc->ncpus / nthreads / ncores;
733 if (!nsockets)
734 nsockets = 1;
735
736 /* number of books */
737 nbooks = desc->ncpus / nthreads / ncores / nsockets;
738 if (!nbooks)
739 nbooks = 1;
740
741 /* all threads, see also read_basicinfo()
742 * -- fallback for kernels without
743 * /sys/devices/system/cpu/online.
744 */
745 if (!desc->nthreads)
746 desc->nthreads = nbooks * nsockets * ncores * nthreads;
747
748 /* For each map we make sure that it can have up to ncpuspos
749 * entries. This is because we cannot reliably calculate the
750 * number of cores, sockets and books on all architectures.
751 * E.g. completely virtualized architectures like s390 may
752 * have multiple sockets of different sizes.
753 */
754 desc->coremaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
755 desc->socketmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
756 if (book_siblings)
757 desc->bookmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
758 }
759
760 add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
761 add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings);
762 if (book_siblings)
763 add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings);
764 }
765
766 static void
767 read_polarization(struct lscpu_desc *desc, int idx)
768 {
769 char mode[64];
770 int num = real_cpu_num(desc, idx);
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->ncpuspos, sizeof(int));
778 path_read_str(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num);
779 if (strncmp(mode, "vertical:low", sizeof(mode)) == 0)
780 desc->polarization[idx] = POLAR_VLOW;
781 else if (strncmp(mode, "vertical:medium", sizeof(mode)) == 0)
782 desc->polarization[idx] = POLAR_VMEDIUM;
783 else if (strncmp(mode, "vertical:high", sizeof(mode)) == 0)
784 desc->polarization[idx] = POLAR_VHIGH;
785 else if (strncmp(mode, "horizontal", sizeof(mode)) == 0)
786 desc->polarization[idx] = POLAR_HORIZONTAL;
787 else
788 desc->polarization[idx] = POLAR_UNKNOWN;
789 }
790
791 static void
792 read_address(struct lscpu_desc *desc, int idx)
793 {
794 int num = real_cpu_num(desc, idx);
795
796 if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num))
797 return;
798 if (!desc->addresses)
799 desc->addresses = xcalloc(desc->ncpuspos, sizeof(int));
800 desc->addresses[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num);
801 }
802
803 static void
804 read_configured(struct lscpu_desc *desc, int idx)
805 {
806 int num = real_cpu_num(desc, idx);
807
808 if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num))
809 return;
810 if (!desc->configured)
811 desc->configured = xcalloc(desc->ncpuspos, sizeof(int));
812 desc->configured[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num);
813 }
814
815 static void
816 read_max_mhz(struct lscpu_desc *desc, int idx)
817 {
818 int num = real_cpu_num(desc, idx);
819
820 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_max_freq", num))
821 return;
822 if (!desc->maxmhz)
823 desc->maxmhz = xcalloc(desc->ncpuspos, sizeof(char *));
824 xasprintf(&(desc->maxmhz[idx]), "%.4f",
825 (float)path_read_s32(_PATH_SYS_CPU
826 "/cpu%d/cpufreq/cpuinfo_max_freq", num) / 1000);
827 }
828
829 static void
830 read_min_mhz(struct lscpu_desc *desc, int idx)
831 {
832 int num = real_cpu_num(desc, idx);
833
834 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_min_freq", num))
835 return;
836 if (!desc->minmhz)
837 desc->minmhz = xcalloc(desc->ncpuspos, sizeof(char *));
838 xasprintf(&(desc->minmhz[idx]), "%.4f",
839 (float)path_read_s32(_PATH_SYS_CPU
840 "/cpu%d/cpufreq/cpuinfo_min_freq", num) / 1000);
841 }
842
843 static int
844 cachecmp(const void *a, const void *b)
845 {
846 struct cpu_cache *c1 = (struct cpu_cache *) a;
847 struct cpu_cache *c2 = (struct cpu_cache *) b;
848
849 return strcmp(c2->name, c1->name);
850 }
851
852 static void
853 read_cache(struct lscpu_desc *desc, int idx)
854 {
855 char buf[256];
856 int i;
857 int num = real_cpu_num(desc, idx);
858
859 if (!desc->ncaches) {
860 while(path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
861 num, desc->ncaches))
862 desc->ncaches++;
863
864 if (!desc->ncaches)
865 return;
866
867 desc->caches = xcalloc(desc->ncaches, sizeof(*desc->caches));
868 }
869 for (i = 0; i < desc->ncaches; i++) {
870 struct cpu_cache *ca = &desc->caches[i];
871 cpu_set_t *map;
872
873 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
874 num, i))
875 continue;
876 if (!ca->name) {
877 int type, level;
878
879 /* cache type */
880 path_read_str(buf, sizeof(buf),
881 _PATH_SYS_CPU "/cpu%d/cache/index%d/type",
882 num, i);
883 if (!strcmp(buf, "Data"))
884 type = 'd';
885 else if (!strcmp(buf, "Instruction"))
886 type = 'i';
887 else
888 type = 0;
889
890 /* cache level */
891 level = path_read_s32(_PATH_SYS_CPU "/cpu%d/cache/index%d/level",
892 num, i);
893 if (type)
894 snprintf(buf, sizeof(buf), "L%d%c", level, type);
895 else
896 snprintf(buf, sizeof(buf), "L%d", level);
897
898 ca->name = xstrdup(buf);
899
900 /* cache size */
901 if (path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d/size",num, i)) {
902 path_read_str(buf, sizeof(buf),
903 _PATH_SYS_CPU "/cpu%d/cache/index%d/size", num, i);
904 ca->size = xstrdup(buf);
905 } else {
906 ca->size = xstrdup("unknown size");
907 }
908 }
909
910 /* information about how CPUs share different caches */
911 map = path_read_cpuset(maxcpus,
912 _PATH_SYS_CPU "/cpu%d/cache/index%d/shared_cpu_map",
913 num, i);
914
915 if (!ca->sharedmaps)
916 ca->sharedmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
917 add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
918 }
919 }
920
921 static inline int is_node_dirent(struct dirent *d)
922 {
923 return
924 d &&
925 #ifdef _DIRENT_HAVE_D_TYPE
926 (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN) &&
927 #endif
928 strncmp(d->d_name, "node", 4) == 0 &&
929 isdigit_string(d->d_name + 4);
930 }
931
932 static int
933 nodecmp(const void *ap, const void *bp)
934 {
935 int *a = (int *) ap, *b = (int *) bp;
936 return *a - *b;
937 }
938
939 static void
940 read_nodes(struct lscpu_desc *desc)
941 {
942 int i = 0;
943 DIR *dir;
944 struct dirent *d;
945 char *path;
946
947 /* number of NUMA node */
948 path = path_strdup(_PATH_SYS_NODE);
949 dir = opendir(path);
950 free(path);
951
952 while (dir && (d = readdir(dir))) {
953 if (is_node_dirent(d))
954 desc->nnodes++;
955 }
956
957 if (!desc->nnodes) {
958 if (dir)
959 closedir(dir);
960 return;
961 }
962
963 desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *));
964 desc->idx2nodenum = xmalloc(desc->nnodes * sizeof(int));
965
966 if (dir) {
967 rewinddir(dir);
968 while ((d = readdir(dir)) && i < desc->nnodes) {
969 if (is_node_dirent(d))
970 desc->idx2nodenum[i++] = strtol_or_err(((d->d_name) + 4),
971 _("Failed to extract the node number"));
972 }
973 closedir(dir);
974 qsort(desc->idx2nodenum, desc->nnodes, sizeof(int), nodecmp);
975 }
976
977 /* information about how nodes share different CPUs */
978 for (i = 0; i < desc->nnodes; i++)
979 desc->nodemaps[i] = path_read_cpuset(maxcpus,
980 _PATH_SYS_NODE "/node%d/cpumap",
981 desc->idx2nodenum[i]);
982 }
983
984 static char *
985 get_cell_data(struct lscpu_desc *desc, int idx, int col,
986 struct lscpu_modifier *mod,
987 char *buf, size_t bufsz)
988 {
989 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
990 size_t i;
991 int cpu = real_cpu_num(desc, idx);
992
993 *buf = '\0';
994
995 switch (col) {
996 case COL_CPU:
997 snprintf(buf, bufsz, "%d", cpu);
998 break;
999 case COL_CORE:
1000 if (cpuset_ary_isset(cpu, desc->coremaps,
1001 desc->ncores, setsize, &i) == 0)
1002 snprintf(buf, bufsz, "%zd", i);
1003 break;
1004 case COL_SOCKET:
1005 if (cpuset_ary_isset(cpu, desc->socketmaps,
1006 desc->nsockets, setsize, &i) == 0)
1007 snprintf(buf, bufsz, "%zd", i);
1008 break;
1009 case COL_NODE:
1010 if (cpuset_ary_isset(cpu, desc->nodemaps,
1011 desc->nnodes, setsize, &i) == 0)
1012 snprintf(buf, bufsz, "%d", desc->idx2nodenum[i]);
1013 break;
1014 case COL_BOOK:
1015 if (cpuset_ary_isset(cpu, desc->bookmaps,
1016 desc->nbooks, setsize, &i) == 0)
1017 snprintf(buf, bufsz, "%zd", i);
1018 break;
1019 case COL_CACHE:
1020 {
1021 char *p = buf;
1022 size_t sz = bufsz;
1023 int j;
1024
1025 for (j = desc->ncaches - 1; j >= 0; j--) {
1026 struct cpu_cache *ca = &desc->caches[j];
1027
1028 if (cpuset_ary_isset(cpu, ca->sharedmaps,
1029 ca->nsharedmaps, setsize, &i) == 0) {
1030 int x = snprintf(p, sz, "%zd", i);
1031 if (x <= 0 || (size_t) x + 2 >= sz)
1032 return NULL;
1033 p += x;
1034 sz -= x;
1035 }
1036 if (j != 0) {
1037 *p++ = mod->compat ? ',' : ':';
1038 *p = '\0';
1039 sz++;
1040 }
1041 }
1042 break;
1043 }
1044 case COL_POLARIZATION:
1045 if (desc->polarization) {
1046 int x = desc->polarization[idx];
1047
1048 snprintf(buf, bufsz, "%s",
1049 mod->mode == OUTPUT_PARSABLE ?
1050 polar_modes[x].parsable :
1051 polar_modes[x].readable);
1052 }
1053 break;
1054 case COL_ADDRESS:
1055 if (desc->addresses)
1056 snprintf(buf, bufsz, "%d", desc->addresses[idx]);
1057 break;
1058 case COL_CONFIGURED:
1059 if (!desc->configured)
1060 break;
1061 if (mod->mode == OUTPUT_PARSABLE)
1062 snprintf(buf, bufsz,
1063 desc->configured[idx] ? _("Y") : _("N"));
1064 else
1065 snprintf(buf, bufsz,
1066 desc->configured[idx] ? _("yes") : _("no"));
1067 break;
1068 case COL_ONLINE:
1069 if (!desc->online)
1070 break;
1071 if (mod->mode == OUTPUT_PARSABLE)
1072 snprintf(buf, bufsz,
1073 is_cpu_online(desc, cpu) ? _("Y") : _("N"));
1074 else
1075 snprintf(buf, bufsz,
1076 is_cpu_online(desc, cpu) ? _("yes") : _("no"));
1077 break;
1078 case COL_MAXMHZ:
1079 if (desc->maxmhz)
1080 xstrncpy(buf, desc->maxmhz[idx], bufsz);
1081 break;
1082 case COL_MINMHZ:
1083 if (desc->minmhz)
1084 xstrncpy(buf, desc->minmhz[idx], bufsz);
1085 break;
1086 }
1087 return buf;
1088 }
1089
1090 static char *
1091 get_cell_header(struct lscpu_desc *desc, int col,
1092 struct lscpu_modifier *mod,
1093 char *buf, size_t bufsz)
1094 {
1095 *buf = '\0';
1096
1097 if (col == COL_CACHE) {
1098 char *p = buf;
1099 size_t sz = bufsz;
1100 int i;
1101
1102 for (i = desc->ncaches - 1; i >= 0; i--) {
1103 int x = snprintf(p, sz, "%s", desc->caches[i].name);
1104 if (x <= 0 || (size_t) x + 2 > sz)
1105 return NULL;
1106 sz -= x;
1107 p += x;
1108 if (i > 0) {
1109 *p++ = mod->compat ? ',' : ':';
1110 *p = '\0';
1111 sz++;
1112 }
1113 }
1114 if (desc->ncaches)
1115 return buf;
1116 }
1117 snprintf(buf, bufsz, "%s", coldescs[col].name);
1118 return buf;
1119 }
1120
1121 /*
1122 * [-p] backend, we support two parsable formats:
1123 *
1124 * 1) "compatible" -- this format is compatible with the original lscpu(1)
1125 * output and it contains fixed set of the columns. The CACHE columns are at
1126 * the end of the line and the CACHE is not printed if the number of the caches
1127 * is zero. The CACHE columns are separated by two commas, for example:
1128 *
1129 * $ lscpu --parse
1130 * # CPU,Core,Socket,Node,,L1d,L1i,L2
1131 * 0,0,0,0,,0,0,0
1132 * 1,1,0,0,,1,1,0
1133 *
1134 * 2) "user defined output" -- this format prints always all columns without
1135 * special prefix for CACHE column. If there are not CACHEs then the column is
1136 * empty and the header "Cache" is printed rather than a real name of the cache.
1137 * The CACHE columns are separated by ':'.
1138 *
1139 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
1140 * # CPU,Core,Socket,Node,L1d:L1i:L2
1141 * 0,0,0,0,0:0:0
1142 * 1,1,0,0,1:1:0
1143 */
1144 static void
1145 print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
1146 struct lscpu_modifier *mod)
1147 {
1148 char buf[BUFSIZ], *data;
1149 int i;
1150
1151 /*
1152 * Header
1153 */
1154 printf(_(
1155 "# The following is the parsable format, which can be fed to other\n"
1156 "# programs. Each different item in every column has an unique ID\n"
1157 "# starting from zero.\n"));
1158
1159 fputs("# ", stdout);
1160 for (i = 0; i < ncols; i++) {
1161 int col = cols[i];
1162
1163 if (col == COL_CACHE) {
1164 if (mod->compat && !desc->ncaches)
1165 continue;
1166 if (mod->compat && i != 0)
1167 putchar(',');
1168 }
1169 if (i > 0)
1170 putchar(',');
1171
1172 data = get_cell_header(desc, col, mod, buf, sizeof(buf));
1173
1174 if (data && * data && col != COL_CACHE &&
1175 !coldescs[col].is_abbr) {
1176 /*
1177 * For normal column names use mixed case (e.g. "Socket")
1178 */
1179 char *p = data + 1;
1180
1181 while (p && *p != '\0') {
1182 *p = tolower((unsigned int) *p);
1183 p++;
1184 }
1185 }
1186 fputs(data && *data ? data : "", stdout);
1187 }
1188 putchar('\n');
1189
1190 /*
1191 * Data
1192 */
1193 for (i = 0; i < desc->ncpuspos; i++) {
1194 int c;
1195 int cpu = real_cpu_num(desc, i);
1196
1197 if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
1198 continue;
1199 if (!mod->online && desc->online && is_cpu_online(desc, cpu))
1200 continue;
1201 if (desc->present && !is_cpu_present(desc, cpu))
1202 continue;
1203 for (c = 0; c < ncols; c++) {
1204 if (mod->compat && cols[c] == COL_CACHE) {
1205 if (!desc->ncaches)
1206 continue;
1207 if (c > 0)
1208 putchar(',');
1209 }
1210 if (c > 0)
1211 putchar(',');
1212
1213 data = get_cell_data(desc, i, cols[c], mod,
1214 buf, sizeof(buf));
1215 fputs(data && *data ? data : "", stdout);
1216 }
1217 putchar('\n');
1218 }
1219 }
1220
1221 /*
1222 * [-e] backend
1223 */
1224 static void
1225 print_readable(struct lscpu_desc *desc, int cols[], int ncols,
1226 struct lscpu_modifier *mod)
1227 {
1228 int i;
1229 char buf[BUFSIZ];
1230 const char *data;
1231 struct libscols_table *table = scols_new_table();
1232
1233 if (!table)
1234 err(EXIT_FAILURE, _("failed to initialize output table"));
1235
1236 for (i = 0; i < ncols; i++) {
1237 data = get_cell_header(desc, cols[i], mod, buf, sizeof(buf));
1238 if (!scols_table_new_column(table, xstrdup(data), 0, 0))
1239 err(EXIT_FAILURE, _("failed to initialize output column"));
1240 }
1241
1242 for (i = 0; i < desc->ncpuspos; i++) {
1243 int c;
1244 struct libscols_line *line;
1245 int cpu = real_cpu_num(desc, i);
1246
1247 if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
1248 continue;
1249 if (!mod->online && desc->online && is_cpu_online(desc, cpu))
1250 continue;
1251 if (desc->present && !is_cpu_present(desc, cpu))
1252 continue;
1253
1254 line = scols_table_new_line(table, NULL);
1255 if (!line)
1256 err(EXIT_FAILURE, _("failed to initialize output line"));
1257
1258 for (c = 0; c < ncols; c++) {
1259 data = get_cell_data(desc, i, cols[c], mod,
1260 buf, sizeof(buf));
1261 if (!data || !*data)
1262 data = "-";
1263 scols_line_set_data(line, c, data);
1264 }
1265 }
1266
1267 scols_print_table(table);
1268 scols_unref_table(table);
1269 }
1270
1271 /* output formats "<key> <value>"*/
1272 #define print_s(_key, _val) printf("%-23s%s\n", _key, _val)
1273 #define print_n(_key, _val) printf("%-23s%d\n", _key, _val)
1274
1275 static void
1276 print_cpuset(const char *key, cpu_set_t *set, int hex)
1277 {
1278 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
1279 size_t setbuflen = 7 * maxcpus;
1280 char setbuf[setbuflen], *p;
1281
1282 if (hex) {
1283 p = cpumask_create(setbuf, setbuflen, set, setsize);
1284 printf("%-23s0x%s\n", key, p);
1285 } else {
1286 p = cpulist_create(setbuf, setbuflen, set, setsize);
1287 print_s(key, p);
1288 }
1289
1290 }
1291
1292 /*
1293 * default output
1294 */
1295 static void
1296 print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
1297 {
1298 char buf[512];
1299 int i;
1300 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
1301
1302 print_s(_("Architecture:"), desc->arch);
1303
1304 if (desc->mode) {
1305 char mbuf[64], *p = mbuf;
1306
1307 if (desc->mode & MODE_32BIT) {
1308 strcpy(p, "32-bit, ");
1309 p += 8;
1310 }
1311 if (desc->mode & MODE_64BIT) {
1312 strcpy(p, "64-bit, ");
1313 p += 8;
1314 }
1315 *(p - 2) = '\0';
1316 print_s(_("CPU op-mode(s):"), mbuf);
1317 }
1318 #if !defined(WORDS_BIGENDIAN)
1319 print_s(_("Byte Order:"), "Little Endian");
1320 #else
1321 print_s(_("Byte Order:"), "Big Endian");
1322 #endif
1323 print_n(_("CPU(s):"), desc->ncpus);
1324
1325 if (desc->online)
1326 print_cpuset(mod->hex ? _("On-line CPU(s) mask:") :
1327 _("On-line CPU(s) list:"),
1328 desc->online, mod->hex);
1329
1330 if (desc->online && CPU_COUNT_S(setsize, desc->online) != desc->ncpus) {
1331 cpu_set_t *set;
1332
1333 /* Linux kernel provides cpuset of off-line CPUs that contains
1334 * all configured CPUs (see /sys/devices/system/cpu/offline),
1335 * but want to print real (present in system) off-line CPUs only.
1336 */
1337 set = cpuset_alloc(maxcpus, NULL, NULL);
1338 if (!set)
1339 err(EXIT_FAILURE, _("failed to callocate cpu set"));
1340 CPU_ZERO_S(setsize, set);
1341 for (i = 0; i < desc->ncpuspos; i++) {
1342 int cpu = real_cpu_num(desc, i);
1343 if (!is_cpu_online(desc, cpu) && is_cpu_present(desc, cpu))
1344 CPU_SET_S(cpu, setsize, set);
1345 }
1346 print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") :
1347 _("Off-line CPU(s) list:"),
1348 set, mod->hex);
1349 cpuset_free(set);
1350 }
1351
1352 if (desc->nsockets) {
1353 int cores_per_socket, sockets_per_book, books;
1354
1355 cores_per_socket = sockets_per_book = books = 0;
1356 /* s390 detects its cpu topology via /proc/sysinfo, if present.
1357 * Using simply the cpu topology masks in sysfs will not give
1358 * usable results since everything is virtualized. E.g.
1359 * virtual core 0 may have only 1 cpu, but virtual core 2 may
1360 * five cpus.
1361 * If the cpu topology is not exported (e.g. 2nd level guest)
1362 * fall back to old calculation scheme.
1363 */
1364 if (path_exist(_PATH_PROC_SYSINFO)) {
1365 FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
1366 char pbuf[BUFSIZ];
1367 int t0, t1, t2;
1368
1369 while (fd && fgets(pbuf, sizeof(pbuf), fd) != NULL) {
1370 if (sscanf(pbuf, "CPU Topology SW:%d%d%d%d%d%d",
1371 &t0, &t1, &t2, &books, &sockets_per_book,
1372 &cores_per_socket) == 6)
1373 break;
1374 }
1375 if (fd)
1376 fclose(fd);
1377 }
1378 print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores);
1379 print_n(_("Core(s) per socket:"),
1380 cores_per_socket ?: desc->ncores / desc->nsockets);
1381 if (desc->nbooks) {
1382 print_n(_("Socket(s) per book:"),
1383 sockets_per_book ?: desc->nsockets / desc->nbooks);
1384 print_n(_("Book(s):"), books ?: desc->nbooks);
1385 } else {
1386 print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets);
1387 }
1388 }
1389 if (desc->nnodes)
1390 print_n(_("NUMA node(s):"), desc->nnodes);
1391 if (desc->vendor)
1392 print_s(_("Vendor ID:"), desc->vendor);
1393 if (desc->family)
1394 print_s(_("CPU family:"), desc->family);
1395 if (desc->model)
1396 print_s(_("Model:"), desc->model);
1397 if (desc->modelname)
1398 print_s(_("Model name:"), desc->modelname);
1399 if (desc->stepping)
1400 print_s(_("Stepping:"), desc->stepping);
1401 if (desc->mhz)
1402 print_s(_("CPU MHz:"), desc->mhz);
1403 if (desc->maxmhz)
1404 print_s(_("CPU max MHz:"), desc->maxmhz[0]);
1405 if (desc->minmhz)
1406 print_s(_("CPU min MHz:"), desc->minmhz[0]);
1407 if (desc->bogomips)
1408 print_s(_("BogoMIPS:"), desc->bogomips);
1409 if (desc->virtflag) {
1410 if (!strcmp(desc->virtflag, "svm"))
1411 print_s(_("Virtualization:"), "AMD-V");
1412 else if (!strcmp(desc->virtflag, "vmx"))
1413 print_s(_("Virtualization:"), "VT-x");
1414 }
1415 if (desc->hypervisor)
1416 print_s(_("Hypervisor:"), desc->hypervisor);
1417 if (desc->hyper) {
1418 print_s(_("Hypervisor vendor:"), hv_vendors[desc->hyper]);
1419 print_s(_("Virtualization type:"), _(virt_types[desc->virtype]));
1420 }
1421 if (desc->dispatching >= 0)
1422 print_s(_("Dispatching mode:"), _(disp_modes[desc->dispatching]));
1423 if (desc->ncaches) {
1424 char cbuf[512];
1425
1426 for (i = desc->ncaches - 1; i >= 0; i--) {
1427 snprintf(cbuf, sizeof(cbuf),
1428 _("%s cache:"), desc->caches[i].name);
1429 print_s(cbuf, desc->caches[i].size);
1430 }
1431 }
1432
1433 for (i = 0; i < desc->nnodes; i++) {
1434 snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]);
1435 print_cpuset(buf, desc->nodemaps[i], mod->hex);
1436 }
1437 }
1438
1439 static void __attribute__((__noreturn__)) usage(FILE *out)
1440 {
1441 size_t i;
1442
1443 fputs(USAGE_HEADER, out);
1444 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
1445
1446 fputs(USAGE_OPTIONS, out);
1447 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out);
1448 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out);
1449 fputs(_(" -c, --offline print offline CPUs only\n"), out);
1450 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out);
1451 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out);
1452 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out);
1453 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out);
1454 fputs(USAGE_SEPARATOR, out);
1455 fputs(USAGE_HELP, out);
1456 fputs(USAGE_VERSION, out);
1457
1458 fprintf(out, _("\nAvailable columns:\n"));
1459
1460 for (i = 0; i < ARRAY_SIZE(coldescs); i++)
1461 fprintf(out, " %13s %s\n", coldescs[i].name, _(coldescs[i].help));
1462
1463 fprintf(out, _("\nFor more details see lscpu(1).\n"));
1464
1465 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
1466 }
1467
1468 int main(int argc, char *argv[])
1469 {
1470 struct lscpu_modifier _mod = { .mode = OUTPUT_SUMMARY }, *mod = &_mod;
1471 struct lscpu_desc _desc = { .flags = 0 }, *desc = &_desc;
1472 int c, i;
1473 int columns[ARRAY_SIZE(coldescs)], ncolumns = 0;
1474 int cpu_modifier_specified = 0;
1475
1476 static const struct option longopts[] = {
1477 { "all", no_argument, 0, 'a' },
1478 { "online", no_argument, 0, 'b' },
1479 { "offline", no_argument, 0, 'c' },
1480 { "help", no_argument, 0, 'h' },
1481 { "extended", optional_argument, 0, 'e' },
1482 { "parse", optional_argument, 0, 'p' },
1483 { "sysroot", required_argument, 0, 's' },
1484 { "hex", no_argument, 0, 'x' },
1485 { "version", no_argument, 0, 'V' },
1486 { NULL, 0, 0, 0 }
1487 };
1488
1489 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
1490 { 'a','b','c' },
1491 { 'e','p' },
1492 { 0 }
1493 };
1494 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1495
1496 setlocale(LC_ALL, "");
1497 bindtextdomain(PACKAGE, LOCALEDIR);
1498 textdomain(PACKAGE);
1499 atexit(close_stdout);
1500
1501 while ((c = getopt_long(argc, argv, "abce::hp::s:xV", longopts, NULL)) != -1) {
1502
1503 err_exclusive_options(c, longopts, excl, excl_st);
1504
1505 switch (c) {
1506 case 'a':
1507 mod->online = mod->offline = 1;
1508 cpu_modifier_specified = 1;
1509 break;
1510 case 'b':
1511 mod->online = 1;
1512 cpu_modifier_specified = 1;
1513 break;
1514 case 'c':
1515 mod->offline = 1;
1516 cpu_modifier_specified = 1;
1517 break;
1518 case 'h':
1519 usage(stdout);
1520 case 'p':
1521 case 'e':
1522 if (optarg) {
1523 if (*optarg == '=')
1524 optarg++;
1525 ncolumns = string_to_idarray(optarg,
1526 columns, ARRAY_SIZE(columns),
1527 column_name_to_id);
1528 if (ncolumns < 0)
1529 return EXIT_FAILURE;
1530 }
1531 mod->mode = c == 'p' ? OUTPUT_PARSABLE : OUTPUT_READABLE;
1532 break;
1533 case 's':
1534 path_set_prefix(optarg);
1535 mod->system = SYSTEM_SNAPSHOT;
1536 break;
1537 case 'x':
1538 mod->hex = 1;
1539 break;
1540 case 'V':
1541 printf(_("%s from %s\n"), program_invocation_short_name,
1542 PACKAGE_STRING);
1543 return EXIT_SUCCESS;
1544 default:
1545 usage(stderr);
1546 }
1547 }
1548
1549 if (cpu_modifier_specified && mod->mode == OUTPUT_SUMMARY) {
1550 fprintf(stderr,
1551 _("%s: options --all, --online and --offline may only "
1552 "be used with options --extended or --parse.\n"),
1553 program_invocation_short_name);
1554 return EXIT_FAILURE;
1555 }
1556
1557 if (argc != optind)
1558 usage(stderr);
1559
1560 /* set default cpu display mode if none was specified */
1561 if (!mod->online && !mod->offline) {
1562 mod->online = 1;
1563 mod->offline = mod->mode == OUTPUT_READABLE ? 1 : 0;
1564 }
1565
1566 read_basicinfo(desc, mod);
1567
1568 for (i = 0; i < desc->ncpuspos; i++) {
1569 read_topology(desc, i);
1570 read_cache(desc, i);
1571 read_polarization(desc, i);
1572 read_address(desc, i);
1573 read_configured(desc, i);
1574 read_max_mhz(desc, i);
1575 read_min_mhz(desc, i);
1576 }
1577
1578 if (desc->caches)
1579 qsort(desc->caches, desc->ncaches,
1580 sizeof(struct cpu_cache), cachecmp);
1581
1582 read_nodes(desc);
1583 read_hypervisor(desc, mod);
1584
1585 switch(mod->mode) {
1586 case OUTPUT_SUMMARY:
1587 print_summary(desc, mod);
1588 break;
1589 case OUTPUT_PARSABLE:
1590 if (!ncolumns) {
1591 columns[ncolumns++] = COL_CPU;
1592 columns[ncolumns++] = COL_CORE;
1593 columns[ncolumns++] = COL_SOCKET;
1594 columns[ncolumns++] = COL_NODE;
1595 columns[ncolumns++] = COL_CACHE;
1596 mod->compat = 1;
1597 }
1598 print_parsable(desc, columns, ncolumns, mod);
1599 break;
1600 case OUTPUT_READABLE:
1601 if (!ncolumns) {
1602 /* No list was given. Just print whatever is there. */
1603 columns[ncolumns++] = COL_CPU;
1604 if (desc->nodemaps)
1605 columns[ncolumns++] = COL_NODE;
1606 if (desc->bookmaps)
1607 columns[ncolumns++] = COL_BOOK;
1608 if (desc->socketmaps)
1609 columns[ncolumns++] = COL_SOCKET;
1610 if (desc->coremaps)
1611 columns[ncolumns++] = COL_CORE;
1612 if (desc->caches)
1613 columns[ncolumns++] = COL_CACHE;
1614 if (desc->online)
1615 columns[ncolumns++] = COL_ONLINE;
1616 if (desc->configured)
1617 columns[ncolumns++] = COL_CONFIGURED;
1618 if (desc->polarization)
1619 columns[ncolumns++] = COL_POLARIZATION;
1620 if (desc->addresses)
1621 columns[ncolumns++] = COL_ADDRESS;
1622 if (desc->maxmhz)
1623 columns[ncolumns++] = COL_MAXMHZ;
1624 if (desc->minmhz)
1625 columns[ncolumns++] = COL_MINMHZ;
1626 }
1627 print_readable(desc, columns, ncolumns, mod);
1628 break;
1629 }
1630
1631 return EXIT_SUCCESS;
1632 }