2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
10 * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com>
12 * lscpu - CPU architecture information helper
23 #include <sys/utsname.h>
26 #include <sys/types.h>
28 #include <sys/personality.h>
30 #include <libsmartcols.h>
32 #include "closestream.h"
39 static const char *virt_types
[] = {
40 [VIRT_TYPE_NONE
] = N_("none"),
41 [VIRT_TYPE_PARA
] = N_("para"),
42 [VIRT_TYPE_FULL
] = N_("full"),
43 [VIRT_TYPE_CONTAINER
] = N_("container"),
46 static const char *hv_vendors
[] = {
47 [VIRT_VENDOR_NONE
] = NULL
,
48 [VIRT_VENDOR_XEN
] = "Xen",
49 [VIRT_VENDOR_KVM
] = "KVM",
50 [VIRT_VENDOR_MSHV
] = "Microsoft",
51 [VIRT_VENDOR_VMWARE
] = "VMware",
52 [VIRT_VENDOR_IBM
] = "IBM",
53 [VIRT_VENDOR_VSERVER
] = "Linux-VServer",
54 [VIRT_VENDOR_UML
] = "User-mode Linux",
55 [VIRT_VENDOR_INNOTEK
] = "Innotek GmbH",
56 [VIRT_VENDOR_HITACHI
] = "Hitachi",
57 [VIRT_VENDOR_PARALLELS
] = "Parallels",
58 [VIRT_VENDOR_VBOX
] = "Oracle",
59 [VIRT_VENDOR_OS400
] = "OS/400",
60 [VIRT_VENDOR_PHYP
] = "pHyp",
61 [VIRT_VENDOR_SPAR
] = "Unisys s-Par",
62 [VIRT_VENDOR_WSL
] = "Windows Subsystem for Linux"
65 /* dispatching modes */
66 static const char *disp_modes
[] = {
67 [DISP_HORIZONTAL
] = N_("horizontal"),
68 [DISP_VERTICAL
] = N_("vertical")
71 struct polarization_modes
{
76 static struct polarization_modes polar_modes
[] = {
77 [POLAR_UNKNOWN
] = {"U", "-"},
78 [POLAR_VLOW
] = {"VL", "vert-low"},
79 [POLAR_VMEDIUM
] = {"VM", "vert-medium"},
80 [POLAR_VHIGH
] = {"VH", "vert-high"},
81 [POLAR_HORIZONTAL
] = {"H", "horizontal"},
119 COL_CACHE_COHERENCYSIZE
123 /* column description
125 struct lscpu_coldesc
{
130 unsigned int is_abbr
:1; /* name is abbreviation */
134 static struct lscpu_coldesc coldescs_cpu
[] =
136 [COL_CPU_BOGOMIPS
] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT
, 1, SCOLS_JSON_NUMBER
},
137 [COL_CPU_CPU
] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT
, 1, SCOLS_JSON_NUMBER
},
138 [COL_CPU_CORE
] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
139 [COL_CPU_CLUSTER
] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
140 [COL_CPU_SOCKET
] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
141 [COL_CPU_NODE
] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
142 [COL_CPU_BOOK
] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
143 [COL_CPU_DRAWER
] = { "DRAWER", N_("logical drawer number"), SCOLS_FL_RIGHT
, SCOLS_JSON_NUMBER
},
144 [COL_CPU_CACHE
] = { "CACHE", N_("shows how caches are shared between CPUs") },
145 [COL_CPU_POLARIZATION
] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
146 [COL_CPU_ADDRESS
] = { "ADDRESS", N_("physical address of a CPU") },
147 [COL_CPU_CONFIGURED
] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU"), 0, 0, SCOLS_JSON_BOOLEAN_OPTIONAL
},
148 [COL_CPU_ONLINE
] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_BOOLEAN_OPTIONAL
},
149 [COL_CPU_MHZ
] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
150 [COL_CPU_SCALMHZ
] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT
, SCOLS_JSON_NUMBER
},
151 [COL_CPU_MAXMHZ
] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
152 [COL_CPU_MINMHZ
] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
153 [COL_CPU_MODELNAME
] = { "MODELNAME", N_("shows CPU model name"), 0, 0, SCOLS_JSON_STRING
}
156 static struct lscpu_coldesc coldescs_cache
[] =
158 [COL_CACHE_ALLSIZE
] = { "ALL-SIZE", N_("size of all system caches"), SCOLS_FL_RIGHT
},
159 [COL_CACHE_LEVEL
] = { "LEVEL", N_("cache level"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
160 [COL_CACHE_NAME
] = { "NAME", N_("cache name") },
161 [COL_CACHE_ONESIZE
] = { "ONE-SIZE", N_("size of one cache"), SCOLS_FL_RIGHT
},
162 [COL_CACHE_TYPE
] = { "TYPE", N_("cache type") },
163 [COL_CACHE_WAYS
] = { "WAYS", N_("ways of associativity"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
164 [COL_CACHE_ALLOCPOL
] = { "ALLOC-POLICY", N_("allocation policy") },
165 [COL_CACHE_WRITEPOL
] = { "WRITE-POLICY", N_("write policy") },
166 [COL_CACHE_PHYLINE
] = { "PHY-LINE", N_("number of physical cache line per cache tag"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
167 [COL_CACHE_SETS
] = { "SETS", N_("number of sets in the cache; set lines has the same cache index"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
168 [COL_CACHE_COHERENCYSIZE
] = { "COHERENCY-SIZE", N_("minimum amount of data in bytes transferred from memory to cache"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
}
171 static int hierarchic
= -1;
173 UL_DEBUG_DEFINE_MASK(lscpu
);
174 UL_DEBUG_DEFINE_MASKNAMES(lscpu
) = UL_DEBUG_EMPTY_MASKNAMES
;
176 static void lscpu_init_debug(void)
178 __UL_INIT_DEBUG_FROM_ENV(lscpu
, LSCPU_DEBUG_
, 0, LSCPU_DEBUG
);
182 cpu_column_name_to_id(const char *name
, size_t namesz
)
186 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++) {
187 const char *cn
= coldescs_cpu
[i
].name
;
189 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
192 warnx(_("unknown column: %s"), name
);
197 cache_column_name_to_id(const char *name
, size_t namesz
)
201 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++) {
202 const char *cn
= coldescs_cache
[i
].name
;
204 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
207 warnx(_("unknown column: %s"), name
);
211 static void lscpu_context_init_paths(struct lscpu_cxt
*cxt
)
213 DBG(MISC
, ul_debugobj(cxt
, "initialize paths"));
214 ul_path_init_debug();
219 cxt
->rootfs
= ul_new_path("/");
221 err(EXIT_FAILURE
, _("failed to initialize rootfs handler"));
222 ul_path_set_prefix(cxt
->rootfs
, cxt
->prefix
);
225 /* /sys/devices/system/cpu */
226 cxt
->syscpu
= ul_new_path(_PATH_SYS_CPU
);
228 err(EXIT_FAILURE
, _("failed to initialize CPUs sysfs handler"));
230 ul_path_set_prefix(cxt
->syscpu
, cxt
->prefix
);
233 cxt
->procfs
= ul_new_path("/proc");
235 err(EXIT_FAILURE
, _("failed to initialize procfs handler"));
237 ul_path_set_prefix(cxt
->procfs
, cxt
->prefix
);
240 static struct lscpu_cxt
*lscpu_new_context(void)
242 return xcalloc(1, sizeof(struct lscpu_cxt
));
245 static void lscpu_free_context(struct lscpu_cxt
*cxt
)
252 DBG(MISC
, ul_debugobj(cxt
, "freeing context"));
254 DBG(MISC
, ul_debugobj(cxt
, " de-initialize paths"));
255 ul_unref_path(cxt
->syscpu
);
256 ul_unref_path(cxt
->procfs
);
257 ul_unref_path(cxt
->rootfs
);
259 DBG(MISC
, ul_debugobj(cxt
, " freeing cpus"));
260 for (i
= 0; i
< cxt
->npossibles
; i
++) {
261 lscpu_unref_cpu(cxt
->cpus
[i
]);
264 DBG(MISC
, ul_debugobj(cxt
, " freeing types"));
265 for (i
= 0; i
< cxt
->ncputypes
; i
++) {
266 lscpu_unref_cputype(cxt
->cputypes
[i
]);
267 cxt
->cputypes
[i
] = NULL
;
275 for (i
= 0; i
< cxt
->nvuls
; i
++) {
276 free(cxt
->vuls
[i
].name
);
277 free(cxt
->vuls
[i
].text
);
281 for (i
= 0; i
< cxt
->nnodes
; i
++)
282 free(cxt
->nodemaps
[i
]);
285 free(cxt
->idx2nodenum
);
287 lscpu_free_virtualization(cxt
->virt
);
288 lscpu_free_architecture(cxt
->arch
);
290 lscpu_free_caches(cxt
->ecaches
, cxt
->necaches
);
291 lscpu_free_caches(cxt
->caches
, cxt
->ncaches
);
296 static void __fill_id( struct lscpu_cxt
*cxt
,
297 struct lscpu_cpu
*cpu
,
298 int id
, cpu_set_t
**map
,
300 char *buf
, size_t bufsz
)
304 if (cxt
->show_physical
) {
306 snprintf(buf
, bufsz
, "-");
308 snprintf(buf
, bufsz
, "%d", id
);
312 if (cpuset_ary_isset(cpu
->logical_id
, map
, nitems
,
313 cxt
->setsize
, &i
) == 0)
314 snprintf(buf
, bufsz
, "%zu", i
);
318 static void get_cell_boolean(
319 struct lscpu_cxt
*cxt
,
320 int has_data
, int data
,
321 char *buf
, size_t bufsz
)
326 if (cxt
->mode
== LSCPU_OUTPUT_PARSABLE
|| cxt
->json
)
327 snprintf(buf
, bufsz
, "%s",
328 data
? _("Y") : _("N"));
330 snprintf(buf
, bufsz
, "%s",
331 data
? _("yes") : _("no"));
334 #define fill_id(_cxt, _cpu, NAME, _buf, _bufsz) \
335 __fill_id(_cxt, (_cpu), \
336 (_cpu)-> NAME ## id, \
337 (_cpu)->type-> NAME ## maps, \
338 (_cpu)->type->n ## NAME ## s, \
341 static char *get_cell_data(
342 struct lscpu_cxt
*cxt
,
343 struct lscpu_cpu
*cpu
, int col
,
344 char *buf
, size_t bufsz
)
355 snprintf(buf
, bufsz
, "%d", cpu
->logical_id
);
357 case COL_CPU_BOGOMIPS
:
358 if (!cpu
->bogomips
&& !cpu
->type
->bogomips
)
360 snprintf(buf
, bufsz
, "%.2f", (float) c_strtod(
361 cpu
->bogomips
? : cpu
->type
->bogomips
, NULL
));
364 fill_id(cxt
, cpu
, core
, buf
, bufsz
);
367 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
369 case COL_CPU_CLUSTER
:
371 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
374 fill_id(cxt
, cpu
, drawer
, buf
, bufsz
);
377 fill_id(cxt
, cpu
, book
, buf
, bufsz
);
380 if (cpuset_ary_isset(cpu
->logical_id
, cxt
->nodemaps
,
381 cxt
->nnodes
, cxt
->setsize
, &i
) == 0)
382 snprintf(buf
, bufsz
, "%d", cxt
->idx2nodenum
[i
]);
386 const char *last
= NULL
;
390 for (i
= 0; i
< cxt
->ncaches
; i
++) {
392 struct lscpu_cache
*ca
;
393 const char *name
= cxt
->caches
[i
].name
;
395 if (last
&& strcmp(last
, name
) == 0)
398 ca
= lscpu_cpu_get_cache(cxt
, cpu
, name
);
401 x
= snprintf(p
, sz
, "%d", ca
->id
);
402 if (x
< 0 || (size_t) x
>= sz
)
408 *p
++ = cxt
->show_compatible
? ',' : ':';
412 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
416 case COL_CPU_POLARIZATION
:
417 if (cpu
->polarization
< 0)
419 snprintf(buf
, bufsz
, "%s",
420 cxt
->mode
== LSCPU_OUTPUT_PARSABLE
?
421 polar_modes
[cpu
->polarization
].parsable
:
422 polar_modes
[cpu
->polarization
].readable
);
424 case COL_CPU_ADDRESS
:
425 if (cpu
->address
< 0)
427 snprintf(buf
, bufsz
, "%d", cpu
->address
);
429 case COL_CPU_CONFIGURED
:
430 get_cell_boolean(cxt
, cpu
->configured
>= 0, cpu
->configured
, buf
, bufsz
);
433 get_cell_boolean(cxt
, !!cxt
->online
, is_cpu_online(cxt
, cpu
), buf
, bufsz
);
436 if (cpu
->mhz_cur_freq
)
437 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_cur_freq
);
439 case COL_CPU_SCALMHZ
:
440 if (cpu
->mhz_cur_freq
&& cpu
->mhz_max_freq
)
441 snprintf(buf
, bufsz
, "%.0f%%", cpu
->mhz_cur_freq
/ cpu
->mhz_max_freq
* 100);
444 if (cpu
->mhz_max_freq
)
445 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_max_freq
);
448 if (cpu
->mhz_min_freq
)
449 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_min_freq
);
451 case COL_CPU_MODELNAME
:
452 if (cpu
->type
&& cpu
->type
->modelname
)
453 xstrncpy(buf
, cpu
->type
->modelname
, bufsz
);
459 static char *get_cell_header(
460 struct lscpu_cxt
*cxt
, int col
,
461 char *buf
, size_t bufsz
)
465 if (col
== COL_CPU_CACHE
) {
466 const char *last
= NULL
;
471 for (i
= 0; i
< cxt
->ncaches
; i
++) {
472 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
475 if (last
&& strcmp(last
, ca
->name
) == 0)
479 x
= snprintf(p
, sz
, "%s", ca
->name
);
480 if (x
< 0 || (size_t) x
>= sz
)
486 *p
++ = cxt
->show_compatible
? ',' : ':';
490 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
495 snprintf(buf
, bufsz
, "%s", coldescs_cpu
[col
].name
);
500 static void caches_add_line(struct lscpu_cxt
*cxt
,
501 struct libscols_table
*tb
,
502 struct lscpu_cache
*ca
,
503 int cols
[], size_t ncols
)
505 struct libscols_line
*ln
;
508 ln
= scols_table_new_line(tb
, NULL
);
510 err(EXIT_FAILURE
, _("failed to allocate output line"));
512 for (c
= 0; c
< ncols
; c
++) {
519 data
= xstrdup(ca
->name
);
521 case COL_CACHE_ONESIZE
:
525 xasprintf(&data
, "%" PRIu64
, ca
->size
);
527 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, ca
->size
);
529 case COL_CACHE_ALLSIZE
:
533 sz
= lscpu_get_cache_full_size(cxt
, ca
->name
, NULL
);
537 xasprintf(&data
, "%" PRIu64
, sz
);
539 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, sz
);
543 if (ca
->ways_of_associativity
)
544 xasprintf(&data
, "%u", ca
->ways_of_associativity
);
549 data
= xstrdup(ca
->type
);
551 case COL_CACHE_LEVEL
:
553 xasprintf(&data
, "%d", ca
->level
);
555 case COL_CACHE_ALLOCPOL
:
556 if (ca
->allocation_policy
)
557 data
= xstrdup(ca
->allocation_policy
);
559 case COL_CACHE_WRITEPOL
:
560 if (ca
->write_policy
)
561 data
= xstrdup(ca
->write_policy
);
563 case COL_CACHE_PHYLINE
:
564 if (ca
->physical_line_partition
)
565 xasprintf(&data
, "%u", ca
->physical_line_partition
);
568 if (ca
->number_of_sets
)
569 xasprintf(&data
, "%u", ca
->number_of_sets
);
571 case COL_CACHE_COHERENCYSIZE
:
572 if (ca
->coherency_line_size
)
573 xasprintf(&data
, "%u", ca
->coherency_line_size
);
577 if (data
&& scols_line_refer_data(ln
, c
, data
))
578 err(EXIT_FAILURE
, _("failed to add output data"));
586 static void print_caches_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
589 struct libscols_table
*tb
;
590 const char *last
= NULL
;
594 tb
= scols_new_table();
596 err(EXIT_FAILURE
, _("failed to allocate output table"));
598 scols_table_enable_json(tb
, 1);
599 scols_table_set_name(tb
, "caches");
602 for (i
= 0; i
< ncols
; i
++) {
603 struct lscpu_coldesc
*cd
= &coldescs_cache
[cols
[i
]];
604 struct libscols_column
*cl
;
606 cl
= scols_table_new_column(tb
, cd
->name
, 0, cd
->flags
);
608 err(EXIT_FAILURE
, _("failed to allocate output column"));
610 scols_column_set_json_type(cl
, cd
->json_type
);
613 /* standard caches */
614 for (i
= 0; i
< cxt
->ncaches
; i
++) {
615 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
617 if (last
&& strcmp(last
, ca
->name
) == 0)
620 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
624 for (i
= 0; i
< cxt
->necaches
; i
++) {
625 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
627 if (last
&& strcmp(last
, ca
->name
) == 0)
630 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
633 scols_print_table(tb
);
634 scols_unref_table(tb
);
638 * [-p] backend, we support two parsable formats:
640 * 1) "compatible" -- this format is compatible with the original lscpu(1)
641 * output and it contains fixed set of the columns. The CACHE columns are at
642 * the end of the line and the CACHE is not printed if the number of the caches
643 * is zero. The CACHE columns are separated by two commas, for example:
646 * # CPU,Core,Socket,Node,,L1d,L1i,L2
650 * 2) "user defined output" -- this format prints always all columns without
651 * special prefix for CACHE column. If there are not CACHEs then the column is
652 * empty and the header "Cache" is printed rather than a real name of the cache.
653 * The CACHE columns are separated by ':'.
655 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
656 * # CPU,Core,Socket,Node,L1d:L1i:L2
660 static void print_cpus_parsable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
662 char buf
[BUFSIZ
], *data
;
669 "# The following is the parsable format, which can be fed to other\n"
670 "# programs. Each different item in every column has an unique ID\n"
671 "# starting usually from zero.\n"));
674 for (i
= 0; i
< ncols
; i
++) {
677 if (col
== COL_CPU_CACHE
) {
678 if (cxt
->show_compatible
&& !cxt
->ncaches
)
680 if (cxt
->show_compatible
&& i
!= 0)
686 data
= get_cell_header(cxt
, col
, buf
, sizeof(buf
));
687 if (data
&& * data
&& col
!= COL_CPU_CACHE
&&
688 !coldescs_cpu
[col
].is_abbr
) {
690 * For normal column names use mixed case (e.g. "Socket")
694 while (p
&& *p
!= '\0') {
695 *p
= tolower((unsigned int) *p
);
699 fputs(data
&& *data
? data
: "", stdout
);
706 for (i
= 0; i
< cxt
->npossibles
; i
++) {
707 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
711 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
713 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
716 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
719 for (c
= 0; c
< ncols
; c
++) {
720 if (cxt
->show_compatible
&& cols
[c
] == COL_CPU_CACHE
) {
729 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
730 fputs(data
&& *data
? data
: "", stdout
);
740 static void print_cpus_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
745 struct libscols_table
*tb
;
749 tb
= scols_new_table();
751 err(EXIT_FAILURE
, _("failed to allocate output table"));
753 scols_table_enable_json(tb
, 1);
754 scols_table_set_name(tb
, "cpus");
757 for (i
= 0; i
< ncols
; i
++) {
758 data
= get_cell_header(cxt
, cols
[i
], buf
, sizeof(buf
));
759 struct lscpu_coldesc
*cd
= &coldescs_cpu
[cols
[i
]];
760 struct libscols_column
*cl
;
762 cl
= scols_table_new_column(tb
, data
, 0, cd
->flags
);
764 err(EXIT_FAILURE
, _("failed to allocate output column"));
766 scols_column_set_json_type(cl
, cd
->json_type
);
769 for (i
= 0; i
< cxt
->npossibles
; i
++) {
771 struct libscols_line
*ln
;
772 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
775 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
777 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
781 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
784 ln
= scols_table_new_line(tb
, NULL
);
786 err(EXIT_FAILURE
, _("failed to allocate output line"));
788 for (c
= 0; c
< ncols
; c
++) {
789 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
792 if (scols_line_set_data(ln
, c
, data
))
793 err(EXIT_FAILURE
, _("failed to add output data"));
797 scols_print_table(tb
);
798 scols_unref_table(tb
);
801 static struct libscols_line
*
802 __attribute__ ((__format__(printf
, 4, 5)))
803 add_summary_sprint(struct libscols_table
*tb
,
804 struct libscols_line
*sec
,
809 struct libscols_line
*ln
;
812 /* Don't print section lines without data */
813 if (!hierarchic
&& fmt
== NULL
)
816 ln
= scols_table_new_line(tb
, sec
);
818 err(EXIT_FAILURE
, _("failed to allocate output line"));
820 /* description column */
821 if (txt
&& scols_line_set_data(ln
, 0, txt
))
822 err(EXIT_FAILURE
, _("failed to add output data"));
828 xvasprintf(&data
, fmt
, args
);
831 if (data
&& scols_line_refer_data(ln
, 1, data
))
832 err(EXIT_FAILURE
, _("failed to add output data"));
838 #define add_summary_e(tb, sec, txt) add_summary_sprint(tb, sec, txt, NULL)
839 #define add_summary_n(tb, sec, txt, num) add_summary_sprint(tb, sec, txt, "%zu", num)
840 #define add_summary_s(tb, sec, txt, str) add_summary_sprint(tb, sec, txt, "%s", str)
841 #define add_summary_x(tb, sec, txt, fmt, x) add_summary_sprint(tb, sec, txt, fmt, x)
844 print_cpuset(struct lscpu_cxt
*cxt
,
845 struct libscols_table
*tb
,
846 struct libscols_line
*sec
,
847 const char *key
, cpu_set_t
*set
)
849 size_t setbuflen
= 7 * cxt
->maxcpus
;
857 setbuf
= xmalloc(setbuflen
);
860 p
= cpumask_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
861 add_summary_s(tb
, sec
, key
, p
);
863 p
= cpulist_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
864 add_summary_s(tb
, sec
, key
, p
);
871 print_summary_cputype(struct lscpu_cxt
*cxt
,
872 struct lscpu_cputype
*ct
,
873 struct libscols_table
*tb
,
874 struct libscols_line
*sec
)
876 sec
= add_summary_s(tb
, sec
, _("Model name:"), ct
->modelname
? ct
->modelname
: "-");
877 if (ct
->bios_modelname
)
878 add_summary_s(tb
, sec
, _("BIOS Model name:"), ct
->bios_modelname
);
880 add_summary_s(tb
, sec
, _("BIOS CPU family:"), ct
->bios_family
);
882 add_summary_s(tb
, sec
, _("Machine type:"), ct
->machinetype
);
884 add_summary_s(tb
, sec
, _("CPU family:"), ct
->family
);
885 if (ct
->model
|| ct
->revision
)
886 add_summary_s(tb
, sec
, _("Model:"), ct
->revision
? ct
->revision
: ct
->model
);
888 add_summary_n(tb
, sec
, _("Thread(s) per core:"), ct
->nthreads_per_core
);
890 add_summary_n(tb
, sec
, _("Core(s) per cluster:"), ct
->ncores_per_socket
);
892 add_summary_n(tb
, sec
, _("Core(s) per socket:"), ct
->ncores_per_socket
);
895 add_summary_n(tb
, sec
, _("Socket(s) per book:"), ct
->nsockets_per_book
);
896 if (ct
->ndrawers_per_system
|| ct
->ndrawers
) {
897 add_summary_n(tb
, sec
, _("Book(s) per drawer:"), ct
->nbooks_per_drawer
);
898 add_summary_n(tb
, sec
, _("Drawer(s):"), ct
->ndrawers_per_system
?: ct
->ndrawers
);
900 add_summary_n(tb
, sec
, _("Book(s):"), ct
->nbooks_per_drawer
?: ct
->nbooks
);
902 if (cxt
->is_cluster
) {
903 if (ct
->nr_socket_on_cluster
> 0)
904 add_summary_n(tb
, sec
, _("Socket(s):"), ct
->nr_socket_on_cluster
);
906 add_summary_s(tb
, sec
, _("Socket(s):"), "-");
908 add_summary_n(tb
, sec
, _("Cluster(s):"),
909 ct
->nsockets_per_book
?: ct
->nsockets
);
911 add_summary_n(tb
, sec
, _("Socket(s):"),
912 ct
->nsockets_per_book
?: ct
->nsockets
);
916 add_summary_s(tb
, sec
, _("Stepping:"), ct
->stepping
);
917 if (ct
->freqboost
>= 0)
918 add_summary_s(tb
, sec
, _("Frequency boost:"), ct
->freqboost
?
919 _("enabled") : _("disabled"));
921 /* s390 -- from the first CPU where is dynamic/static MHz */
923 add_summary_s(tb
, sec
, _("CPU dynamic MHz:"), ct
->dynamic_mhz
);
925 add_summary_s(tb
, sec
, _("CPU static MHz:"), ct
->static_mhz
);
928 float scal
= lsblk_cputype_get_scalmhz(cxt
, ct
);
930 add_summary_x(tb
, sec
, _("CPU(s) scaling MHz:"), "%.0f%%", scal
);
931 add_summary_x(tb
, sec
, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt
, ct
));
932 add_summary_x(tb
, sec
, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt
, ct
));
935 add_summary_x(tb
, sec
, _("BogoMIPS:"), "%.2f", (float) c_strtod(ct
->bogomips
, NULL
));
937 if (ct
->dispatching
>= 0)
938 add_summary_s(tb
, sec
, _("Dispatching mode:"), _(disp_modes
[ct
->dispatching
]));
940 if (ct
->physsockets
) {
941 add_summary_n(tb
, sec
, _("Physical sockets:"), ct
->physsockets
);
942 add_summary_n(tb
, sec
, _("Physical chips:"), ct
->physchips
);
943 add_summary_n(tb
, sec
, _("Physical cores/chip:"), ct
->physcoresperchip
);
947 add_summary_s(tb
, sec
, _("Flags:"), ct
->flags
);
953 static void print_summary(struct lscpu_cxt
*cxt
)
955 struct lscpu_cputype
*ct
;
958 struct libscols_table
*tb
;
959 struct libscols_line
*sec
;
964 tb
= scols_new_table();
966 err(EXIT_FAILURE
, _("failed to allocate output table"));
968 scols_table_enable_noheadings(tb
, 1);
970 scols_table_enable_json(tb
, 1);
971 scols_table_set_name(tb
, "lscpu");
972 } else if (hierarchic
) {
973 struct libscols_symbols
*sy
= scols_new_symbols();
977 scols_symbols_set_branch(sy
, " ");
978 scols_symbols_set_vertical(sy
, " ");
979 scols_symbols_set_right(sy
, " ");
980 scols_table_set_symbols(tb
, sy
);
981 scols_unref_symbols(sy
);
984 if (scols_table_new_column(tb
, "field", 0, hierarchic
? SCOLS_FL_TREE
: 0) == NULL
||
985 scols_table_new_column(tb
, "data", 0, SCOLS_FL_NOEXTREMES
| SCOLS_FL_WRAP
) == NULL
)
986 err(EXIT_FAILURE
, _("failed to initialize output column"));
988 ct
= lscpu_cputype_get_default(cxt
);
990 /* Section: architecture */
991 sec
= add_summary_s(tb
, NULL
, _("Architecture:"), cxt
->arch
->name
);
992 if (cxt
->arch
->bit32
|| cxt
->arch
->bit64
) {
993 char buf
[32], *p
= buf
;
995 if (cxt
->arch
->bit32
) {
996 strcpy(p
, "32-bit, ");
999 if (cxt
->arch
->bit64
) {
1000 strcpy(p
, "64-bit, ");
1004 add_summary_s(tb
, sec
, _("CPU op-mode(s):"), buf
);
1006 if (ct
&& ct
->addrsz
)
1007 add_summary_s(tb
, sec
, _("Address sizes:"), ct
->addrsz
);
1009 if (sysfs_get_byteorder(cxt
->rootfs
) == SYSFS_BYTEORDER_LITTLE
)
1010 add_summary_s(tb
, sec
, _("Byte Order:"), "Little Endian");
1012 add_summary_s(tb
, sec
, _("Byte Order:"), "Big Endian");
1014 /* Section: CPU lists */
1015 sec
= add_summary_n(tb
, NULL
, _("CPU(s):"), cxt
->npresents
);
1018 print_cpuset(cxt
, tb
, sec
,
1019 cxt
->hex
? _("On-line CPU(s) mask:") :
1020 _("On-line CPU(s) list:"),
1023 if (cxt
->online
&& cxt
->nonlines
!= cxt
->npresents
) {
1026 /* Linux kernel provides cpuset of off-line CPUs that contains
1027 * all configured CPUs (see /sys/devices/system/cpu/offline),
1028 * but want to print real (present in system) off-line CPUs only.
1030 set
= cpuset_alloc(cxt
->maxcpus
, NULL
, NULL
);
1032 err(EXIT_FAILURE
, _("failed to callocate cpu set"));
1033 CPU_ZERO_S(cxt
->setsize
, set
);
1034 for (i
= 0; i
< cxt
->npossibles
; i
++) {
1035 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
1037 if (cpu
&& is_cpu_present(cxt
, cpu
) && !is_cpu_online(cxt
, cpu
))
1038 CPU_SET_S(cpu
->logical_id
, cxt
->setsize
, set
);
1040 print_cpuset(cxt
, tb
, sec
,
1041 cxt
->hex
? _("Off-line CPU(s) mask:") :
1042 _("Off-line CPU(s) list:"), set
);
1047 /* Section: cpu type description */
1048 if (ct
&& ct
->vendor
)
1049 sec
= add_summary_s(tb
, NULL
, _("Vendor ID:"), ct
->vendor
);
1050 if (ct
&& ct
->bios_vendor
)
1051 add_summary_s(tb
, sec
, _("BIOS Vendor ID:"), ct
->bios_vendor
);
1053 for (i
= 0; i
< cxt
->ncputypes
; i
++)
1054 print_summary_cputype(cxt
, cxt
->cputypes
[i
], tb
, sec
);
1057 /* Section: vitualiazation */
1059 sec
= add_summary_e(tb
, NULL
, _("Virtualization features:"));
1060 if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "svm"))
1061 add_summary_s(tb
, sec
, _("Virtualization:"), "AMD-V");
1062 else if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "vmx"))
1063 add_summary_s(tb
, sec
, _("Virtualization:"), "VT-x");
1065 if (cxt
->virt
->hypervisor
)
1066 add_summary_s(tb
, sec
, _("Hypervisor:"), cxt
->virt
->hypervisor
);
1067 if (cxt
->virt
->vendor
) {
1068 add_summary_s(tb
, sec
, _("Hypervisor vendor:"), hv_vendors
[cxt
->virt
->vendor
]);
1069 add_summary_s(tb
, sec
, _("Virtualization type:"), _(virt_types
[cxt
->virt
->type
]));
1074 /* Section: caches */
1076 const char *last
= NULL
;
1078 /* The caches are sorted by name, cxt->caches[] may contains
1079 * multiple instances for the same name.
1081 for (i
= 0; i
< cxt
->ncaches
; i
++) {
1082 const char *name
= cxt
->caches
[i
].name
;
1086 if (last
&& strcmp(last
, name
) == 0)
1088 sz
= lscpu_get_cache_full_size(cxt
, name
, &n
);
1092 sec
= add_summary_e(tb
, NULL
, _("Caches (sum of all):"));
1096 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), name
);
1098 add_summary_sprint(tb
, sec
, field
,
1099 P_("%" PRIu64
" (%d instance)",
1100 "%" PRIu64
" (%d instances)", n
),
1103 char *tmp
= size_to_human_string(
1104 SIZE_SUFFIX_3LETTER
|
1107 add_summary_sprint(tb
, sec
, field
,
1108 P_("%s (%d instance)",
1109 "%s (%d instances)", n
),
1117 for (i
= 0; i
< cxt
->necaches
; i
++) {
1118 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
1123 sec
= add_summary_e(tb
, NULL
, _("Caches:"));
1126 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), ca
->name
);
1128 add_summary_x(tb
, sec
, field
, "%" PRIu64
, ca
->size
);
1130 char *tmp
= size_to_human_string(
1131 SIZE_SUFFIX_3LETTER
|
1134 add_summary_s(tb
, sec
, field
, tmp
);
1140 /* Section: NUMA modes */
1142 sec
= add_summary_e(tb
, NULL
, _("NUMA:"));
1144 add_summary_n(tb
, sec
,_("NUMA node(s):"), cxt
->nnodes
);
1145 for (i
= 0; i
< cxt
->nnodes
; i
++) {
1146 snprintf(field
, sizeof(field
), _("NUMA node%d CPU(s):"), cxt
->idx2nodenum
[i
]);
1147 print_cpuset(cxt
, tb
, sec
, field
, cxt
->nodemaps
[i
]);
1152 /* Section: Vulnerabilities */
1154 sec
= add_summary_e(tb
, NULL
, _("Vulnerabilities:"));
1156 for (i
= 0; i
< cxt
->nvuls
; i
++) {
1157 snprintf(field
, sizeof(field
), hierarchic
?
1158 _("%s:") : _("Vulnerability %s:"), cxt
->vuls
[i
].name
);
1159 add_summary_s(tb
, sec
, field
, cxt
->vuls
[i
].text
);
1163 scols_print_table(tb
);
1164 scols_unref_table(tb
);
1167 static void __attribute__((__noreturn__
)) usage(void)
1172 fputs(USAGE_HEADER
, out
);
1173 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
1175 fputs(USAGE_SEPARATOR
, out
);
1176 fputs(_("Display information about the CPU architecture.\n"), out
);
1178 fputs(USAGE_OPTIONS
, out
);
1179 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out
);
1180 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out
);
1181 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out
);
1182 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out
);
1183 fputs(_(" -c, --offline print offline CPUs only\n"), out
);
1184 fputs(_(" -J, --json use JSON for default or extended format\n"), out
);
1185 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out
);
1186 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out
);
1187 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out
);
1188 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out
);
1189 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out
);
1190 fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out
);
1191 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out
);
1192 fputs(USAGE_SEPARATOR
, out
);
1193 fprintf(out
, USAGE_HELP_OPTIONS(25));
1195 fputs(_("\nAvailable output columns for -e or -p:\n"), out
);
1196 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++)
1197 fprintf(out
, " %13s %s\n", coldescs_cpu
[i
].name
, _(coldescs_cpu
[i
].help
));
1199 fputs(_("\nAvailable output columns for -C:\n"), out
);
1200 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++)
1201 fprintf(out
, " %13s %s\n", coldescs_cache
[i
].name
, _(coldescs_cache
[i
].help
));
1203 fprintf(out
, USAGE_MAN_TAIL("lscpu(1)"));
1208 int main(int argc
, char *argv
[])
1210 struct lscpu_cxt
*cxt
;
1212 int columns
[ARRAY_SIZE(coldescs_cpu
)];
1213 int cpu_modifier_specified
= 0;
1214 char *outarg
= NULL
;
1215 size_t i
, ncolumns
= 0;
1217 OPT_OUTPUT_ALL
= CHAR_MAX
+ 1,
1220 static const struct option longopts
[] = {
1221 { "all", no_argument
, NULL
, 'a' },
1222 { "online", no_argument
, NULL
, 'b' },
1223 { "bytes", no_argument
, NULL
, 'B' },
1224 { "caches", optional_argument
, NULL
, 'C' },
1225 { "offline", no_argument
, NULL
, 'c' },
1226 { "help", no_argument
, NULL
, 'h' },
1227 { "extended", optional_argument
, NULL
, 'e' },
1228 { "json", no_argument
, NULL
, 'J' },
1229 { "parse", optional_argument
, NULL
, 'p' },
1230 { "sysroot", required_argument
, NULL
, 's' },
1231 { "physical", no_argument
, NULL
, 'y' },
1232 { "hex", no_argument
, NULL
, 'x' },
1233 { "version", no_argument
, NULL
, 'V' },
1234 { "output-all", no_argument
, NULL
, OPT_OUTPUT_ALL
},
1235 { "hierarchic", optional_argument
, NULL
, OPT_HIERARCHIC
},
1236 { NULL
, 0, NULL
, 0 }
1239 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
1244 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1246 setlocale(LC_ALL
, "");
1247 bindtextdomain(PACKAGE
, LOCALEDIR
);
1248 textdomain(PACKAGE
);
1249 close_stdout_atexit();
1251 cxt
= lscpu_new_context();
1253 while ((c
= getopt_long(argc
, argv
, "aBbC::ce::hJp::s:xyV", longopts
, NULL
)) != -1) {
1255 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1259 cxt
->show_online
= cxt
->show_offline
= 1;
1260 cpu_modifier_specified
= 1;
1266 cxt
->show_online
= 1;
1267 cpu_modifier_specified
= 1;
1270 cxt
->show_offline
= 1;
1271 cpu_modifier_specified
= 1;
1279 cxt
->mode
= LSCPU_OUTPUT_CACHES
;
1291 cxt
->mode
= c
== 'p' ? LSCPU_OUTPUT_PARSABLE
: LSCPU_OUTPUT_READABLE
;
1294 cxt
->prefix
= optarg
;
1301 cxt
->show_physical
= 1;
1303 case OPT_OUTPUT_ALL
:
1306 case OPT_HIERARCHIC
:
1308 if (strcmp(optarg
, "auto") == 0)
1310 else if (strcmp(optarg
, "never") == 0)
1312 else if (strcmp(optarg
, "always") == 0)
1315 errx(EXIT_FAILURE
, _("unsupported --flat argument"));
1322 print_version(EXIT_SUCCESS
);
1324 errtryhelp(EXIT_FAILURE
);
1328 if (all
&& ncolumns
== 0) {
1329 size_t maxsz
= cxt
->mode
== LSCPU_OUTPUT_CACHES
?
1330 ARRAY_SIZE(coldescs_cache
) :
1331 ARRAY_SIZE(coldescs_cpu
);
1333 for (i
= 0; i
< maxsz
; i
++)
1334 columns
[ncolumns
++] = i
;
1337 if (cpu_modifier_specified
&& cxt
->mode
== LSCPU_OUTPUT_SUMMARY
) {
1339 _("%s: options --all, --online and --offline may only "
1340 "be used with options --extended or --parse.\n"),
1341 program_invocation_short_name
);
1342 return EXIT_FAILURE
;
1345 if (argc
!= optind
) {
1346 warnx(_("bad usage"));
1347 errtryhelp(EXIT_FAILURE
);
1350 /* set default cpu display mode if none was specified */
1351 if (!cxt
->show_online
&& !cxt
->show_offline
) {
1352 cxt
->show_online
= 1;
1353 cxt
->show_offline
= cxt
->mode
== LSCPU_OUTPUT_READABLE
? 1 : 0;
1359 lscpu_context_init_paths(cxt
);
1361 lscpu_read_cpulists(cxt
);
1362 lscpu_read_cpuinfo(cxt
);
1363 cxt
->arch
= lscpu_read_architecture(cxt
);
1365 lscpu_read_archext(cxt
);
1366 lscpu_read_vulnerabilities(cxt
);
1367 lscpu_read_numas(cxt
);
1368 lscpu_read_topology(cxt
);
1370 lscpu_decode_arm(cxt
);
1372 cxt
->virt
= lscpu_read_virtualization(cxt
);
1374 if (hierarchic
== -1)
1375 hierarchic
= isatty(STDOUT_FILENO
); /* default */
1378 case LSCPU_OUTPUT_SUMMARY
:
1381 case LSCPU_OUTPUT_CACHES
:
1383 columns
[ncolumns
++] = COL_CACHE_NAME
;
1384 columns
[ncolumns
++] = COL_CACHE_ONESIZE
;
1385 columns
[ncolumns
++] = COL_CACHE_ALLSIZE
;
1386 columns
[ncolumns
++] = COL_CACHE_WAYS
;
1387 columns
[ncolumns
++] = COL_CACHE_TYPE
;
1388 columns
[ncolumns
++] = COL_CACHE_LEVEL
;
1389 columns
[ncolumns
++] = COL_CACHE_SETS
;
1390 columns
[ncolumns
++] = COL_CACHE_PHYLINE
;
1391 columns
[ncolumns
++] = COL_CACHE_COHERENCYSIZE
;
1393 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1394 ARRAY_SIZE(columns
),
1395 &ncolumns
, cache_column_name_to_id
) < 0)
1396 return EXIT_FAILURE
;
1398 print_caches_readable(cxt
, columns
, ncolumns
);
1400 case LSCPU_OUTPUT_READABLE
:
1402 /* No list was given. Just print whatever is there. */
1403 struct lscpu_cputype
*ct
= lscpu_cputype_get_default(cxt
);
1405 columns
[ncolumns
++] = COL_CPU_CPU
;
1407 columns
[ncolumns
++] = COL_CPU_NODE
;
1408 if (ct
&& ct
->ndrawers
)
1409 columns
[ncolumns
++] = COL_CPU_DRAWER
;
1410 if (ct
&& ct
->nbooks
)
1411 columns
[ncolumns
++] = COL_CPU_BOOK
;
1412 if (ct
&& ct
->nsockets
) {
1413 if (cxt
->is_cluster
)
1414 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1416 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1418 if (ct
&& ct
->ncores
)
1419 columns
[ncolumns
++] = COL_CPU_CORE
;
1421 columns
[ncolumns
++] = COL_CPU_CACHE
;
1423 columns
[ncolumns
++] = COL_CPU_ONLINE
;
1424 if (ct
&& ct
->has_configured
)
1425 columns
[ncolumns
++] = COL_CPU_CONFIGURED
;
1426 if (ct
&& ct
->has_polarization
)
1427 columns
[ncolumns
++] = COL_CPU_POLARIZATION
;
1428 if (ct
&& ct
->has_addresses
)
1429 columns
[ncolumns
++] = COL_CPU_ADDRESS
;
1430 if (ct
&& ct
->has_freq
) {
1431 columns
[ncolumns
++] = COL_CPU_MAXMHZ
;
1432 columns
[ncolumns
++] = COL_CPU_MINMHZ
;
1433 columns
[ncolumns
++] = COL_CPU_MHZ
;
1436 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1437 ARRAY_SIZE(columns
),
1438 &ncolumns
, cpu_column_name_to_id
) < 0)
1439 return EXIT_FAILURE
;
1440 print_cpus_readable(cxt
, columns
, ncolumns
);
1442 case LSCPU_OUTPUT_PARSABLE
:
1443 cxt
->show_compatible
= 1;
1445 columns
[ncolumns
++] = COL_CPU_CPU
;
1446 columns
[ncolumns
++] = COL_CPU_CORE
;
1447 if (cxt
->is_cluster
)
1448 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1450 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1451 columns
[ncolumns
++] = COL_CPU_NODE
;
1452 columns
[ncolumns
++] = COL_CPU_CACHE
;
1455 if (string_add_to_idarray(outarg
, columns
,
1456 ARRAY_SIZE(columns
),
1457 &ncolumns
, cpu_column_name_to_id
) < 0)
1458 return EXIT_FAILURE
;
1459 cxt
->show_compatible
= 0;
1462 print_cpus_parsable(cxt
, columns
, ncolumns
);
1466 lscpu_free_context(cxt
);
1468 return EXIT_SUCCESS
;