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