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