2 * lscpu - CPU architecture information helper
4 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
5 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
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.
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.
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.
31 #include <sys/utsname.h>
34 #include <sys/types.h>
36 #include <sys/personality.h>
38 #include <libsmartcols.h>
40 #include "closestream.h"
47 static const char *virt_types
[] = {
48 [VIRT_TYPE_NONE
] = N_("none"),
49 [VIRT_TYPE_PARA
] = N_("para"),
50 [VIRT_TYPE_FULL
] = N_("full"),
51 [VIRT_TYPE_CONTAINER
] = N_("container"),
54 static const char *hv_vendors
[] = {
55 [VIRT_VENDOR_NONE
] = NULL
,
56 [VIRT_VENDOR_XEN
] = "Xen",
57 [VIRT_VENDOR_KVM
] = "KVM",
58 [VIRT_VENDOR_MSHV
] = "Microsoft",
59 [VIRT_VENDOR_VMWARE
] = "VMware",
60 [VIRT_VENDOR_IBM
] = "IBM",
61 [VIRT_VENDOR_VSERVER
] = "Linux-VServer",
62 [VIRT_VENDOR_UML
] = "User-mode Linux",
63 [VIRT_VENDOR_INNOTEK
] = "Innotek GmbH",
64 [VIRT_VENDOR_HITACHI
] = "Hitachi",
65 [VIRT_VENDOR_PARALLELS
] = "Parallels",
66 [VIRT_VENDOR_VBOX
] = "Oracle",
67 [VIRT_VENDOR_OS400
] = "OS/400",
68 [VIRT_VENDOR_PHYP
] = "pHyp",
69 [VIRT_VENDOR_SPAR
] = "Unisys s-Par",
70 [VIRT_VENDOR_WSL
] = "Windows Subsystem for Linux"
73 /* dispatching modes */
74 static const char *disp_modes
[] = {
75 [DISP_HORIZONTAL
] = N_("horizontal"),
76 [DISP_VERTICAL
] = N_("vertical")
79 struct polarization_modes
{
84 static struct polarization_modes polar_modes
[] = {
85 [POLAR_UNKNOWN
] = {"U", "-"},
86 [POLAR_VLOW
] = {"VL", "vert-low"},
87 [POLAR_VMEDIUM
] = {"VM", "vert-medium"},
88 [POLAR_VHIGH
] = {"VH", "vert-high"},
89 [POLAR_HORIZONTAL
] = {"H", "horizontal"},
105 COL_CPU_POLARIZATION
,
127 COL_CACHE_COHERENCYSIZE
131 /* column description
133 struct lscpu_coldesc
{
138 unsigned int is_abbr
:1; /* name is abbreviation */
142 static struct lscpu_coldesc coldescs_cpu
[] =
144 [COL_CPU_BOGOMIPS
] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT
, 1, SCOLS_JSON_NUMBER
},
145 [COL_CPU_CPU
] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT
, 1, SCOLS_JSON_NUMBER
},
146 [COL_CPU_CORE
] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
147 [COL_CPU_CLUSTER
] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
148 [COL_CPU_SOCKET
] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
149 [COL_CPU_NODE
] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
150 [COL_CPU_BOOK
] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
151 [COL_CPU_DRAWER
] = { "DRAWER", N_("logical drawer number"), SCOLS_FL_RIGHT
, SCOLS_JSON_NUMBER
},
152 [COL_CPU_CACHE
] = { "CACHE", N_("shows how caches are shared between CPUs") },
153 [COL_CPU_POLARIZATION
] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
154 [COL_CPU_ADDRESS
] = { "ADDRESS", N_("physical address of a CPU") },
155 [COL_CPU_CONFIGURED
] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU"), 0, 0, SCOLS_JSON_BOOLEAN_OPTIONAL
},
156 [COL_CPU_ONLINE
] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_BOOLEAN_OPTIONAL
},
157 [COL_CPU_MHZ
] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
158 [COL_CPU_SCALMHZ
] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT
, SCOLS_JSON_NUMBER
},
159 [COL_CPU_MAXMHZ
] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
160 [COL_CPU_MINMHZ
] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
161 [COL_CPU_MODELNAME
] = { "MODELNAME", N_("shows CPU model name"), 0, 0, SCOLS_JSON_STRING
}
164 static struct lscpu_coldesc coldescs_cache
[] =
166 [COL_CACHE_ALLSIZE
] = { "ALL-SIZE", N_("size of all system caches"), SCOLS_FL_RIGHT
},
167 [COL_CACHE_LEVEL
] = { "LEVEL", N_("cache level"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
168 [COL_CACHE_NAME
] = { "NAME", N_("cache name") },
169 [COL_CACHE_ONESIZE
] = { "ONE-SIZE", N_("size of one cache"), SCOLS_FL_RIGHT
},
170 [COL_CACHE_TYPE
] = { "TYPE", N_("cache type") },
171 [COL_CACHE_WAYS
] = { "WAYS", N_("ways of associativity"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
172 [COL_CACHE_ALLOCPOL
] = { "ALLOC-POLICY", N_("allocation policy") },
173 [COL_CACHE_WRITEPOL
] = { "WRITE-POLICY", N_("write policy") },
174 [COL_CACHE_PHYLINE
] = { "PHY-LINE", N_("number of physical cache line per cache tag"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
},
175 [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
},
176 [COL_CACHE_COHERENCYSIZE
] = { "COHERENCY-SIZE", N_("minimum amount of data in bytes transferred from memory to cache"), SCOLS_FL_RIGHT
, 0, SCOLS_JSON_NUMBER
}
179 static int hierarchic
= -1;
181 UL_DEBUG_DEFINE_MASK(lscpu
);
182 UL_DEBUG_DEFINE_MASKNAMES(lscpu
) = UL_DEBUG_EMPTY_MASKNAMES
;
184 static void lscpu_init_debug(void)
186 __UL_INIT_DEBUG_FROM_ENV(lscpu
, LSCPU_DEBUG_
, 0, LSCPU_DEBUG
);
190 cpu_column_name_to_id(const char *name
, size_t namesz
)
194 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++) {
195 const char *cn
= coldescs_cpu
[i
].name
;
197 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
200 warnx(_("unknown column: %s"), name
);
205 cache_column_name_to_id(const char *name
, size_t namesz
)
209 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++) {
210 const char *cn
= coldescs_cache
[i
].name
;
212 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
215 warnx(_("unknown column: %s"), name
);
219 static void lscpu_context_init_paths(struct lscpu_cxt
*cxt
)
221 DBG(MISC
, ul_debugobj(cxt
, "initialize paths"));
222 ul_path_init_debug();
227 cxt
->rootfs
= ul_new_path("/");
229 err(EXIT_FAILURE
, _("failed to initialize rootfs handler"));
230 ul_path_set_prefix(cxt
->rootfs
, cxt
->prefix
);
233 /* /sys/devices/system/cpu */
234 cxt
->syscpu
= ul_new_path(_PATH_SYS_CPU
);
236 err(EXIT_FAILURE
, _("failed to initialize CPUs sysfs handler"));
238 ul_path_set_prefix(cxt
->syscpu
, cxt
->prefix
);
241 cxt
->procfs
= ul_new_path("/proc");
243 err(EXIT_FAILURE
, _("failed to initialize procfs handler"));
245 ul_path_set_prefix(cxt
->procfs
, cxt
->prefix
);
248 static struct lscpu_cxt
*lscpu_new_context(void)
250 return xcalloc(1, sizeof(struct lscpu_cxt
));
253 static void lscpu_free_context(struct lscpu_cxt
*cxt
)
260 DBG(MISC
, ul_debugobj(cxt
, "freeing context"));
262 DBG(MISC
, ul_debugobj(cxt
, " de-initialize paths"));
263 ul_unref_path(cxt
->syscpu
);
264 ul_unref_path(cxt
->procfs
);
265 ul_unref_path(cxt
->rootfs
);
267 DBG(MISC
, ul_debugobj(cxt
, " freeing cpus"));
268 for (i
= 0; i
< cxt
->npossibles
; i
++) {
269 lscpu_unref_cpu(cxt
->cpus
[i
]);
272 DBG(MISC
, ul_debugobj(cxt
, " freeing types"));
273 for (i
= 0; i
< cxt
->ncputypes
; i
++) {
274 lscpu_unref_cputype(cxt
->cputypes
[i
]);
275 cxt
->cputypes
[i
] = NULL
;
283 for (i
= 0; i
< cxt
->nvuls
; i
++) {
284 free(cxt
->vuls
[i
].name
);
285 free(cxt
->vuls
[i
].text
);
289 for (i
= 0; i
< cxt
->nnodes
; i
++)
290 free(cxt
->nodemaps
[i
]);
293 free(cxt
->idx2nodenum
);
295 lscpu_free_virtualization(cxt
->virt
);
296 lscpu_free_architecture(cxt
->arch
);
298 lscpu_free_caches(cxt
->ecaches
, cxt
->necaches
);
299 lscpu_free_caches(cxt
->caches
, cxt
->ncaches
);
304 static void __fill_id( struct lscpu_cxt
*cxt
,
305 struct lscpu_cpu
*cpu
,
306 int id
, cpu_set_t
**map
,
308 char *buf
, size_t bufsz
)
312 if (cxt
->show_physical
) {
314 snprintf(buf
, bufsz
, "-");
316 snprintf(buf
, bufsz
, "%d", id
);
320 if (cpuset_ary_isset(cpu
->logical_id
, map
, nitems
,
321 cxt
->setsize
, &i
) == 0)
322 snprintf(buf
, bufsz
, "%zu", i
);
326 static void get_cell_boolean(
327 struct lscpu_cxt
*cxt
,
328 int has_data
, int data
,
329 char *buf
, size_t bufsz
)
334 if (cxt
->mode
== LSCPU_OUTPUT_PARSABLE
|| cxt
->json
)
335 snprintf(buf
, bufsz
, "%s",
336 data
? _("Y") : _("N"));
338 snprintf(buf
, bufsz
, "%s",
339 data
? _("yes") : _("no"));
342 #define fill_id(_cxt, _cpu, NAME, _buf, _bufsz) \
343 __fill_id(_cxt, (_cpu), \
344 (_cpu)-> NAME ## id, \
345 (_cpu)->type-> NAME ## maps, \
346 (_cpu)->type->n ## NAME ## s, \
349 static char *get_cell_data(
350 struct lscpu_cxt
*cxt
,
351 struct lscpu_cpu
*cpu
, int col
,
352 char *buf
, size_t bufsz
)
363 snprintf(buf
, bufsz
, "%d", cpu
->logical_id
);
365 case COL_CPU_BOGOMIPS
:
366 if (!cpu
->bogomips
&& !cpu
->type
->bogomips
)
368 snprintf(buf
, bufsz
, "%.2f", (float) c_strtod(
369 cpu
->bogomips
? : cpu
->type
->bogomips
, NULL
));
372 fill_id(cxt
, cpu
, core
, buf
, bufsz
);
375 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
377 case COL_CPU_CLUSTER
:
379 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
382 fill_id(cxt
, cpu
, drawer
, buf
, bufsz
);
385 fill_id(cxt
, cpu
, book
, buf
, bufsz
);
388 if (cpuset_ary_isset(cpu
->logical_id
, cxt
->nodemaps
,
389 cxt
->nnodes
, cxt
->setsize
, &i
) == 0)
390 snprintf(buf
, bufsz
, "%d", cxt
->idx2nodenum
[i
]);
394 const char *last
= NULL
;
398 for (i
= 0; i
< cxt
->ncaches
; i
++) {
400 struct lscpu_cache
*ca
;
401 const char *name
= cxt
->caches
[i
].name
;
403 if (last
&& strcmp(last
, name
) == 0)
406 ca
= lscpu_cpu_get_cache(cxt
, cpu
, name
);
409 x
= snprintf(p
, sz
, "%d", ca
->id
);
410 if (x
< 0 || (size_t) x
>= sz
)
416 *p
++ = cxt
->show_compatible
? ',' : ':';
420 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
424 case COL_CPU_POLARIZATION
:
425 if (cpu
->polarization
< 0)
427 snprintf(buf
, bufsz
, "%s",
428 cxt
->mode
== LSCPU_OUTPUT_PARSABLE
?
429 polar_modes
[cpu
->polarization
].parsable
:
430 polar_modes
[cpu
->polarization
].readable
);
432 case COL_CPU_ADDRESS
:
433 if (cpu
->address
< 0)
435 snprintf(buf
, bufsz
, "%d", cpu
->address
);
437 case COL_CPU_CONFIGURED
:
438 get_cell_boolean(cxt
, cpu
->configured
>= 0, cpu
->configured
, buf
, bufsz
);
441 get_cell_boolean(cxt
, !!cxt
->online
, is_cpu_online(cxt
, cpu
), buf
, bufsz
);
444 if (cpu
->mhz_cur_freq
)
445 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_cur_freq
);
447 case COL_CPU_SCALMHZ
:
448 if (cpu
->mhz_cur_freq
&& cpu
->mhz_max_freq
)
449 snprintf(buf
, bufsz
, "%.0f%%", cpu
->mhz_cur_freq
/ cpu
->mhz_max_freq
* 100);
452 if (cpu
->mhz_max_freq
)
453 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_max_freq
);
456 if (cpu
->mhz_min_freq
)
457 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_min_freq
);
459 case COL_CPU_MODELNAME
:
460 if (cpu
->type
&& cpu
->type
->modelname
)
461 xstrncpy(buf
, cpu
->type
->modelname
, bufsz
);
467 static char *get_cell_header(
468 struct lscpu_cxt
*cxt
, int col
,
469 char *buf
, size_t bufsz
)
473 if (col
== COL_CPU_CACHE
) {
474 const char *last
= NULL
;
479 for (i
= 0; i
< cxt
->ncaches
; i
++) {
480 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
483 if (last
&& strcmp(last
, ca
->name
) == 0)
487 x
= snprintf(p
, sz
, "%s", ca
->name
);
488 if (x
< 0 || (size_t) x
>= sz
)
494 *p
++ = cxt
->show_compatible
? ',' : ':';
498 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
503 snprintf(buf
, bufsz
, "%s", coldescs_cpu
[col
].name
);
508 static void caches_add_line(struct lscpu_cxt
*cxt
,
509 struct libscols_table
*tb
,
510 struct lscpu_cache
*ca
,
511 int cols
[], size_t ncols
)
513 struct libscols_line
*ln
;
516 ln
= scols_table_new_line(tb
, NULL
);
518 err(EXIT_FAILURE
, _("failed to allocate output line"));
520 for (c
= 0; c
< ncols
; c
++) {
527 data
= xstrdup(ca
->name
);
529 case COL_CACHE_ONESIZE
:
533 xasprintf(&data
, "%" PRIu64
, ca
->size
);
535 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, ca
->size
);
537 case COL_CACHE_ALLSIZE
:
541 sz
= lscpu_get_cache_full_size(cxt
, ca
->name
, NULL
);
545 xasprintf(&data
, "%" PRIu64
, sz
);
547 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, sz
);
551 if (ca
->ways_of_associativity
)
552 xasprintf(&data
, "%u", ca
->ways_of_associativity
);
557 data
= xstrdup(ca
->type
);
559 case COL_CACHE_LEVEL
:
561 xasprintf(&data
, "%d", ca
->level
);
563 case COL_CACHE_ALLOCPOL
:
564 if (ca
->allocation_policy
)
565 data
= xstrdup(ca
->allocation_policy
);
567 case COL_CACHE_WRITEPOL
:
568 if (ca
->write_policy
)
569 data
= xstrdup(ca
->write_policy
);
571 case COL_CACHE_PHYLINE
:
572 if (ca
->physical_line_partition
)
573 xasprintf(&data
, "%u", ca
->physical_line_partition
);
576 if (ca
->number_of_sets
)
577 xasprintf(&data
, "%u", ca
->number_of_sets
);
579 case COL_CACHE_COHERENCYSIZE
:
580 if (ca
->coherency_line_size
)
581 xasprintf(&data
, "%u", ca
->coherency_line_size
);
585 if (data
&& scols_line_refer_data(ln
, c
, data
))
586 err(EXIT_FAILURE
, _("failed to add output data"));
594 static void print_caches_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
597 struct libscols_table
*tb
;
598 const char *last
= NULL
;
602 tb
= scols_new_table();
604 err(EXIT_FAILURE
, _("failed to allocate output table"));
606 scols_table_enable_json(tb
, 1);
607 scols_table_set_name(tb
, "caches");
610 for (i
= 0; i
< ncols
; i
++) {
611 struct lscpu_coldesc
*cd
= &coldescs_cache
[cols
[i
]];
612 struct libscols_column
*cl
;
614 cl
= scols_table_new_column(tb
, cd
->name
, 0, cd
->flags
);
616 err(EXIT_FAILURE
, _("failed to allocate output column"));
618 scols_column_set_json_type(cl
, cd
->json_type
);
621 /* standard caches */
622 for (i
= 0; i
< cxt
->ncaches
; i
++) {
623 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
625 if (last
&& strcmp(last
, ca
->name
) == 0)
628 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
632 for (i
= 0; i
< cxt
->necaches
; i
++) {
633 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
635 if (last
&& strcmp(last
, ca
->name
) == 0)
638 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
641 scols_print_table(tb
);
642 scols_unref_table(tb
);
646 * [-p] backend, we support two parsable formats:
648 * 1) "compatible" -- this format is compatible with the original lscpu(1)
649 * output and it contains fixed set of the columns. The CACHE columns are at
650 * the end of the line and the CACHE is not printed if the number of the caches
651 * is zero. The CACHE columns are separated by two commas, for example:
654 * # CPU,Core,Socket,Node,,L1d,L1i,L2
658 * 2) "user defined output" -- this format prints always all columns without
659 * special prefix for CACHE column. If there are not CACHEs then the column is
660 * empty and the header "Cache" is printed rather than a real name of the cache.
661 * The CACHE columns are separated by ':'.
663 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
664 * # CPU,Core,Socket,Node,L1d:L1i:L2
668 static void print_cpus_parsable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
670 char buf
[BUFSIZ
], *data
;
677 "# The following is the parsable format, which can be fed to other\n"
678 "# programs. Each different item in every column has an unique ID\n"
679 "# starting usually from zero.\n"));
682 for (i
= 0; i
< ncols
; i
++) {
685 if (col
== COL_CPU_CACHE
) {
686 if (cxt
->show_compatible
&& !cxt
->ncaches
)
688 if (cxt
->show_compatible
&& i
!= 0)
694 data
= get_cell_header(cxt
, col
, buf
, sizeof(buf
));
695 if (data
&& * data
&& col
!= COL_CPU_CACHE
&&
696 !coldescs_cpu
[col
].is_abbr
) {
698 * For normal column names use mixed case (e.g. "Socket")
702 while (p
&& *p
!= '\0') {
703 *p
= tolower((unsigned int) *p
);
707 fputs(data
&& *data
? data
: "", stdout
);
714 for (i
= 0; i
< cxt
->npossibles
; i
++) {
715 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
719 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
721 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
724 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
727 for (c
= 0; c
< ncols
; c
++) {
728 if (cxt
->show_compatible
&& cols
[c
] == COL_CPU_CACHE
) {
737 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
738 fputs(data
&& *data
? data
: "", stdout
);
748 static void print_cpus_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
753 struct libscols_table
*tb
;
757 tb
= scols_new_table();
759 err(EXIT_FAILURE
, _("failed to allocate output table"));
761 scols_table_enable_json(tb
, 1);
762 scols_table_set_name(tb
, "cpus");
765 for (i
= 0; i
< ncols
; i
++) {
766 data
= get_cell_header(cxt
, cols
[i
], buf
, sizeof(buf
));
767 struct lscpu_coldesc
*cd
= &coldescs_cpu
[cols
[i
]];
768 struct libscols_column
*cl
;
770 cl
= scols_table_new_column(tb
, data
, 0, cd
->flags
);
772 err(EXIT_FAILURE
, _("failed to allocate output column"));
774 scols_column_set_json_type(cl
, cd
->json_type
);
777 for (i
= 0; i
< cxt
->npossibles
; i
++) {
779 struct libscols_line
*ln
;
780 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
783 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
785 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
789 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
792 ln
= scols_table_new_line(tb
, NULL
);
794 err(EXIT_FAILURE
, _("failed to allocate output line"));
796 for (c
= 0; c
< ncols
; c
++) {
797 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
800 if (scols_line_set_data(ln
, c
, data
))
801 err(EXIT_FAILURE
, _("failed to add output data"));
805 scols_print_table(tb
);
806 scols_unref_table(tb
);
809 static struct libscols_line
*
810 __attribute__ ((__format__(printf
, 4, 5)))
811 add_summary_sprint(struct libscols_table
*tb
,
812 struct libscols_line
*sec
,
817 struct libscols_line
*ln
;
820 /* Don't print section lines without data */
821 if (!hierarchic
&& fmt
== NULL
)
824 ln
= scols_table_new_line(tb
, sec
);
826 err(EXIT_FAILURE
, _("failed to allocate output line"));
828 /* description column */
829 if (txt
&& scols_line_set_data(ln
, 0, txt
))
830 err(EXIT_FAILURE
, _("failed to add output data"));
836 xvasprintf(&data
, fmt
, args
);
839 if (data
&& scols_line_refer_data(ln
, 1, data
))
840 err(EXIT_FAILURE
, _("failed to add output data"));
846 #define add_summary_e(tb, sec, txt) add_summary_sprint(tb, sec, txt, NULL)
847 #define add_summary_n(tb, sec, txt, num) add_summary_sprint(tb, sec, txt, "%zu", num)
848 #define add_summary_s(tb, sec, txt, str) add_summary_sprint(tb, sec, txt, "%s", str)
849 #define add_summary_x(tb, sec, txt, fmt, x) add_summary_sprint(tb, sec, txt, fmt, x)
852 print_cpuset(struct lscpu_cxt
*cxt
,
853 struct libscols_table
*tb
,
854 struct libscols_line
*sec
,
855 const char *key
, cpu_set_t
*set
)
857 size_t setbuflen
= 7 * cxt
->maxcpus
;
865 setbuf
= xmalloc(setbuflen
);
868 p
= cpumask_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
869 add_summary_s(tb
, sec
, key
, p
);
871 p
= cpulist_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
872 add_summary_s(tb
, sec
, key
, p
);
879 print_summary_cputype(struct lscpu_cxt
*cxt
,
880 struct lscpu_cputype
*ct
,
881 struct libscols_table
*tb
,
882 struct libscols_line
*sec
)
884 sec
= add_summary_s(tb
, sec
, _("Model name:"), ct
->modelname
? ct
->modelname
: "-");
885 if (ct
->bios_modelname
)
886 add_summary_s(tb
, sec
, _("BIOS Model name:"), ct
->bios_modelname
);
888 add_summary_s(tb
, sec
, _("BIOS CPU family:"), ct
->bios_family
);
890 add_summary_s(tb
, sec
, _("Machine type:"), ct
->machinetype
);
892 add_summary_s(tb
, sec
, _("CPU family:"), ct
->family
);
893 if (ct
->model
|| ct
->revision
)
894 add_summary_s(tb
, sec
, _("Model:"), ct
->revision
? ct
->revision
: ct
->model
);
896 add_summary_n(tb
, sec
, _("Thread(s) per core:"), ct
->nthreads_per_core
);
898 add_summary_n(tb
, sec
, _("Core(s) per cluster:"), ct
->ncores_per_socket
);
900 add_summary_n(tb
, sec
, _("Core(s) per socket:"), ct
->ncores_per_socket
);
903 add_summary_n(tb
, sec
, _("Socket(s) per book:"), ct
->nsockets_per_book
);
904 if (ct
->ndrawers_per_system
|| ct
->ndrawers
) {
905 add_summary_n(tb
, sec
, _("Book(s) per drawer:"), ct
->nbooks_per_drawer
);
906 add_summary_n(tb
, sec
, _("Drawer(s):"), ct
->ndrawers_per_system
?: ct
->ndrawers
);
908 add_summary_n(tb
, sec
, _("Book(s):"), ct
->nbooks_per_drawer
?: ct
->nbooks
);
910 if (cxt
->is_cluster
) {
911 if (ct
->nr_socket_on_cluster
> 0)
912 add_summary_n(tb
, sec
, _("Socket(s):"), ct
->nr_socket_on_cluster
);
914 add_summary_s(tb
, sec
, _("Socket(s):"), "-");
916 add_summary_n(tb
, sec
, _("Cluster(s):"),
917 ct
->nsockets_per_book
?: ct
->nsockets
);
919 add_summary_n(tb
, sec
, _("Socket(s):"),
920 ct
->nsockets_per_book
?: ct
->nsockets
);
924 add_summary_s(tb
, sec
, _("Stepping:"), ct
->stepping
);
925 if (ct
->freqboost
>= 0)
926 add_summary_s(tb
, sec
, _("Frequency boost:"), ct
->freqboost
?
927 _("enabled") : _("disabled"));
929 /* s390 -- from the first CPU where is dynamic/static MHz */
931 add_summary_s(tb
, sec
, _("CPU dynamic MHz:"), ct
->dynamic_mhz
);
933 add_summary_s(tb
, sec
, _("CPU static MHz:"), ct
->static_mhz
);
936 float scal
= lsblk_cputype_get_scalmhz(cxt
, ct
);
938 add_summary_x(tb
, sec
, _("CPU(s) scaling MHz:"), "%.0f%%", scal
);
939 add_summary_x(tb
, sec
, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt
, ct
));
940 add_summary_x(tb
, sec
, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt
, ct
));
943 add_summary_x(tb
, sec
, _("BogoMIPS:"), "%.2f", (float) c_strtod(ct
->bogomips
, NULL
));
945 if (ct
->dispatching
>= 0)
946 add_summary_s(tb
, sec
, _("Dispatching mode:"), _(disp_modes
[ct
->dispatching
]));
948 if (ct
->physsockets
) {
949 add_summary_n(tb
, sec
, _("Physical sockets:"), ct
->physsockets
);
950 add_summary_n(tb
, sec
, _("Physical chips:"), ct
->physchips
);
951 add_summary_n(tb
, sec
, _("Physical cores/chip:"), ct
->physcoresperchip
);
955 add_summary_s(tb
, sec
, _("Flags:"), ct
->flags
);
961 static void print_summary(struct lscpu_cxt
*cxt
)
963 struct lscpu_cputype
*ct
;
966 struct libscols_table
*tb
;
967 struct libscols_line
*sec
;
972 tb
= scols_new_table();
974 err(EXIT_FAILURE
, _("failed to allocate output table"));
976 scols_table_enable_noheadings(tb
, 1);
978 scols_table_enable_json(tb
, 1);
979 scols_table_set_name(tb
, "lscpu");
980 } else if (hierarchic
) {
981 struct libscols_symbols
*sy
= scols_new_symbols();
985 scols_symbols_set_branch(sy
, " ");
986 scols_symbols_set_vertical(sy
, " ");
987 scols_symbols_set_right(sy
, " ");
988 scols_table_set_symbols(tb
, sy
);
989 scols_unref_symbols(sy
);
992 if (scols_table_new_column(tb
, "field", 0, hierarchic
? SCOLS_FL_TREE
: 0) == NULL
||
993 scols_table_new_column(tb
, "data", 0, SCOLS_FL_NOEXTREMES
| SCOLS_FL_WRAP
) == NULL
)
994 err(EXIT_FAILURE
, _("failed to initialize output column"));
996 ct
= lscpu_cputype_get_default(cxt
);
998 /* Section: architecture */
999 sec
= add_summary_s(tb
, NULL
, _("Architecture:"), cxt
->arch
->name
);
1000 if (cxt
->arch
->bit32
|| cxt
->arch
->bit64
) {
1001 char buf
[32], *p
= buf
;
1003 if (cxt
->arch
->bit32
) {
1004 strcpy(p
, "32-bit, ");
1007 if (cxt
->arch
->bit64
) {
1008 strcpy(p
, "64-bit, ");
1012 add_summary_s(tb
, sec
, _("CPU op-mode(s):"), buf
);
1014 if (ct
&& ct
->addrsz
)
1015 add_summary_s(tb
, sec
, _("Address sizes:"), ct
->addrsz
);
1017 if (sysfs_get_byteorder(cxt
->rootfs
) == SYSFS_BYTEORDER_LITTLE
)
1018 add_summary_s(tb
, sec
, _("Byte Order:"), "Little Endian");
1020 add_summary_s(tb
, sec
, _("Byte Order:"), "Big Endian");
1022 /* Section: CPU lists */
1023 sec
= add_summary_n(tb
, NULL
, _("CPU(s):"), cxt
->npresents
);
1026 print_cpuset(cxt
, tb
, sec
,
1027 cxt
->hex
? _("On-line CPU(s) mask:") :
1028 _("On-line CPU(s) list:"),
1031 if (cxt
->online
&& cxt
->nonlines
!= cxt
->npresents
) {
1034 /* Linux kernel provides cpuset of off-line CPUs that contains
1035 * all configured CPUs (see /sys/devices/system/cpu/offline),
1036 * but want to print real (present in system) off-line CPUs only.
1038 set
= cpuset_alloc(cxt
->maxcpus
, NULL
, NULL
);
1040 err(EXIT_FAILURE
, _("failed to callocate cpu set"));
1041 CPU_ZERO_S(cxt
->setsize
, set
);
1042 for (i
= 0; i
< cxt
->npossibles
; i
++) {
1043 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
1045 if (cpu
&& is_cpu_present(cxt
, cpu
) && !is_cpu_online(cxt
, cpu
))
1046 CPU_SET_S(cpu
->logical_id
, cxt
->setsize
, set
);
1048 print_cpuset(cxt
, tb
, sec
,
1049 cxt
->hex
? _("Off-line CPU(s) mask:") :
1050 _("Off-line CPU(s) list:"), set
);
1055 /* Section: cpu type description */
1056 if (ct
&& ct
->vendor
)
1057 sec
= add_summary_s(tb
, NULL
, _("Vendor ID:"), ct
->vendor
);
1058 if (ct
&& ct
->bios_vendor
)
1059 add_summary_s(tb
, sec
, _("BIOS Vendor ID:"), ct
->bios_vendor
);
1061 for (i
= 0; i
< cxt
->ncputypes
; i
++)
1062 print_summary_cputype(cxt
, cxt
->cputypes
[i
], tb
, sec
);
1065 /* Section: vitualiazation */
1067 sec
= add_summary_e(tb
, NULL
, _("Virtualization features:"));
1068 if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "svm"))
1069 add_summary_s(tb
, sec
, _("Virtualization:"), "AMD-V");
1070 else if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "vmx"))
1071 add_summary_s(tb
, sec
, _("Virtualization:"), "VT-x");
1073 if (cxt
->virt
->hypervisor
)
1074 add_summary_s(tb
, sec
, _("Hypervisor:"), cxt
->virt
->hypervisor
);
1075 if (cxt
->virt
->vendor
) {
1076 add_summary_s(tb
, sec
, _("Hypervisor vendor:"), hv_vendors
[cxt
->virt
->vendor
]);
1077 add_summary_s(tb
, sec
, _("Virtualization type:"), _(virt_types
[cxt
->virt
->type
]));
1082 /* Section: caches */
1084 const char *last
= NULL
;
1086 /* The caches are sorted by name, cxt->caches[] may contains
1087 * multiple instances for the same name.
1089 for (i
= 0; i
< cxt
->ncaches
; i
++) {
1090 const char *name
= cxt
->caches
[i
].name
;
1094 if (last
&& strcmp(last
, name
) == 0)
1096 sz
= lscpu_get_cache_full_size(cxt
, name
, &n
);
1100 sec
= add_summary_e(tb
, NULL
, _("Caches (sum of all):"));
1104 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), name
);
1106 add_summary_sprint(tb
, sec
, field
,
1107 P_("%" PRIu64
" (%d instance)",
1108 "%" PRIu64
" (%d instances)", n
),
1111 char *tmp
= size_to_human_string(
1112 SIZE_SUFFIX_3LETTER
|
1115 add_summary_sprint(tb
, sec
, field
,
1116 P_("%s (%d instance)",
1117 "%s (%d instances)", n
),
1125 for (i
= 0; i
< cxt
->necaches
; i
++) {
1126 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
1131 sec
= add_summary_e(tb
, NULL
, _("Caches:"));
1134 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), ca
->name
);
1136 add_summary_x(tb
, sec
, field
, "%" PRIu64
, ca
->size
);
1138 char *tmp
= size_to_human_string(
1139 SIZE_SUFFIX_3LETTER
|
1142 add_summary_s(tb
, sec
, field
, tmp
);
1148 /* Section: NUMA modes */
1150 sec
= add_summary_e(tb
, NULL
, _("NUMA:"));
1152 add_summary_n(tb
, sec
,_("NUMA node(s):"), cxt
->nnodes
);
1153 for (i
= 0; i
< cxt
->nnodes
; i
++) {
1154 snprintf(field
, sizeof(field
), _("NUMA node%d CPU(s):"), cxt
->idx2nodenum
[i
]);
1155 print_cpuset(cxt
, tb
, sec
, field
, cxt
->nodemaps
[i
]);
1160 /* Section: Vulnerabilities */
1162 sec
= add_summary_e(tb
, NULL
, _("Vulnerabilities:"));
1164 for (i
= 0; i
< cxt
->nvuls
; i
++) {
1165 snprintf(field
, sizeof(field
), hierarchic
?
1166 _("%s:") : _("Vulnerability %s:"), cxt
->vuls
[i
].name
);
1167 add_summary_s(tb
, sec
, field
, cxt
->vuls
[i
].text
);
1171 scols_print_table(tb
);
1172 scols_unref_table(tb
);
1175 static void __attribute__((__noreturn__
)) usage(void)
1180 fputs(USAGE_HEADER
, out
);
1181 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
1183 fputs(USAGE_SEPARATOR
, out
);
1184 fputs(_("Display information about the CPU architecture.\n"), out
);
1186 fputs(USAGE_OPTIONS
, out
);
1187 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out
);
1188 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out
);
1189 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out
);
1190 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out
);
1191 fputs(_(" -c, --offline print offline CPUs only\n"), out
);
1192 fputs(_(" -J, --json use JSON for default or extended format\n"), out
);
1193 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out
);
1194 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out
);
1195 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out
);
1196 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out
);
1197 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out
);
1198 fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out
);
1199 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out
);
1200 fputs(USAGE_SEPARATOR
, out
);
1201 printf(USAGE_HELP_OPTIONS(25));
1203 fputs(_("\nAvailable output columns for -e or -p:\n"), out
);
1204 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++)
1205 fprintf(out
, " %13s %s\n", coldescs_cpu
[i
].name
, _(coldescs_cpu
[i
].help
));
1207 fputs(_("\nAvailable output columns for -C:\n"), out
);
1208 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++)
1209 fprintf(out
, " %13s %s\n", coldescs_cache
[i
].name
, _(coldescs_cache
[i
].help
));
1211 printf(USAGE_MAN_TAIL("lscpu(1)"));
1216 int main(int argc
, char *argv
[])
1218 struct lscpu_cxt
*cxt
;
1220 int columns
[ARRAY_SIZE(coldescs_cpu
)];
1221 int cpu_modifier_specified
= 0;
1222 char *outarg
= NULL
;
1223 size_t i
, ncolumns
= 0;
1225 OPT_OUTPUT_ALL
= CHAR_MAX
+ 1,
1228 static const struct option longopts
[] = {
1229 { "all", no_argument
, NULL
, 'a' },
1230 { "online", no_argument
, NULL
, 'b' },
1231 { "bytes", no_argument
, NULL
, 'B' },
1232 { "caches", optional_argument
, NULL
, 'C' },
1233 { "offline", no_argument
, NULL
, 'c' },
1234 { "help", no_argument
, NULL
, 'h' },
1235 { "extended", optional_argument
, NULL
, 'e' },
1236 { "json", no_argument
, NULL
, 'J' },
1237 { "parse", optional_argument
, NULL
, 'p' },
1238 { "sysroot", required_argument
, NULL
, 's' },
1239 { "physical", no_argument
, NULL
, 'y' },
1240 { "hex", no_argument
, NULL
, 'x' },
1241 { "version", no_argument
, NULL
, 'V' },
1242 { "output-all", no_argument
, NULL
, OPT_OUTPUT_ALL
},
1243 { "hierarchic", optional_argument
, NULL
, OPT_HIERARCHIC
},
1244 { NULL
, 0, NULL
, 0 }
1247 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
1252 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1254 setlocale(LC_ALL
, "");
1255 bindtextdomain(PACKAGE
, LOCALEDIR
);
1256 textdomain(PACKAGE
);
1257 close_stdout_atexit();
1259 cxt
= lscpu_new_context();
1261 while ((c
= getopt_long(argc
, argv
, "aBbC::ce::hJp::s:xyV", longopts
, NULL
)) != -1) {
1263 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1267 cxt
->show_online
= cxt
->show_offline
= 1;
1268 cpu_modifier_specified
= 1;
1274 cxt
->show_online
= 1;
1275 cpu_modifier_specified
= 1;
1278 cxt
->show_offline
= 1;
1279 cpu_modifier_specified
= 1;
1287 cxt
->mode
= LSCPU_OUTPUT_CACHES
;
1299 cxt
->mode
= c
== 'p' ? LSCPU_OUTPUT_PARSABLE
: LSCPU_OUTPUT_READABLE
;
1302 cxt
->prefix
= optarg
;
1309 cxt
->show_physical
= 1;
1311 case OPT_OUTPUT_ALL
:
1314 case OPT_HIERARCHIC
:
1316 if (strcmp(optarg
, "auto") == 0)
1318 else if (strcmp(optarg
, "never") == 0)
1320 else if (strcmp(optarg
, "always") == 0)
1323 errx(EXIT_FAILURE
, _("unsupported --flat argument"));
1330 print_version(EXIT_SUCCESS
);
1332 errtryhelp(EXIT_FAILURE
);
1336 if (all
&& ncolumns
== 0) {
1337 size_t maxsz
= cxt
->mode
== LSCPU_OUTPUT_CACHES
?
1338 ARRAY_SIZE(coldescs_cache
) :
1339 ARRAY_SIZE(coldescs_cpu
);
1341 for (i
= 0; i
< maxsz
; i
++)
1342 columns
[ncolumns
++] = i
;
1345 if (cpu_modifier_specified
&& cxt
->mode
== LSCPU_OUTPUT_SUMMARY
) {
1347 _("%s: options --all, --online and --offline may only "
1348 "be used with options --extended or --parse.\n"),
1349 program_invocation_short_name
);
1350 return EXIT_FAILURE
;
1353 if (argc
!= optind
) {
1354 warnx(_("bad usage"));
1355 errtryhelp(EXIT_FAILURE
);
1358 /* set default cpu display mode if none was specified */
1359 if (!cxt
->show_online
&& !cxt
->show_offline
) {
1360 cxt
->show_online
= 1;
1361 cxt
->show_offline
= cxt
->mode
== LSCPU_OUTPUT_READABLE
? 1 : 0;
1367 lscpu_context_init_paths(cxt
);
1369 lscpu_read_cpulists(cxt
);
1370 lscpu_read_cpuinfo(cxt
);
1371 cxt
->arch
= lscpu_read_architecture(cxt
);
1373 lscpu_read_archext(cxt
);
1374 lscpu_read_vulnerabilities(cxt
);
1375 lscpu_read_numas(cxt
);
1376 lscpu_read_topology(cxt
);
1378 lscpu_decode_arm(cxt
);
1380 cxt
->virt
= lscpu_read_virtualization(cxt
);
1382 if (hierarchic
== -1)
1383 hierarchic
= isatty(STDOUT_FILENO
); /* default */
1386 case LSCPU_OUTPUT_SUMMARY
:
1389 case LSCPU_OUTPUT_CACHES
:
1391 columns
[ncolumns
++] = COL_CACHE_NAME
;
1392 columns
[ncolumns
++] = COL_CACHE_ONESIZE
;
1393 columns
[ncolumns
++] = COL_CACHE_ALLSIZE
;
1394 columns
[ncolumns
++] = COL_CACHE_WAYS
;
1395 columns
[ncolumns
++] = COL_CACHE_TYPE
;
1396 columns
[ncolumns
++] = COL_CACHE_LEVEL
;
1397 columns
[ncolumns
++] = COL_CACHE_SETS
;
1398 columns
[ncolumns
++] = COL_CACHE_PHYLINE
;
1399 columns
[ncolumns
++] = COL_CACHE_COHERENCYSIZE
;
1401 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1402 ARRAY_SIZE(columns
),
1403 &ncolumns
, cache_column_name_to_id
) < 0)
1404 return EXIT_FAILURE
;
1406 print_caches_readable(cxt
, columns
, ncolumns
);
1408 case LSCPU_OUTPUT_READABLE
:
1410 /* No list was given. Just print whatever is there. */
1411 struct lscpu_cputype
*ct
= lscpu_cputype_get_default(cxt
);
1413 columns
[ncolumns
++] = COL_CPU_CPU
;
1415 columns
[ncolumns
++] = COL_CPU_NODE
;
1416 if (ct
&& ct
->ndrawers
)
1417 columns
[ncolumns
++] = COL_CPU_DRAWER
;
1418 if (ct
&& ct
->nbooks
)
1419 columns
[ncolumns
++] = COL_CPU_BOOK
;
1420 if (ct
&& ct
->nsockets
) {
1421 if (cxt
->is_cluster
)
1422 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1424 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1426 if (ct
&& ct
->ncores
)
1427 columns
[ncolumns
++] = COL_CPU_CORE
;
1429 columns
[ncolumns
++] = COL_CPU_CACHE
;
1431 columns
[ncolumns
++] = COL_CPU_ONLINE
;
1432 if (ct
&& ct
->has_configured
)
1433 columns
[ncolumns
++] = COL_CPU_CONFIGURED
;
1434 if (ct
&& ct
->has_polarization
)
1435 columns
[ncolumns
++] = COL_CPU_POLARIZATION
;
1436 if (ct
&& ct
->has_addresses
)
1437 columns
[ncolumns
++] = COL_CPU_ADDRESS
;
1438 if (ct
&& ct
->has_freq
) {
1439 columns
[ncolumns
++] = COL_CPU_MAXMHZ
;
1440 columns
[ncolumns
++] = COL_CPU_MINMHZ
;
1441 columns
[ncolumns
++] = COL_CPU_MHZ
;
1444 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1445 ARRAY_SIZE(columns
),
1446 &ncolumns
, cpu_column_name_to_id
) < 0)
1447 return EXIT_FAILURE
;
1448 print_cpus_readable(cxt
, columns
, ncolumns
);
1450 case LSCPU_OUTPUT_PARSABLE
:
1451 cxt
->show_compatible
= 1;
1453 columns
[ncolumns
++] = COL_CPU_CPU
;
1454 columns
[ncolumns
++] = COL_CPU_CORE
;
1455 if (cxt
->is_cluster
)
1456 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1458 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1459 columns
[ncolumns
++] = COL_CPU_NODE
;
1460 columns
[ncolumns
++] = COL_CPU_CACHE
;
1462 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1463 ARRAY_SIZE(columns
),
1464 &ncolumns
, cpu_column_name_to_id
) < 0)
1465 return EXIT_FAILURE
;
1467 print_cpus_parsable(cxt
, columns
, ncolumns
);
1471 lscpu_free_context(cxt
);
1473 return EXIT_SUCCESS
;