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
;
858 char setbuf
[setbuflen
], *p
;
866 p
= cpumask_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
867 add_summary_s(tb
, sec
, key
, p
);
869 p
= cpulist_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
870 add_summary_s(tb
, sec
, key
, p
);
875 print_summary_cputype(struct lscpu_cxt
*cxt
,
876 struct lscpu_cputype
*ct
,
877 struct libscols_table
*tb
,
878 struct libscols_line
*sec
)
880 sec
= add_summary_s(tb
, sec
, _("Model name:"), ct
->modelname
? ct
->modelname
: "-");
881 if (ct
->bios_modelname
)
882 add_summary_s(tb
, sec
, _("BIOS Model name:"), ct
->bios_modelname
);
884 add_summary_s(tb
, sec
, _("BIOS CPU family:"), ct
->bios_family
);
886 add_summary_s(tb
, sec
, _("Machine type:"), ct
->machinetype
);
888 add_summary_s(tb
, sec
, _("CPU family:"), ct
->family
);
889 if (ct
->model
|| ct
->revision
)
890 add_summary_s(tb
, sec
, _("Model:"), ct
->revision
? ct
->revision
: ct
->model
);
892 add_summary_n(tb
, sec
, _("Thread(s) per core:"), ct
->nthreads_per_core
);
894 add_summary_n(tb
, sec
, _("Core(s) per cluster:"), ct
->ncores_per_socket
);
896 add_summary_n(tb
, sec
, _("Core(s) per socket:"), ct
->ncores_per_socket
);
899 add_summary_n(tb
, sec
, _("Socket(s) per book:"), ct
->nsockets_per_book
);
900 if (ct
->ndrawers_per_system
|| ct
->ndrawers
) {
901 add_summary_n(tb
, sec
, _("Book(s) per drawer:"), ct
->nbooks_per_drawer
);
902 add_summary_n(tb
, sec
, _("Drawer(s):"), ct
->ndrawers_per_system
?: ct
->ndrawers
);
904 add_summary_n(tb
, sec
, _("Book(s):"), ct
->nbooks_per_drawer
?: ct
->nbooks
);
906 if (cxt
->is_cluster
) {
907 if (ct
->nr_socket_on_cluster
> 0)
908 add_summary_n(tb
, sec
, _("Socket(s):"), ct
->nr_socket_on_cluster
);
910 add_summary_s(tb
, sec
, _("Socket(s):"), "-");
912 add_summary_n(tb
, sec
, _("Cluster(s):"),
913 ct
->nsockets_per_book
?: ct
->nsockets
);
915 add_summary_n(tb
, sec
, _("Socket(s):"),
916 ct
->nsockets_per_book
?: ct
->nsockets
);
920 add_summary_s(tb
, sec
, _("Stepping:"), ct
->stepping
);
921 if (ct
->freqboost
>= 0)
922 add_summary_s(tb
, sec
, _("Frequency boost:"), ct
->freqboost
?
923 _("enabled") : _("disabled"));
925 /* s390 -- from the first CPU where is dynamic/static MHz */
927 add_summary_s(tb
, sec
, _("CPU dynamic MHz:"), ct
->dynamic_mhz
);
929 add_summary_s(tb
, sec
, _("CPU static MHz:"), ct
->static_mhz
);
932 float scal
= lsblk_cputype_get_scalmhz(cxt
, ct
);
934 add_summary_x(tb
, sec
, _("CPU(s) scaling MHz:"), "%.0f%%", scal
);
935 add_summary_x(tb
, sec
, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt
, ct
));
936 add_summary_x(tb
, sec
, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt
, ct
));
939 add_summary_x(tb
, sec
, _("BogoMIPS:"), "%.2f", (float) c_strtod(ct
->bogomips
, NULL
));
941 if (ct
->dispatching
>= 0)
942 add_summary_s(tb
, sec
, _("Dispatching mode:"), _(disp_modes
[ct
->dispatching
]));
944 if (ct
->physsockets
) {
945 add_summary_n(tb
, sec
, _("Physical sockets:"), ct
->physsockets
);
946 add_summary_n(tb
, sec
, _("Physical chips:"), ct
->physchips
);
947 add_summary_n(tb
, sec
, _("Physical cores/chip:"), ct
->physcoresperchip
);
951 add_summary_s(tb
, sec
, _("Flags:"), ct
->flags
);
957 static void print_summary(struct lscpu_cxt
*cxt
)
959 struct lscpu_cputype
*ct
;
962 struct libscols_table
*tb
;
963 struct libscols_line
*sec
;
968 tb
= scols_new_table();
970 err(EXIT_FAILURE
, _("failed to allocate output table"));
972 scols_table_enable_noheadings(tb
, 1);
974 scols_table_enable_json(tb
, 1);
975 scols_table_set_name(tb
, "lscpu");
976 } else if (hierarchic
) {
977 struct libscols_symbols
*sy
= scols_new_symbols();
981 scols_symbols_set_branch(sy
, " ");
982 scols_symbols_set_vertical(sy
, " ");
983 scols_symbols_set_right(sy
, " ");
984 scols_table_set_symbols(tb
, sy
);
985 scols_unref_symbols(sy
);
988 if (scols_table_new_column(tb
, "field", 0, hierarchic
? SCOLS_FL_TREE
: 0) == NULL
||
989 scols_table_new_column(tb
, "data", 0, SCOLS_FL_NOEXTREMES
| SCOLS_FL_WRAP
) == NULL
)
990 err(EXIT_FAILURE
, _("failed to initialize output column"));
992 ct
= lscpu_cputype_get_default(cxt
);
994 /* Section: architecture */
995 sec
= add_summary_s(tb
, NULL
, _("Architecture:"), cxt
->arch
->name
);
996 if (cxt
->arch
->bit32
|| cxt
->arch
->bit64
) {
997 char buf
[32], *p
= buf
;
999 if (cxt
->arch
->bit32
) {
1000 strcpy(p
, "32-bit, ");
1003 if (cxt
->arch
->bit64
) {
1004 strcpy(p
, "64-bit, ");
1008 add_summary_s(tb
, sec
, _("CPU op-mode(s):"), buf
);
1010 if (ct
&& ct
->addrsz
)
1011 add_summary_s(tb
, sec
, _("Address sizes:"), ct
->addrsz
);
1013 if (sysfs_get_byteorder(cxt
->rootfs
) == SYSFS_BYTEORDER_LITTLE
)
1014 add_summary_s(tb
, sec
, _("Byte Order:"), "Little Endian");
1016 add_summary_s(tb
, sec
, _("Byte Order:"), "Big Endian");
1018 /* Section: CPU lists */
1019 sec
= add_summary_n(tb
, NULL
, _("CPU(s):"), cxt
->npresents
);
1022 print_cpuset(cxt
, tb
, sec
,
1023 cxt
->hex
? _("On-line CPU(s) mask:") :
1024 _("On-line CPU(s) list:"),
1027 if (cxt
->online
&& cxt
->nonlines
!= cxt
->npresents
) {
1030 /* Linux kernel provides cpuset of off-line CPUs that contains
1031 * all configured CPUs (see /sys/devices/system/cpu/offline),
1032 * but want to print real (present in system) off-line CPUs only.
1034 set
= cpuset_alloc(cxt
->maxcpus
, NULL
, NULL
);
1036 err(EXIT_FAILURE
, _("failed to callocate cpu set"));
1037 CPU_ZERO_S(cxt
->setsize
, set
);
1038 for (i
= 0; i
< cxt
->npossibles
; i
++) {
1039 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
1041 if (cpu
&& is_cpu_present(cxt
, cpu
) && !is_cpu_online(cxt
, cpu
))
1042 CPU_SET_S(cpu
->logical_id
, cxt
->setsize
, set
);
1044 print_cpuset(cxt
, tb
, sec
,
1045 cxt
->hex
? _("Off-line CPU(s) mask:") :
1046 _("Off-line CPU(s) list:"), set
);
1051 /* Section: cpu type description */
1052 if (ct
&& ct
->vendor
)
1053 sec
= add_summary_s(tb
, NULL
, _("Vendor ID:"), ct
->vendor
);
1054 if (ct
&& ct
->bios_vendor
)
1055 add_summary_s(tb
, sec
, _("BIOS Vendor ID:"), ct
->bios_vendor
);
1057 for (i
= 0; i
< cxt
->ncputypes
; i
++)
1058 print_summary_cputype(cxt
, cxt
->cputypes
[i
], tb
, sec
);
1061 /* Section: vitualiazation */
1063 sec
= add_summary_e(tb
, NULL
, _("Virtualization features:"));
1064 if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "svm"))
1065 add_summary_s(tb
, sec
, _("Virtualization:"), "AMD-V");
1066 else if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "vmx"))
1067 add_summary_s(tb
, sec
, _("Virtualization:"), "VT-x");
1069 if (cxt
->virt
->hypervisor
)
1070 add_summary_s(tb
, sec
, _("Hypervisor:"), cxt
->virt
->hypervisor
);
1071 if (cxt
->virt
->vendor
) {
1072 add_summary_s(tb
, sec
, _("Hypervisor vendor:"), hv_vendors
[cxt
->virt
->vendor
]);
1073 add_summary_s(tb
, sec
, _("Virtualization type:"), _(virt_types
[cxt
->virt
->type
]));
1078 /* Section: caches */
1080 const char *last
= NULL
;
1082 /* The caches are sorted by name, cxt->caches[] may contains
1083 * multiple instances for the same name.
1085 for (i
= 0; i
< cxt
->ncaches
; i
++) {
1086 const char *name
= cxt
->caches
[i
].name
;
1090 if (last
&& strcmp(last
, name
) == 0)
1092 sz
= lscpu_get_cache_full_size(cxt
, name
, &n
);
1096 sec
= add_summary_e(tb
, NULL
, _("Caches (sum of all):"));
1100 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), name
);
1102 add_summary_sprint(tb
, sec
, field
,
1103 P_("%" PRIu64
" (%d instance)",
1104 "%" PRIu64
" (%d instances)", n
),
1107 char *tmp
= size_to_human_string(
1108 SIZE_SUFFIX_3LETTER
|
1111 add_summary_sprint(tb
, sec
, field
,
1112 P_("%s (%d instance)",
1113 "%s (%d instances)", n
),
1121 for (i
= 0; i
< cxt
->necaches
; i
++) {
1122 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
1127 sec
= add_summary_e(tb
, NULL
, _("Caches:"));
1130 snprintf(field
, sizeof(field
), hierarchic
? _("%s:") : _("%s cache:"), ca
->name
);
1132 add_summary_x(tb
, sec
, field
, "%" PRIu64
, ca
->size
);
1134 char *tmp
= size_to_human_string(
1135 SIZE_SUFFIX_3LETTER
|
1138 add_summary_s(tb
, sec
, field
, tmp
);
1144 /* Section: NUMA modes */
1146 sec
= add_summary_e(tb
, NULL
, _("NUMA:"));
1148 add_summary_n(tb
, sec
,_("NUMA node(s):"), cxt
->nnodes
);
1149 for (i
= 0; i
< cxt
->nnodes
; i
++) {
1150 snprintf(field
, sizeof(field
), _("NUMA node%d CPU(s):"), cxt
->idx2nodenum
[i
]);
1151 print_cpuset(cxt
, tb
, sec
, field
, cxt
->nodemaps
[i
]);
1156 /* Section: Vulnerabilities */
1158 sec
= add_summary_e(tb
, NULL
, _("Vulnerabilities:"));
1160 for (i
= 0; i
< cxt
->nvuls
; i
++) {
1161 snprintf(field
, sizeof(field
), hierarchic
?
1162 _("%s:") : _("Vulnerability %s:"), cxt
->vuls
[i
].name
);
1163 add_summary_s(tb
, sec
, field
, cxt
->vuls
[i
].text
);
1167 scols_print_table(tb
);
1168 scols_unref_table(tb
);
1171 static void __attribute__((__noreturn__
)) usage(void)
1176 fputs(USAGE_HEADER
, out
);
1177 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
1179 fputs(USAGE_SEPARATOR
, out
);
1180 fputs(_("Display information about the CPU architecture.\n"), out
);
1182 fputs(USAGE_OPTIONS
, out
);
1183 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out
);
1184 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out
);
1185 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out
);
1186 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out
);
1187 fputs(_(" -c, --offline print offline CPUs only\n"), out
);
1188 fputs(_(" -J, --json use JSON for default or extended format\n"), out
);
1189 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out
);
1190 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out
);
1191 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out
);
1192 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out
);
1193 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out
);
1194 fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out
);
1195 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out
);
1196 fputs(USAGE_SEPARATOR
, out
);
1197 printf(USAGE_HELP_OPTIONS(25));
1199 fputs(_("\nAvailable output columns for -e or -p:\n"), out
);
1200 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++)
1201 fprintf(out
, " %13s %s\n", coldescs_cpu
[i
].name
, _(coldescs_cpu
[i
].help
));
1203 fputs(_("\nAvailable output columns for -C:\n"), out
);
1204 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++)
1205 fprintf(out
, " %13s %s\n", coldescs_cache
[i
].name
, _(coldescs_cache
[i
].help
));
1207 printf(USAGE_MAN_TAIL("lscpu(1)"));
1212 int main(int argc
, char *argv
[])
1214 struct lscpu_cxt
*cxt
;
1216 int columns
[ARRAY_SIZE(coldescs_cpu
)];
1217 int cpu_modifier_specified
= 0;
1218 char *outarg
= NULL
;
1219 size_t i
, ncolumns
= 0;
1221 OPT_OUTPUT_ALL
= CHAR_MAX
+ 1,
1224 static const struct option longopts
[] = {
1225 { "all", no_argument
, NULL
, 'a' },
1226 { "online", no_argument
, NULL
, 'b' },
1227 { "bytes", no_argument
, NULL
, 'B' },
1228 { "caches", optional_argument
, NULL
, 'C' },
1229 { "offline", no_argument
, NULL
, 'c' },
1230 { "help", no_argument
, NULL
, 'h' },
1231 { "extended", optional_argument
, NULL
, 'e' },
1232 { "json", no_argument
, NULL
, 'J' },
1233 { "parse", optional_argument
, NULL
, 'p' },
1234 { "sysroot", required_argument
, NULL
, 's' },
1235 { "physical", no_argument
, NULL
, 'y' },
1236 { "hex", no_argument
, NULL
, 'x' },
1237 { "version", no_argument
, NULL
, 'V' },
1238 { "output-all", no_argument
, NULL
, OPT_OUTPUT_ALL
},
1239 { "hierarchic", optional_argument
, NULL
, OPT_HIERARCHIC
},
1240 { NULL
, 0, NULL
, 0 }
1243 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
1248 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1250 setlocale(LC_ALL
, "");
1251 bindtextdomain(PACKAGE
, LOCALEDIR
);
1252 textdomain(PACKAGE
);
1253 close_stdout_atexit();
1255 cxt
= lscpu_new_context();
1257 while ((c
= getopt_long(argc
, argv
, "aBbC::ce::hJp::s:xyV", longopts
, NULL
)) != -1) {
1259 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1263 cxt
->show_online
= cxt
->show_offline
= 1;
1264 cpu_modifier_specified
= 1;
1270 cxt
->show_online
= 1;
1271 cpu_modifier_specified
= 1;
1274 cxt
->show_offline
= 1;
1275 cpu_modifier_specified
= 1;
1283 cxt
->mode
= LSCPU_OUTPUT_CACHES
;
1295 cxt
->mode
= c
== 'p' ? LSCPU_OUTPUT_PARSABLE
: LSCPU_OUTPUT_READABLE
;
1298 cxt
->prefix
= optarg
;
1305 cxt
->show_physical
= 1;
1307 case OPT_OUTPUT_ALL
:
1310 case OPT_HIERARCHIC
:
1312 if (strcmp(optarg
, "auto") == 0)
1314 else if (strcmp(optarg
, "never") == 0)
1316 else if (strcmp(optarg
, "always") == 0)
1319 errx(EXIT_FAILURE
, _("unsupported --flat argument"));
1326 print_version(EXIT_SUCCESS
);
1328 errtryhelp(EXIT_FAILURE
);
1332 if (all
&& ncolumns
== 0) {
1333 size_t maxsz
= cxt
->mode
== LSCPU_OUTPUT_CACHES
?
1334 ARRAY_SIZE(coldescs_cache
) :
1335 ARRAY_SIZE(coldescs_cpu
);
1337 for (i
= 0; i
< maxsz
; i
++)
1338 columns
[ncolumns
++] = i
;
1341 if (cpu_modifier_specified
&& cxt
->mode
== LSCPU_OUTPUT_SUMMARY
) {
1343 _("%s: options --all, --online and --offline may only "
1344 "be used with options --extended or --parse.\n"),
1345 program_invocation_short_name
);
1346 return EXIT_FAILURE
;
1349 if (argc
!= optind
) {
1350 warnx(_("bad usage"));
1351 errtryhelp(EXIT_FAILURE
);
1354 /* set default cpu display mode if none was specified */
1355 if (!cxt
->show_online
&& !cxt
->show_offline
) {
1356 cxt
->show_online
= 1;
1357 cxt
->show_offline
= cxt
->mode
== LSCPU_OUTPUT_READABLE
? 1 : 0;
1363 lscpu_context_init_paths(cxt
);
1365 lscpu_read_cpulists(cxt
);
1366 lscpu_read_cpuinfo(cxt
);
1367 cxt
->arch
= lscpu_read_architecture(cxt
);
1369 lscpu_read_archext(cxt
);
1370 lscpu_read_vulnerabilities(cxt
);
1371 lscpu_read_numas(cxt
);
1372 lscpu_read_topology(cxt
);
1374 lscpu_decode_arm(cxt
);
1376 cxt
->virt
= lscpu_read_virtualization(cxt
);
1378 if (hierarchic
== -1)
1379 hierarchic
= isatty(STDOUT_FILENO
); /* default */
1382 case LSCPU_OUTPUT_SUMMARY
:
1385 case LSCPU_OUTPUT_CACHES
:
1387 columns
[ncolumns
++] = COL_CACHE_NAME
;
1388 columns
[ncolumns
++] = COL_CACHE_ONESIZE
;
1389 columns
[ncolumns
++] = COL_CACHE_ALLSIZE
;
1390 columns
[ncolumns
++] = COL_CACHE_WAYS
;
1391 columns
[ncolumns
++] = COL_CACHE_TYPE
;
1392 columns
[ncolumns
++] = COL_CACHE_LEVEL
;
1393 columns
[ncolumns
++] = COL_CACHE_SETS
;
1394 columns
[ncolumns
++] = COL_CACHE_PHYLINE
;
1395 columns
[ncolumns
++] = COL_CACHE_COHERENCYSIZE
;
1397 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1398 ARRAY_SIZE(columns
),
1399 &ncolumns
, cache_column_name_to_id
) < 0)
1400 return EXIT_FAILURE
;
1402 print_caches_readable(cxt
, columns
, ncolumns
);
1404 case LSCPU_OUTPUT_READABLE
:
1406 /* No list was given. Just print whatever is there. */
1407 struct lscpu_cputype
*ct
= lscpu_cputype_get_default(cxt
);
1409 columns
[ncolumns
++] = COL_CPU_CPU
;
1411 columns
[ncolumns
++] = COL_CPU_NODE
;
1412 if (ct
&& ct
->ndrawers
)
1413 columns
[ncolumns
++] = COL_CPU_DRAWER
;
1414 if (ct
&& ct
->nbooks
)
1415 columns
[ncolumns
++] = COL_CPU_BOOK
;
1416 if (ct
&& ct
->nsockets
) {
1417 if (cxt
->is_cluster
)
1418 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1420 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1422 if (ct
&& ct
->ncores
)
1423 columns
[ncolumns
++] = COL_CPU_CORE
;
1425 columns
[ncolumns
++] = COL_CPU_CACHE
;
1427 columns
[ncolumns
++] = COL_CPU_ONLINE
;
1428 if (ct
&& ct
->has_configured
)
1429 columns
[ncolumns
++] = COL_CPU_CONFIGURED
;
1430 if (ct
&& ct
->has_polarization
)
1431 columns
[ncolumns
++] = COL_CPU_POLARIZATION
;
1432 if (ct
&& ct
->has_addresses
)
1433 columns
[ncolumns
++] = COL_CPU_ADDRESS
;
1434 if (ct
&& ct
->has_freq
) {
1435 columns
[ncolumns
++] = COL_CPU_MAXMHZ
;
1436 columns
[ncolumns
++] = COL_CPU_MINMHZ
;
1437 columns
[ncolumns
++] = COL_CPU_MHZ
;
1440 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1441 ARRAY_SIZE(columns
),
1442 &ncolumns
, cpu_column_name_to_id
) < 0)
1443 return EXIT_FAILURE
;
1444 print_cpus_readable(cxt
, columns
, ncolumns
);
1446 case LSCPU_OUTPUT_PARSABLE
:
1447 cxt
->show_compatible
= 1;
1449 columns
[ncolumns
++] = COL_CPU_CPU
;
1450 columns
[ncolumns
++] = COL_CPU_CORE
;
1451 if (cxt
->is_cluster
)
1452 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1454 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1455 columns
[ncolumns
++] = COL_CPU_NODE
;
1456 columns
[ncolumns
++] = COL_CPU_CACHE
;
1458 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1459 ARRAY_SIZE(columns
),
1460 &ncolumns
, cpu_column_name_to_id
) < 0)
1461 return EXIT_FAILURE
;
1463 print_cpus_parsable(cxt
, columns
, ncolumns
);
1467 lscpu_free_context(cxt
);
1469 return EXIT_SUCCESS
;