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"
45 static const char *virt_types
[] = {
46 [VIRT_TYPE_NONE
] = N_("none"),
47 [VIRT_TYPE_PARA
] = N_("para"),
48 [VIRT_TYPE_FULL
] = N_("full"),
49 [VIRT_TYPE_CONTAINER
] = N_("container"),
52 static const char *hv_vendors
[] = {
53 [VIRT_VENDOR_NONE
] = NULL
,
54 [VIRT_VENDOR_XEN
] = "Xen",
55 [VIRT_VENDOR_KVM
] = "KVM",
56 [VIRT_VENDOR_MSHV
] = "Microsoft",
57 [VIRT_VENDOR_VMWARE
] = "VMware",
58 [VIRT_VENDOR_IBM
] = "IBM",
59 [VIRT_VENDOR_VSERVER
] = "Linux-VServer",
60 [VIRT_VENDOR_UML
] = "User-mode Linux",
61 [VIRT_VENDOR_INNOTEK
] = "Innotek GmbH",
62 [VIRT_VENDOR_HITACHI
] = "Hitachi",
63 [VIRT_VENDOR_PARALLELS
] = "Parallels",
64 [VIRT_VENDOR_VBOX
] = "Oracle",
65 [VIRT_VENDOR_OS400
] = "OS/400",
66 [VIRT_VENDOR_PHYP
] = "pHyp",
67 [VIRT_VENDOR_SPAR
] = "Unisys s-Par",
68 [VIRT_VENDOR_WSL
] = "Windows Subsystem for Linux"
71 /* dispatching modes */
72 static const char *disp_modes
[] = {
73 [DISP_HORIZONTAL
] = N_("horizontal"),
74 [DISP_VERTICAL
] = N_("vertical")
77 struct polarization_modes
{
82 static struct polarization_modes polar_modes
[] = {
83 [POLAR_UNKNOWN
] = {"U", "-"},
84 [POLAR_VLOW
] = {"VL", "vert-low"},
85 [POLAR_VMEDIUM
] = {"VM", "vert-medium"},
86 [POLAR_VHIGH
] = {"VH", "vert-high"},
87 [POLAR_HORIZONTAL
] = {"H", "horizontal"},
103 COL_CPU_POLARIZATION
,
123 COL_CACHE_COHERENCYSIZE
127 /* column description
129 struct lscpu_coldesc
{
134 unsigned int is_abbr
:1; /* name is abbreviation */
137 static struct lscpu_coldesc coldescs_cpu
[] =
139 [COL_CPU_BOGOMIPS
] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT
, 1 },
140 [COL_CPU_CPU
] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT
, 1 },
141 [COL_CPU_CORE
] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT
},
142 [COL_CPU_CLUSTER
] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT
},
143 [COL_CPU_SOCKET
] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT
},
144 [COL_CPU_NODE
] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT
},
145 [COL_CPU_BOOK
] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT
},
146 [COL_CPU_DRAWER
] = { "DRAWER", N_("logical drawer number"), SCOLS_FL_RIGHT
},
147 [COL_CPU_CACHE
] = { "CACHE", N_("shows how caches are shared between CPUs") },
148 [COL_CPU_POLARIZATION
] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
149 [COL_CPU_ADDRESS
] = { "ADDRESS", N_("physical address of a CPU") },
150 [COL_CPU_CONFIGURED
] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") },
151 [COL_CPU_ONLINE
] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT
},
152 [COL_CPU_MHZ
] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT
},
153 [COL_CPU_MAXMHZ
] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT
},
154 [COL_CPU_MINMHZ
] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT
}
157 static struct lscpu_coldesc coldescs_cache
[] =
159 [COL_CACHE_ALLSIZE
] = { "ALL-SIZE", N_("size of all system caches"), SCOLS_FL_RIGHT
},
160 [COL_CACHE_LEVEL
] = { "LEVEL", N_("cache level"), SCOLS_FL_RIGHT
},
161 [COL_CACHE_NAME
] = { "NAME", N_("cache name") },
162 [COL_CACHE_ONESIZE
] = { "ONE-SIZE", N_("size of one cache"), SCOLS_FL_RIGHT
},
163 [COL_CACHE_TYPE
] = { "TYPE", N_("cache type") },
164 [COL_CACHE_WAYS
] = { "WAYS", N_("ways of associativity"), SCOLS_FL_RIGHT
},
165 [COL_CACHE_ALLOCPOL
] = { "ALLOC-POLICY", N_("allocation policy") },
166 [COL_CACHE_WRITEPOL
] = { "WRITE-POLICY", N_("write policy") },
167 [COL_CACHE_PHYLINE
] = { "PHY-LINE", N_("number of physical cache line per cache t"), SCOLS_FL_RIGHT
},
168 [COL_CACHE_SETS
] = { "SETS", N_("number of sets in the cache; set lines has the same cache index"), SCOLS_FL_RIGHT
},
169 [COL_CACHE_COHERENCYSIZE
] = { "COHERENCY-SIZE", N_("minimum amount of data in bytes transferred from memory to cache"), SCOLS_FL_RIGHT
}
172 static int is_term
= 0;
174 UL_DEBUG_DEFINE_MASK(lscpu
);
175 UL_DEBUG_DEFINE_MASKNAMES(lscpu
) = UL_DEBUG_EMPTY_MASKNAMES
;
177 static void lscpu_init_debug(void)
179 __UL_INIT_DEBUG_FROM_ENV(lscpu
, LSCPU_DEBUG_
, 0, LSCPU_DEBUG
);
183 cpu_column_name_to_id(const char *name
, size_t namesz
)
187 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++) {
188 const char *cn
= coldescs_cpu
[i
].name
;
190 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
193 warnx(_("unknown column: %s"), name
);
198 cache_column_name_to_id(const char *name
, size_t namesz
)
202 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++) {
203 const char *cn
= coldescs_cache
[i
].name
;
205 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
208 warnx(_("unknown column: %s"), name
);
212 static void lscpu_context_init_paths(struct lscpu_cxt
*cxt
)
214 DBG(MISC
, ul_debugobj(cxt
, "initialize paths"));
215 ul_path_init_debug();
217 /* /sys/devices/system/cpu */
218 cxt
->syscpu
= ul_new_path(_PATH_SYS_CPU
);
220 err(EXIT_FAILURE
, _("failed to initialize CPUs sysfs handler"));
222 ul_path_set_prefix(cxt
->syscpu
, cxt
->prefix
);
225 cxt
->procfs
= ul_new_path("/proc");
227 err(EXIT_FAILURE
, _("failed to initialize procfs handler"));
229 ul_path_set_prefix(cxt
->procfs
, cxt
->prefix
);
232 static struct lscpu_cxt
*lscpu_new_context(void)
234 return xcalloc(1, sizeof(struct lscpu_cxt
));
237 static void lscpu_free_context(struct lscpu_cxt
*cxt
)
244 DBG(MISC
, ul_debugobj(cxt
, "freeing context"));
246 DBG(MISC
, ul_debugobj(cxt
, " de-initialize paths"));
247 ul_unref_path(cxt
->syscpu
);
248 ul_unref_path(cxt
->procfs
);
250 DBG(MISC
, ul_debugobj(cxt
, " freeing cpus"));
251 for (i
= 0; i
< cxt
->npossibles
; i
++) {
252 lscpu_unref_cpu(cxt
->cpus
[i
]);
255 DBG(MISC
, ul_debugobj(cxt
, " freeing types"));
256 for (i
= 0; i
< cxt
->ncputypes
; i
++) {
257 lscpu_unref_cputype(cxt
->cputypes
[i
]);
258 cxt
->cputypes
[i
] = NULL
;
266 for (i
= 0; i
< cxt
->nvuls
; i
++) {
267 free(cxt
->vuls
[i
].name
);
268 free(cxt
->vuls
[i
].text
);
272 for (i
= 0; i
< cxt
->nnodes
; i
++)
273 free(cxt
->nodemaps
[i
]);
276 free(cxt
->idx2nodenum
);
278 lscpu_free_virtualization(cxt
->virt
);
279 lscpu_free_architecture(cxt
->arch
);
281 lscpu_free_caches(cxt
->ecaches
, cxt
->necaches
);
282 lscpu_free_caches(cxt
->caches
, cxt
->ncaches
);
287 static void __fill_id( struct lscpu_cxt
*cxt
,
288 struct lscpu_cpu
*cpu
,
289 int id
, cpu_set_t
**map
,
291 char *buf
, size_t bufsz
)
295 if (cxt
->show_physical
) {
297 snprintf(buf
, bufsz
, "-");
299 snprintf(buf
, bufsz
, "%d", id
);
303 if (cpuset_ary_isset(cpu
->logical_id
, map
, nitems
,
304 cxt
->setsize
, &i
) == 0)
305 snprintf(buf
, bufsz
, "%zu", i
);
309 #define fill_id(_cxt, _cpu, NAME, _buf, _bufsz) \
310 __fill_id(_cxt, (_cpu), \
311 (_cpu)-> NAME ## id, \
312 (_cpu)->type-> NAME ## maps, \
313 (_cpu)->type->n ## NAME ## s, \
316 static char *get_cell_data(
317 struct lscpu_cxt
*cxt
,
318 struct lscpu_cpu
*cpu
, int col
,
319 char *buf
, size_t bufsz
)
330 snprintf(buf
, bufsz
, "%d", cpu
->logical_id
);
332 case COL_CPU_BOGOMIPS
:
334 xstrncpy(buf
, cpu
->bogomips
, bufsz
);
335 else if (cpu
->type
->bogomips
)
336 xstrncpy(buf
, cpu
->type
->bogomips
, bufsz
);
339 fill_id(cxt
, cpu
, core
, buf
, bufsz
);
342 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
344 case COL_CPU_CLUSTER
:
346 fill_id(cxt
, cpu
, socket
, buf
, bufsz
);
349 fill_id(cxt
, cpu
, drawer
, buf
, bufsz
);
352 fill_id(cxt
, cpu
, book
, buf
, bufsz
);
355 if (cpuset_ary_isset(cpu
->logical_id
, cxt
->nodemaps
,
356 cxt
->nnodes
, cxt
->setsize
, &i
) == 0)
357 snprintf(buf
, bufsz
, "%d", cxt
->idx2nodenum
[i
]);
361 const char *last
= NULL
;
365 for (i
= 0; i
< cxt
->ncaches
; i
++) {
367 struct lscpu_cache
*ca
;
368 const char *name
= cxt
->caches
[i
].name
;
370 if (last
&& strcmp(last
, name
) == 0)
373 ca
= lscpu_cpu_get_cache(cxt
, cpu
, name
);
376 x
= snprintf(p
, sz
, "%d", ca
->id
);
377 if (x
< 0 || (size_t) x
>= sz
)
383 *p
++ = cxt
->show_compatible
? ',' : ':';
387 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
391 case COL_CPU_POLARIZATION
:
392 if (cpu
->polarization
< 0)
394 snprintf(buf
, bufsz
, "%s",
395 cxt
->mode
== LSCPU_OUTPUT_PARSABLE
?
396 polar_modes
[cpu
->polarization
].parsable
:
397 polar_modes
[cpu
->polarization
].readable
);
399 case COL_CPU_ADDRESS
:
400 if (cpu
->address
< 0)
402 snprintf(buf
, bufsz
, "%d", cpu
->address
);
404 case COL_CPU_CONFIGURED
:
405 if (cpu
->configured
< 0)
407 if (cxt
->mode
== LSCPU_OUTPUT_PARSABLE
)
408 snprintf(buf
, bufsz
, "%s",
409 cpu
->configured
? _("Y") : _("N"));
411 snprintf(buf
, bufsz
, "%s",
412 cpu
->configured
? _("yes") : _("no"));
417 if (cxt
->mode
== LSCPU_OUTPUT_PARSABLE
)
418 snprintf(buf
, bufsz
, "%s",
419 is_cpu_online(cxt
, cpu
) ? _("Y") : _("N"));
421 snprintf(buf
, bufsz
, "%s",
422 is_cpu_online(cxt
, cpu
) ? _("yes") : _("no"));
426 xstrncpy(buf
, cpu
->mhz
, bufsz
);
429 if (cpu
->mhz_max_freq
)
430 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_max_freq
);
433 if (cpu
->mhz_min_freq
)
434 snprintf(buf
, bufsz
, "%.4f", cpu
->mhz_min_freq
);
440 static char *get_cell_header(
441 struct lscpu_cxt
*cxt
, int col
,
442 char *buf
, size_t bufsz
)
446 if (col
== COL_CPU_CACHE
) {
447 const char *last
= NULL
;
452 for (i
= 0; i
< cxt
->ncaches
; i
++) {
453 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
456 if (last
&& strcmp(last
, ca
->name
) == 0)
460 x
= snprintf(p
, sz
, "%s", ca
->name
);
461 if (x
< 0 || (size_t) x
>= sz
)
467 *p
++ = cxt
->show_compatible
? ',' : ':';
471 if (p
> buf
&& (*(p
- 1) == ',' || *(p
- 1) == ':'))
476 snprintf(buf
, bufsz
, "%s", coldescs_cpu
[col
].name
);
481 static void caches_add_line(struct lscpu_cxt
*cxt
,
482 struct libscols_table
*tb
,
483 struct lscpu_cache
*ca
,
484 int cols
[], size_t ncols
)
486 struct libscols_line
*ln
;
489 ln
= scols_table_new_line(tb
, NULL
);
491 err(EXIT_FAILURE
, _("failed to allocate output line"));
493 for (c
= 0; c
< ncols
; c
++) {
500 data
= xstrdup(ca
->name
);
502 case COL_CACHE_ONESIZE
:
506 xasprintf(&data
, "%" PRIu64
, ca
->size
);
508 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, ca
->size
);
510 case COL_CACHE_ALLSIZE
:
514 sz
= lscpu_get_cache_full_size(cxt
, ca
->name
, NULL
);
518 xasprintf(&data
, "%" PRIu64
, sz
);
520 data
= size_to_human_string(SIZE_SUFFIX_1LETTER
, sz
);
524 if (ca
->ways_of_associativity
)
525 xasprintf(&data
, "%u", ca
->ways_of_associativity
);
530 data
= xstrdup(ca
->type
);
532 case COL_CACHE_LEVEL
:
534 xasprintf(&data
, "%d", ca
->level
);
536 case COL_CACHE_ALLOCPOL
:
537 if (ca
->allocation_policy
)
538 data
= xstrdup(ca
->allocation_policy
);
540 case COL_CACHE_WRITEPOL
:
541 if (ca
->write_policy
)
542 data
= xstrdup(ca
->write_policy
);
544 case COL_CACHE_PHYLINE
:
545 if (ca
->physical_line_partition
)
546 xasprintf(&data
, "%u", ca
->physical_line_partition
);
549 if (ca
->number_of_sets
)
550 xasprintf(&data
, "%u", ca
->number_of_sets
);
552 case COL_CACHE_COHERENCYSIZE
:
553 if (ca
->coherency_line_size
)
554 xasprintf(&data
, "%u", ca
->coherency_line_size
);
558 if (data
&& scols_line_refer_data(ln
, c
, data
))
559 err(EXIT_FAILURE
, _("failed to add output data"));
567 static void print_caches_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
570 struct libscols_table
*tb
;
571 const char *last
= NULL
;
575 tb
= scols_new_table();
577 err(EXIT_FAILURE
, _("failed to allocate output table"));
579 scols_table_enable_json(tb
, 1);
580 scols_table_set_name(tb
, "caches");
583 for (i
= 0; i
< ncols
; i
++) {
584 struct lscpu_coldesc
*cd
= &coldescs_cache
[cols
[i
]];
585 if (!scols_table_new_column(tb
, cd
->name
, 0, cd
->flags
))
586 err(EXIT_FAILURE
, _("failed to allocate output column"));
589 /* standard caches */
590 for (i
= 0; i
< cxt
->ncaches
; i
++) {
591 struct lscpu_cache
*ca
= &cxt
->caches
[i
];
593 if (last
&& strcmp(last
, ca
->name
) == 0)
596 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
600 for (i
= 0; i
< cxt
->necaches
; i
++) {
601 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
603 if (last
&& strcmp(last
, ca
->name
) == 0)
606 caches_add_line(cxt
, tb
, ca
, cols
, ncols
);
609 scols_print_table(tb
);
610 scols_unref_table(tb
);
614 * [-p] backend, we support two parsable formats:
616 * 1) "compatible" -- this format is compatible with the original lscpu(1)
617 * output and it contains fixed set of the columns. The CACHE columns are at
618 * the end of the line and the CACHE is not printed if the number of the caches
619 * is zero. The CACHE columns are separated by two commas, for example:
622 * # CPU,Core,Socket,Node,,L1d,L1i,L2
626 * 2) "user defined output" -- this format prints always all columns without
627 * special prefix for CACHE column. If there are not CACHEs then the column is
628 * empty and the header "Cache" is printed rather than a real name of the cache.
629 * The CACHE columns are separated by ':'.
631 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
632 * # CPU,Core,Socket,Node,L1d:L1i:L2
636 static void print_cpus_parsable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
638 char buf
[BUFSIZ
], *data
;
645 "# The following is the parsable format, which can be fed to other\n"
646 "# programs. Each different item in every column has an unique ID\n"
647 "# starting usually from zero.\n"));
650 for (i
= 0; i
< ncols
; i
++) {
653 if (col
== COL_CPU_CACHE
) {
654 if (cxt
->show_compatible
&& !cxt
->ncaches
)
656 if (cxt
->show_compatible
&& i
!= 0)
662 data
= get_cell_header(cxt
, col
, buf
, sizeof(buf
));
663 if (data
&& * data
&& col
!= COL_CPU_CACHE
&&
664 !coldescs_cpu
[col
].is_abbr
) {
666 * For normal column names use mixed case (e.g. "Socket")
670 while (p
&& *p
!= '\0') {
671 *p
= tolower((unsigned int) *p
);
675 fputs(data
&& *data
? data
: "", stdout
);
682 for (i
= 0; i
< cxt
->npossibles
; i
++) {
683 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
687 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
689 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
692 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
695 for (c
= 0; c
< ncols
; c
++) {
696 if (cxt
->show_compatible
&& cols
[c
] == COL_CPU_CACHE
) {
705 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
706 fputs(data
&& *data
? data
: "", stdout
);
716 static void print_cpus_readable(struct lscpu_cxt
*cxt
, int cols
[], size_t ncols
)
721 struct libscols_table
*tb
;
725 tb
= scols_new_table();
727 err(EXIT_FAILURE
, _("failed to allocate output table"));
729 scols_table_enable_json(tb
, 1);
730 scols_table_set_name(tb
, "cpus");
733 for (i
= 0; i
< ncols
; i
++) {
734 data
= get_cell_header(cxt
, cols
[i
], buf
, sizeof(buf
));
735 if (!scols_table_new_column(tb
, data
, 0, coldescs_cpu
[cols
[i
]].flags
))
736 err(EXIT_FAILURE
, _("failed to allocate output column"));
739 for (i
= 0; i
< cxt
->npossibles
; i
++) {
741 struct libscols_line
*ln
;
742 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
745 if (!cxt
->show_offline
&& !is_cpu_online(cxt
, cpu
))
747 if (!cxt
->show_online
&& is_cpu_online(cxt
, cpu
))
751 if (cxt
->present
&& !is_cpu_present(cxt
, cpu
))
754 ln
= scols_table_new_line(tb
, NULL
);
756 err(EXIT_FAILURE
, _("failed to allocate output line"));
758 for (c
= 0; c
< ncols
; c
++) {
759 data
= get_cell_data(cxt
, cpu
, cols
[c
], buf
, sizeof(buf
));
762 if (scols_line_set_data(ln
, c
, data
))
763 err(EXIT_FAILURE
, _("failed to add output data"));
767 scols_print_table(tb
);
768 scols_unref_table(tb
);
771 static struct libscols_line
*
772 __attribute__ ((__format__(printf
, 4, 5)))
773 add_summary_sprint(struct libscols_table
*tb
,
774 struct libscols_line
*sec
,
779 struct libscols_line
*ln
;
782 /* Don't print section lines without data on non-terminal output */
783 if (!is_term
&& fmt
== NULL
)
786 ln
= scols_table_new_line(tb
, sec
);
788 err(EXIT_FAILURE
, _("failed to allocate output line"));
790 /* description column */
791 if (txt
&& scols_line_set_data(ln
, 0, txt
))
792 err(EXIT_FAILURE
, _("failed to add output data"));
798 xvasprintf(&data
, fmt
, args
);
801 if (data
&& scols_line_refer_data(ln
, 1, data
))
802 err(EXIT_FAILURE
, _("failed to add output data"));
808 #define add_summary_e(tb, sec, txt) add_summary_sprint(tb, sec, txt, NULL)
809 #define add_summary_n(tb, sec, txt, num) add_summary_sprint(tb, sec, txt, "%zu", num)
810 #define add_summary_s(tb, sec, txt, str) add_summary_sprint(tb, sec, txt, "%s", str)
811 #define add_summary_x(tb, sec, txt, fmt, x) add_summary_sprint(tb, sec, txt, fmt, x)
814 print_cpuset(struct lscpu_cxt
*cxt
,
815 struct libscols_table
*tb
,
816 struct libscols_line
*sec
,
817 const char *key
, cpu_set_t
*set
)
819 size_t setbuflen
= 7 * cxt
->maxcpus
;
820 char setbuf
[setbuflen
], *p
;
828 p
= cpumask_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
829 add_summary_s(tb
, sec
, key
, p
);
831 p
= cpulist_create(setbuf
, setbuflen
, set
, cxt
->setsize
);
832 add_summary_s(tb
, sec
, key
, p
);
837 print_summary_cputype(struct lscpu_cxt
*cxt
,
838 struct lscpu_cputype
*ct
,
839 struct libscols_table
*tb
,
840 struct libscols_line
*sec
)
843 sec
= add_summary_s(tb
, sec
, _("Model name:"), ct
->modelname
);
844 if (ct
->bios_modelname
)
845 add_summary_s(tb
, sec
, _("BIOS Model name:"), ct
->bios_modelname
);
847 add_summary_s(tb
, sec
, _("Machine type:"), ct
->machinetype
);
849 add_summary_s(tb
, sec
, _("CPU family:"), ct
->family
);
850 if (ct
->model
|| ct
->revision
)
851 add_summary_s(tb
, sec
, _("Model:"), ct
->revision
? ct
->revision
: ct
->model
);
853 add_summary_n(tb
, sec
, _("Thread(s) per core:"), ct
->nthreads_per_core
);
855 add_summary_n(tb
, sec
, _("Core(s) per cluster:"), ct
->ncores_per_socket
);
857 add_summary_n(tb
, sec
, _("Core(s) per socket:"), ct
->ncores_per_socket
);
860 add_summary_n(tb
, sec
, _("Socket(s) per book:"), ct
->nsockets_per_book
);
861 if (ct
->ndrawers_per_system
|| ct
->ndrawers
) {
862 add_summary_n(tb
, sec
, _("Book(s) per drawer:"), ct
->nbooks_per_drawer
);
863 add_summary_n(tb
, sec
, _("Drawer(s):"), ct
->ndrawers_per_system
?: ct
->ndrawers
);
865 add_summary_n(tb
, sec
, _("Book(s):"), ct
->nbooks_per_drawer
?: ct
->nbooks
);
867 if (cxt
->is_cluster
) {
868 if (ct
->nr_socket_on_cluster
> 0)
869 add_summary_n(tb
, sec
, _("Socket(s):"), ct
->nr_socket_on_cluster
);
871 add_summary_s(tb
, sec
, _("Socket(s):"), "-");
873 add_summary_n(tb
, sec
, _("Cluster(s):"),
874 ct
->nsockets_per_book
?: ct
->nsockets
);
876 add_summary_n(tb
, sec
, _("Socket(s):"),
877 ct
->nsockets_per_book
?: ct
->nsockets
);
881 add_summary_s(tb
, sec
, _("Stepping:"), ct
->stepping
);
882 if (ct
->freqboost
>= 0)
883 add_summary_s(tb
, sec
, _("Frequency boost:"), ct
->freqboost
?
884 _("enabled") : _("disabled"));
886 /* s390 -- from the first CPU where is dynamic/static MHz */
888 add_summary_s(tb
, sec
, _("CPU dynamic MHz:"), ct
->dynamic_mhz
);
890 add_summary_s(tb
, sec
, _("CPU static MHz:"), ct
->static_mhz
);
893 add_summary_x(tb
, sec
, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt
, ct
));
894 add_summary_x(tb
, sec
, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt
, ct
));
897 add_summary_s(tb
, sec
, _("BogoMIPS:"), ct
->bogomips
);
899 if (ct
->dispatching
>= 0)
900 add_summary_s(tb
, sec
, _("Dispatching mode:"), _(disp_modes
[ct
->dispatching
]));
902 if (ct
->physsockets
) {
903 add_summary_n(tb
, sec
, _("Physical sockets:"), ct
->physsockets
);
904 add_summary_n(tb
, sec
, _("Physical chips:"), ct
->physchips
);
905 add_summary_n(tb
, sec
, _("Physical cores/chip:"), ct
->physcoresperchip
);
909 add_summary_s(tb
, sec
, _("Flags:"), ct
->flags
);
915 static void print_summary(struct lscpu_cxt
*cxt
)
917 struct lscpu_cputype
*ct
;
920 struct libscols_table
*tb
;
921 struct libscols_line
*sec
= NULL
;
926 tb
= scols_new_table();
928 err(EXIT_FAILURE
, _("failed to allocate output table"));
930 scols_table_enable_noheadings(tb
, 1);
932 scols_table_enable_json(tb
, 1);
933 scols_table_set_name(tb
, "lscpu");
934 } else if (is_term
) {
935 struct libscols_symbols
*sy
= scols_new_symbols();
939 scols_symbols_set_branch(sy
, " ");
940 scols_symbols_set_vertical(sy
, " ");
941 scols_symbols_set_right(sy
, " ");
942 scols_table_set_symbols(tb
, sy
);
943 scols_unref_symbols(sy
);
946 if (scols_table_new_column(tb
, "field", 0, is_term
? SCOLS_FL_TREE
: 0) == NULL
||
947 scols_table_new_column(tb
, "data", 0, SCOLS_FL_NOEXTREMES
| SCOLS_FL_WRAP
) == NULL
)
948 err(EXIT_FAILURE
, _("failed to initialize output column"));
950 ct
= lscpu_cputype_get_default(cxt
);
952 /* Section: architecture */
954 sec
= add_summary_s(tb
, NULL
, _("Architecture:"), cxt
->arch
->name
);
955 if (cxt
->arch
&& (cxt
->arch
->bit32
|| cxt
->arch
->bit64
)) {
956 char buf
[32], *p
= buf
;
958 if (cxt
->arch
->bit32
) {
959 strcpy(p
, "32-bit, ");
962 if (cxt
->arch
->bit64
) {
963 strcpy(p
, "64-bit, ");
967 add_summary_s(tb
, sec
, _("CPU op-mode(s):"), buf
);
970 add_summary_s(tb
, sec
, _("Address sizes:"), ct
->addrsz
);
971 #if !defined(WORDS_BIGENDIAN)
972 add_summary_s(tb
, sec
, _("Byte Order:"), "Little Endian");
974 add_summary_s(tb
, sec
, _("Byte Order:"), "Big Endian");
977 /* Section: CPU lists */
978 sec
= add_summary_n(tb
, NULL
, _("CPU(s):"), cxt
->npresents
);
981 print_cpuset(cxt
, tb
, sec
,
982 cxt
->hex
? _("On-line CPU(s) mask:") :
983 _("On-line CPU(s) list:"),
986 if (cxt
->online
&& cxt
->nonlines
!= cxt
->npresents
) {
989 /* Linux kernel provides cpuset of off-line CPUs that contains
990 * all configured CPUs (see /sys/devices/system/cpu/offline),
991 * but want to print real (present in system) off-line CPUs only.
993 set
= cpuset_alloc(cxt
->maxcpus
, NULL
, NULL
);
995 err(EXIT_FAILURE
, _("failed to callocate cpu set"));
996 CPU_ZERO_S(cxt
->setsize
, set
);
997 for (i
= 0; i
< cxt
->npossibles
; i
++) {
998 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
1000 if (cpu
&& is_cpu_present(cxt
, cpu
) && !is_cpu_online(cxt
, cpu
))
1001 CPU_SET_S(cpu
->logical_id
, cxt
->setsize
, set
);
1003 print_cpuset(cxt
, tb
, sec
,
1004 cxt
->hex
? _("Off-line CPU(s) mask:") :
1005 _("Off-line CPU(s) list:"), set
);
1010 /* Section: cpu type description */
1012 sec
= add_summary_s(tb
, NULL
, _("Vendor ID:"), ct
->vendor
);
1013 if (ct
->bios_vendor
)
1014 add_summary_s(tb
, sec
, _("BIOS Vendor ID:"), ct
->bios_vendor
);
1016 for (i
= 0; i
< cxt
->ncputypes
; i
++)
1017 print_summary_cputype(cxt
, cxt
->cputypes
[i
], tb
, sec
);
1020 /* Section: vitualiazation */
1022 sec
= add_summary_e(tb
, NULL
, _("Virtualization features:"));
1023 if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "svm"))
1024 add_summary_s(tb
, sec
, _("Virtualization:"), "AMD-V");
1025 else if (cxt
->virt
->cpuflag
&& !strcmp(cxt
->virt
->cpuflag
, "vmx"))
1026 add_summary_s(tb
, sec
, _("Virtualization:"), "VT-x");
1028 if (cxt
->virt
->hypervisor
)
1029 add_summary_s(tb
, sec
, _("Hypervisor:"), cxt
->virt
->hypervisor
);
1030 if (cxt
->virt
->vendor
) {
1031 add_summary_s(tb
, sec
, _("Hypervisor vendor:"), hv_vendors
[cxt
->virt
->vendor
]);
1032 add_summary_s(tb
, sec
, _("Virtualization type:"), _(virt_types
[cxt
->virt
->type
]));
1037 /* Section: caches */
1039 const char *last
= NULL
;
1041 /* The caches are sorted by name, cxt->caches[] may contains
1042 * multiple instances for the same name.
1044 for (i
= 0; i
< cxt
->ncaches
; i
++) {
1045 const char *name
= cxt
->caches
[i
].name
;
1049 if (last
&& strcmp(last
, name
) == 0)
1051 sz
= lscpu_get_cache_full_size(cxt
, name
, &n
);
1055 sec
= add_summary_e(tb
, NULL
, _("Caches (sum of all):"));
1059 snprintf(field
, sizeof(field
), is_term
? _("%s:") : _("%s cache:"), name
);
1061 add_summary_sprint(tb
, sec
, field
,
1062 P_("%" PRIu64
" (%d instance)",
1063 "%" PRIu64
" (%d instances)", n
),
1066 char *tmp
= size_to_human_string(
1067 SIZE_SUFFIX_3LETTER
|
1070 add_summary_sprint(tb
, sec
, field
,
1071 P_("%s (%d instance)",
1072 "%s (%d instances)", n
),
1080 for (i
= 0; i
< cxt
->necaches
; i
++) {
1081 struct lscpu_cache
*ca
= &cxt
->ecaches
[i
];
1086 sec
= add_summary_e(tb
, NULL
, _("Caches:"));
1089 snprintf(field
, sizeof(field
), is_term
? _("%s:") : _("%s cache:"), ca
->name
);
1091 add_summary_x(tb
, sec
, field
, "%" PRIu64
, ca
->size
);
1093 char *tmp
= size_to_human_string(
1094 SIZE_SUFFIX_3LETTER
|
1097 add_summary_s(tb
, sec
, field
, tmp
);
1103 /* Section: NUMA modes */
1105 sec
= add_summary_e(tb
, NULL
, _("NUMA:"));
1107 add_summary_n(tb
, sec
,_("NUMA node(s):"), cxt
->nnodes
);
1108 for (i
= 0; i
< cxt
->nnodes
; i
++) {
1109 snprintf(field
, sizeof(field
), _("NUMA node%d CPU(s):"), cxt
->idx2nodenum
[i
]);
1110 print_cpuset(cxt
, tb
, sec
, field
, cxt
->nodemaps
[i
]);
1115 /* Section: Vulnerabilities */
1117 sec
= add_summary_e(tb
, NULL
, _("Vulnerabilities:"));
1119 for (i
= 0; i
< cxt
->nvuls
; i
++) {
1120 snprintf(field
, sizeof(field
), is_term
?
1121 _("%s:") : _("Vulnerability %s:"), cxt
->vuls
[i
].name
);
1122 add_summary_s(tb
, sec
, field
, cxt
->vuls
[i
].text
);
1126 scols_print_table(tb
);
1127 scols_unref_table(tb
);
1130 static void __attribute__((__noreturn__
)) usage(void)
1135 fputs(USAGE_HEADER
, out
);
1136 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
1138 fputs(USAGE_SEPARATOR
, out
);
1139 fputs(_("Display information about the CPU architecture.\n"), out
);
1141 fputs(USAGE_OPTIONS
, out
);
1142 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out
);
1143 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out
);
1144 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out
);
1145 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out
);
1146 fputs(_(" -c, --offline print offline CPUs only\n"), out
);
1147 fputs(_(" -J, --json use JSON for default or extended format\n"), out
);
1148 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out
);
1149 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out
);
1150 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out
);
1151 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out
);
1152 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out
);
1153 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out
);
1154 fputs(USAGE_SEPARATOR
, out
);
1155 printf(USAGE_HELP_OPTIONS(25));
1157 fputs(_("\nAvailable output columns for -e or -p:\n"), out
);
1158 for (i
= 0; i
< ARRAY_SIZE(coldescs_cpu
); i
++)
1159 fprintf(out
, " %13s %s\n", coldescs_cpu
[i
].name
, _(coldescs_cpu
[i
].help
));
1161 fputs(_("\nAvailable output columns for -C:\n"), out
);
1162 for (i
= 0; i
< ARRAY_SIZE(coldescs_cache
); i
++)
1163 fprintf(out
, " %13s %s\n", coldescs_cache
[i
].name
, _(coldescs_cache
[i
].help
));
1165 printf(USAGE_MAN_TAIL("lscpu(1)"));
1170 int main(int argc
, char *argv
[])
1172 struct lscpu_cxt
*cxt
;
1174 int columns
[ARRAY_SIZE(coldescs_cpu
)];
1175 int cpu_modifier_specified
= 0;
1176 char *outarg
= NULL
;
1177 size_t i
, ncolumns
= 0;
1179 OPT_OUTPUT_ALL
= CHAR_MAX
+ 1,
1181 static const struct option longopts
[] = {
1182 { "all", no_argument
, NULL
, 'a' },
1183 { "online", no_argument
, NULL
, 'b' },
1184 { "bytes", no_argument
, NULL
, 'B' },
1185 { "caches", optional_argument
, NULL
, 'C' },
1186 { "offline", no_argument
, NULL
, 'c' },
1187 { "help", no_argument
, NULL
, 'h' },
1188 { "extended", optional_argument
, NULL
, 'e' },
1189 { "json", no_argument
, NULL
, 'J' },
1190 { "parse", optional_argument
, NULL
, 'p' },
1191 { "sysroot", required_argument
, NULL
, 's' },
1192 { "physical", no_argument
, NULL
, 'y' },
1193 { "hex", no_argument
, NULL
, 'x' },
1194 { "version", no_argument
, NULL
, 'V' },
1195 { "output-all", no_argument
, NULL
, OPT_OUTPUT_ALL
},
1196 { NULL
, 0, NULL
, 0 }
1199 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
1204 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1206 setlocale(LC_ALL
, "");
1207 bindtextdomain(PACKAGE
, LOCALEDIR
);
1208 textdomain(PACKAGE
);
1209 close_stdout_atexit();
1211 cxt
= lscpu_new_context();
1213 while ((c
= getopt_long(argc
, argv
, "aBbC::ce::hJp::s:xyV", longopts
, NULL
)) != -1) {
1215 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1219 cxt
->show_online
= cxt
->show_offline
= 1;
1220 cpu_modifier_specified
= 1;
1226 cxt
->show_online
= 1;
1227 cpu_modifier_specified
= 1;
1230 cxt
->show_offline
= 1;
1231 cpu_modifier_specified
= 1;
1239 cxt
->mode
= LSCPU_OUTPUT_CACHES
;
1251 cxt
->mode
= c
== 'p' ? LSCPU_OUTPUT_PARSABLE
: LSCPU_OUTPUT_READABLE
;
1254 cxt
->prefix
= optarg
;
1261 cxt
->show_physical
= 1;
1263 case OPT_OUTPUT_ALL
:
1270 print_version(EXIT_SUCCESS
);
1272 errtryhelp(EXIT_FAILURE
);
1276 if (all
&& ncolumns
== 0) {
1277 size_t maxsz
= cxt
->mode
== LSCPU_OUTPUT_CACHES
?
1278 ARRAY_SIZE(coldescs_cache
) :
1279 ARRAY_SIZE(coldescs_cpu
);
1281 for (i
= 0; i
< maxsz
; i
++)
1282 columns
[ncolumns
++] = i
;
1285 if (cpu_modifier_specified
&& cxt
->mode
== LSCPU_OUTPUT_SUMMARY
) {
1287 _("%s: options --all, --online and --offline may only "
1288 "be used with options --extended or --parse.\n"),
1289 program_invocation_short_name
);
1290 return EXIT_FAILURE
;
1293 if (argc
!= optind
) {
1294 warnx(_("bad usage"));
1295 errtryhelp(EXIT_FAILURE
);
1298 /* set default cpu display mode if none was specified */
1299 if (!cxt
->show_online
&& !cxt
->show_offline
) {
1300 cxt
->show_online
= 1;
1301 cxt
->show_offline
= cxt
->mode
== LSCPU_OUTPUT_READABLE
? 1 : 0;
1304 is_term
= isatty(STDOUT_FILENO
); /* global variable */
1308 lscpu_context_init_paths(cxt
);
1310 lscpu_read_cpulists(cxt
);
1311 lscpu_read_cpuinfo(cxt
);
1312 cxt
->arch
= lscpu_read_architecture(cxt
);
1314 lscpu_read_archext(cxt
);
1315 lscpu_read_vulnerabilities(cxt
);
1316 lscpu_read_numas(cxt
);
1317 lscpu_read_topology(cxt
);
1319 lscpu_decode_arm(cxt
);
1321 cxt
->virt
= lscpu_read_virtualization(cxt
);
1324 case LSCPU_OUTPUT_SUMMARY
:
1327 case LSCPU_OUTPUT_CACHES
:
1329 columns
[ncolumns
++] = COL_CACHE_NAME
;
1330 columns
[ncolumns
++] = COL_CACHE_ONESIZE
;
1331 columns
[ncolumns
++] = COL_CACHE_ALLSIZE
;
1332 columns
[ncolumns
++] = COL_CACHE_WAYS
;
1333 columns
[ncolumns
++] = COL_CACHE_TYPE
;
1334 columns
[ncolumns
++] = COL_CACHE_LEVEL
;
1335 columns
[ncolumns
++] = COL_CACHE_SETS
;
1336 columns
[ncolumns
++] = COL_CACHE_PHYLINE
;
1337 columns
[ncolumns
++] = COL_CACHE_COHERENCYSIZE
;
1339 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1340 ARRAY_SIZE(columns
),
1341 &ncolumns
, cache_column_name_to_id
) < 0)
1342 return EXIT_FAILURE
;
1344 print_caches_readable(cxt
, columns
, ncolumns
);
1346 case LSCPU_OUTPUT_READABLE
:
1348 /* No list was given. Just print whatever is there. */
1349 struct lscpu_cputype
*ct
= lscpu_cputype_get_default(cxt
);
1351 columns
[ncolumns
++] = COL_CPU_CPU
;
1353 columns
[ncolumns
++] = COL_CPU_NODE
;
1354 if (ct
&& ct
->ndrawers
)
1355 columns
[ncolumns
++] = COL_CPU_DRAWER
;
1356 if (ct
&& ct
->nbooks
)
1357 columns
[ncolumns
++] = COL_CPU_BOOK
;
1358 if (ct
&& ct
->nsockets
) {
1359 if (cxt
->is_cluster
)
1360 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1362 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1364 if (ct
&& ct
->ncores
)
1365 columns
[ncolumns
++] = COL_CPU_CORE
;
1367 columns
[ncolumns
++] = COL_CPU_CACHE
;
1369 columns
[ncolumns
++] = COL_CPU_ONLINE
;
1370 if (ct
&& ct
->has_configured
)
1371 columns
[ncolumns
++] = COL_CPU_CONFIGURED
;
1372 if (ct
&& ct
->has_polarization
)
1373 columns
[ncolumns
++] = COL_CPU_POLARIZATION
;
1374 if (ct
&& ct
->has_addresses
)
1375 columns
[ncolumns
++] = COL_CPU_ADDRESS
;
1376 if (ct
&& ct
->has_freq
) {
1377 columns
[ncolumns
++] = COL_CPU_MAXMHZ
;
1378 columns
[ncolumns
++] = COL_CPU_MINMHZ
;
1379 columns
[ncolumns
++] = COL_CPU_MHZ
;
1382 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1383 ARRAY_SIZE(columns
),
1384 &ncolumns
, cpu_column_name_to_id
) < 0)
1385 return EXIT_FAILURE
;
1386 print_cpus_readable(cxt
, columns
, ncolumns
);
1388 case LSCPU_OUTPUT_PARSABLE
:
1390 columns
[ncolumns
++] = COL_CPU_CPU
;
1391 columns
[ncolumns
++] = COL_CPU_CORE
;
1392 if (cxt
->is_cluster
)
1393 columns
[ncolumns
++] = COL_CPU_CLUSTER
;
1395 columns
[ncolumns
++] = COL_CPU_SOCKET
;
1396 columns
[ncolumns
++] = COL_CPU_NODE
;
1397 columns
[ncolumns
++] = COL_CPU_CACHE
;
1398 cxt
->show_compatible
= 1;
1400 if (outarg
&& string_add_to_idarray(outarg
, columns
,
1401 ARRAY_SIZE(columns
),
1402 &ncolumns
, cpu_column_name_to_id
) < 0)
1403 return EXIT_FAILURE
;
1405 print_cpus_parsable(cxt
, columns
, ncolumns
);
1409 lscpu_free_context(cxt
);
1411 return EXIT_SUCCESS
;