]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu.c
Merge branch 'cdown/2022-10-26/check_handler' of https://github.com/cdown/util-linux
[thirdparty/util-linux.git] / sys-utils / lscpu.c
CommitLineData
5dd7507c
CQ
1/*
2 * lscpu - CPU architecture information helper
3 *
4 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
5 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
6 *
80dde62f 7 * This program is free software; you can redistribute it and/or modify
5dd7507c 8 * it under the terms of the GNU General Public License as published by
80dde62f 9 * the Free Software Foundation; either version 2 of the License, or
5dd7507c
CQ
10 * (at your option) any later version.
11 *
80dde62f 12 * This program is distributed in the hope that it would be useful,
5dd7507c
CQ
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
7cebf0bb
SK
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
5dd7507c
CQ
20 */
21
5bd31c6d 22#include <assert.h>
5dd7507c
CQ
23#include <ctype.h>
24#include <dirent.h>
5dd7507c
CQ
25#include <errno.h>
26#include <fcntl.h>
27#include <getopt.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/utsname.h>
32#include <unistd.h>
33#include <stdarg.h>
39561c70
KZ
34#include <sys/types.h>
35#include <sys/stat.h>
32865bd5 36#include <sys/personality.h>
5dd7507c 37
83db4eb2
OO
38#include <libsmartcols.h>
39
efb8854f 40#include "closestream.h"
41a8940d 41#include "optutils.h"
aff94add 42#include "c_strtod.h"
71061694 43
fb2627ce 44#include "lscpu.h"
0ebbe9f1 45
2ba641e5 46static const char *virt_types[] = {
7454b598
KZ
47 [VIRT_TYPE_NONE] = N_("none"),
48 [VIRT_TYPE_PARA] = N_("para"),
49 [VIRT_TYPE_FULL] = N_("full"),
50 [VIRT_TYPE_CONTAINER] = N_("container"),
c8b64f6d
KZ
51};
52
2ba641e5 53static const char *hv_vendors[] = {
7454b598
KZ
54 [VIRT_VENDOR_NONE] = NULL,
55 [VIRT_VENDOR_XEN] = "Xen",
56 [VIRT_VENDOR_KVM] = "KVM",
57 [VIRT_VENDOR_MSHV] = "Microsoft",
f2aadc11 58 [VIRT_VENDOR_VMWARE] = "VMware",
7454b598
KZ
59 [VIRT_VENDOR_IBM] = "IBM",
60 [VIRT_VENDOR_VSERVER] = "Linux-VServer",
61 [VIRT_VENDOR_UML] = "User-mode Linux",
62 [VIRT_VENDOR_INNOTEK] = "Innotek GmbH",
63 [VIRT_VENDOR_HITACHI] = "Hitachi",
f2aadc11 64 [VIRT_VENDOR_PARALLELS] = "Parallels",
7454b598
KZ
65 [VIRT_VENDOR_VBOX] = "Oracle",
66 [VIRT_VENDOR_OS400] = "OS/400",
67 [VIRT_VENDOR_PHYP] = "pHyp",
68 [VIRT_VENDOR_SPAR] = "Unisys s-Par",
69 [VIRT_VENDOR_WSL] = "Windows Subsystem for Linux"
96ce475f
RM
70};
71
a0fff77e 72/* dispatching modes */
2ba641e5 73static const char *disp_modes[] = {
a0fff77e
HC
74 [DISP_HORIZONTAL] = N_("horizontal"),
75 [DISP_VERTICAL] = N_("vertical")
76};
77
f9ac0210
KZ
78struct polarization_modes {
79 char *parsable;
80 char *readable;
81};
82
2ba641e5 83static struct polarization_modes polar_modes[] = {
0a0af616
KZ
84 [POLAR_UNKNOWN] = {"U", "-"},
85 [POLAR_VLOW] = {"VL", "vert-low"},
86 [POLAR_VMEDIUM] = {"VM", "vert-medium"},
87 [POLAR_VHIGH] = {"VH", "vert-high"},
8005924a 88 [POLAR_HORIZONTAL] = {"H", "horizontal"},
2b8fcb81
HC
89};
90
477251f8 91/*
3d27b76a 92 * IDs
477251f8
KZ
93 */
94enum {
cc94324e 95 COL_CPU_BOGOMIPS,
cc07239d
KZ
96 COL_CPU_CPU,
97 COL_CPU_CORE,
98 COL_CPU_SOCKET,
73c0a766 99 COL_CPU_CLUSTER,
cc07239d
KZ
100 COL_CPU_NODE,
101 COL_CPU_BOOK,
102 COL_CPU_DRAWER,
103 COL_CPU_CACHE,
104 COL_CPU_POLARIZATION,
105 COL_CPU_ADDRESS,
106 COL_CPU_CONFIGURED,
107 COL_CPU_ONLINE,
6d880d3d 108 COL_CPU_MHZ,
9b9e4f5d 109 COL_CPU_SCALMHZ,
cc07239d
KZ
110 COL_CPU_MAXMHZ,
111 COL_CPU_MINMHZ,
1d956847 112 COL_CPU_MODELNAME,
477251f8
KZ
113};
114
0e86bc84
KZ
115enum {
116 COL_CACHE_ALLSIZE,
117 COL_CACHE_LEVEL,
118 COL_CACHE_NAME,
119 COL_CACHE_ONESIZE,
120 COL_CACHE_TYPE,
121 COL_CACHE_WAYS,
cf3b6b71
KZ
122 COL_CACHE_ALLOCPOL,
123 COL_CACHE_WRITEPOL,
124 COL_CACHE_PHYLINE,
125 COL_CACHE_SETS,
126 COL_CACHE_COHERENCYSIZE
0e86bc84
KZ
127};
128
129
3d27b76a
KZ
130/* column description
131 */
132struct lscpu_coldesc {
133 const char *name;
134 const char *help;
135
0e86bc84 136 int flags;
3d27b76a 137 unsigned int is_abbr:1; /* name is abbreviation */
17353ee0 138 int json_type;
477251f8
KZ
139};
140
cc07239d 141static struct lscpu_coldesc coldescs_cpu[] =
3d27b76a 142{
17353ee0
TW
143 [COL_CPU_BOGOMIPS] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT, 1, SCOLS_JSON_NUMBER },
144 [COL_CPU_CPU] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT, 1, SCOLS_JSON_NUMBER },
145 [COL_CPU_CORE] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
146 [COL_CPU_CLUSTER] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
147 [COL_CPU_SOCKET] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
148 [COL_CPU_NODE] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
149 [COL_CPU_BOOK] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
150 [COL_CPU_DRAWER] = { "DRAWER", N_("logical drawer number"), SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER },
cc07239d
KZ
151 [COL_CPU_CACHE] = { "CACHE", N_("shows how caches are shared between CPUs") },
152 [COL_CPU_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
153 [COL_CPU_ADDRESS] = { "ADDRESS", N_("physical address of a CPU") },
87579a96
TW
154 [COL_CPU_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU"), 0, 0, SCOLS_JSON_BOOLEAN_OPTIONAL },
155 [COL_CPU_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_BOOLEAN_OPTIONAL },
79884c5d 156 [COL_CPU_MHZ] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
17353ee0
TW
157 [COL_CPU_SCALMHZ] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER },
158 [COL_CPU_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
1d956847
KZ
159 [COL_CPU_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
160 [COL_CPU_MODELNAME] = { "MODELNAME", N_("shows CPU model name"), 0, 0, SCOLS_JSON_STRING }
0e86bc84
KZ
161};
162
163static struct lscpu_coldesc coldescs_cache[] =
164{
165 [COL_CACHE_ALLSIZE] = { "ALL-SIZE", N_("size of all system caches"), SCOLS_FL_RIGHT },
17353ee0 166 [COL_CACHE_LEVEL] = { "LEVEL", N_("cache level"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
0e86bc84
KZ
167 [COL_CACHE_NAME] = { "NAME", N_("cache name") },
168 [COL_CACHE_ONESIZE] = { "ONE-SIZE", N_("size of one cache"), SCOLS_FL_RIGHT },
169 [COL_CACHE_TYPE] = { "TYPE", N_("cache type") },
17353ee0 170 [COL_CACHE_WAYS] = { "WAYS", N_("ways of associativity"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
cf3b6b71
KZ
171 [COL_CACHE_ALLOCPOL] = { "ALLOC-POLICY", N_("allocation policy") },
172 [COL_CACHE_WRITEPOL] = { "WRITE-POLICY", N_("write policy") },
b956bc86 173 [COL_CACHE_PHYLINE] = { "PHY-LINE", N_("number of physical cache line per cache tag"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
17353ee0
TW
174 [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 },
175 [COL_CACHE_COHERENCYSIZE] = { "COHERENCY-SIZE", N_("minimum amount of data in bytes transferred from memory to cache"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER }
3d27b76a 176};
477251f8 177
c9121791 178static int hierarchic = -1;
91eef60c 179
43715b4e
KZ
180UL_DEBUG_DEFINE_MASK(lscpu);
181UL_DEBUG_DEFINE_MASKNAMES(lscpu) = UL_DEBUG_EMPTY_MASKNAMES;
182
183static void lscpu_init_debug(void)
184{
185 __UL_INIT_DEBUG_FROM_ENV(lscpu, LSCPU_DEBUG_, 0, LSCPU_DEBUG);
186}
187
583f14cc 188static int
cc07239d 189cpu_column_name_to_id(const char *name, size_t namesz)
477251f8 190{
329fd1c3 191 size_t i;
477251f8 192
cc07239d
KZ
193 for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++) {
194 const char *cn = coldescs_cpu[i].name;
477251f8
KZ
195
196 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
197 return i;
198 }
199 warnx(_("unknown column: %s"), name);
200 return -1;
201}
202
0e86bc84
KZ
203static int
204cache_column_name_to_id(const char *name, size_t namesz)
205{
206 size_t i;
207
208 for (i = 0; i < ARRAY_SIZE(coldescs_cache); i++) {
209 const char *cn = coldescs_cache[i].name;
210
211 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
212 return i;
213 }
214 warnx(_("unknown column: %s"), name);
215 return -1;
216}
217
27c349f9
KZ
218static void lscpu_context_init_paths(struct lscpu_cxt *cxt)
219{
220 DBG(MISC, ul_debugobj(cxt, "initialize paths"));
221 ul_path_init_debug();
222
223 /* /sys/devices/system/cpu */
224 cxt->syscpu = ul_new_path(_PATH_SYS_CPU);
225 if (!cxt->syscpu)
226 err(EXIT_FAILURE, _("failed to initialize CPUs sysfs handler"));
227 if (cxt->prefix)
228 ul_path_set_prefix(cxt->syscpu, cxt->prefix);
229
230 /* /proc */
231 cxt->procfs = ul_new_path("/proc");
232 if (!cxt->procfs)
233 err(EXIT_FAILURE, _("failed to initialize procfs handler"));
234 if (cxt->prefix)
235 ul_path_set_prefix(cxt->procfs, cxt->prefix);
236}
237
238static struct lscpu_cxt *lscpu_new_context(void)
239{
240 return xcalloc(1, sizeof(struct lscpu_cxt));
241}
242
243static void lscpu_free_context(struct lscpu_cxt *cxt)
244{
245 size_t i;
246
247 if (!cxt)
248 return;
249
250 DBG(MISC, ul_debugobj(cxt, "freeing context"));
251
252 DBG(MISC, ul_debugobj(cxt, " de-initialize paths"));
253 ul_unref_path(cxt->syscpu);
254 ul_unref_path(cxt->procfs);
255
256 DBG(MISC, ul_debugobj(cxt, " freeing cpus"));
257 for (i = 0; i < cxt->npossibles; i++) {
258 lscpu_unref_cpu(cxt->cpus[i]);
259 cxt->cpus[i] = NULL;
260 }
261 DBG(MISC, ul_debugobj(cxt, " freeing types"));
262 for (i = 0; i < cxt->ncputypes; i++) {
263 lscpu_unref_cputype(cxt->cputypes[i]);
264 cxt->cputypes[i] = NULL;
265 }
266
267 free(cxt->present);
268 free(cxt->online);
269 free(cxt->cputypes);
270 free(cxt->cpus);
271
272 for (i = 0; i < cxt->nvuls; i++) {
273 free(cxt->vuls[i].name);
274 free(cxt->vuls[i].text);
275 }
276 free(cxt->vuls);
277
278 for (i = 0; i < cxt->nnodes; i++)
279 free(cxt->nodemaps[i]);
280
281 free(cxt->nodemaps);
282 free(cxt->idx2nodenum);
283
284 lscpu_free_virtualization(cxt->virt);
285 lscpu_free_architecture(cxt->arch);
6fbb5328 286
27c349f9 287 lscpu_free_caches(cxt->ecaches, cxt->necaches);
6fbb5328 288 lscpu_free_caches(cxt->caches, cxt->ncaches);
27c349f9
KZ
289
290 free(cxt);
291}
292
63c5e7f8
KZ
293static void __fill_id( struct lscpu_cxt *cxt,
294 struct lscpu_cpu *cpu,
295 int id, cpu_set_t **map,
296 size_t nitems,
297 char *buf, size_t bufsz)
298{
299 *buf = '\0';
300
301 if (cxt->show_physical) {
302 if (id < 0)
303 snprintf(buf, bufsz, "-");
304 else
305 snprintf(buf, bufsz, "%d", id);
306 } else if (map) {
307 size_t i;
308
309 if (cpuset_ary_isset(cpu->logical_id, map, nitems,
310 cxt->setsize, &i) == 0)
311 snprintf(buf, bufsz, "%zu", i);
312 }
313}
5dd7507c 314
17353ee0
TW
315static void get_cell_boolean(
316 struct lscpu_cxt *cxt,
317 int has_data, int data,
318 char *buf, size_t bufsz)
319{
320 if (!has_data)
321 return;
322
323 if (cxt->mode == LSCPU_OUTPUT_PARSABLE || cxt->json)
324 snprintf(buf, bufsz, "%s",
325 data ? _("Y") : _("N"));
326 else
327 snprintf(buf, bufsz, "%s",
328 data ? _("yes") : _("no"));
329}
330
63c5e7f8
KZ
331#define fill_id(_cxt, _cpu, NAME, _buf, _bufsz) \
332 __fill_id(_cxt, (_cpu), \
333 (_cpu)-> NAME ## id, \
334 (_cpu)->type-> NAME ## maps, \
335 (_cpu)->type->n ## NAME ## s, \
336 _buf, _bufsz)
337
338static char *get_cell_data(
339 struct lscpu_cxt *cxt,
340 struct lscpu_cpu *cpu, int col,
341 char *buf, size_t bufsz)
5dd7507c 342{
4f642863 343 size_t i;
e3b3a2f3
KZ
344
345 *buf = '\0';
5dd7507c 346
63c5e7f8
KZ
347 if (!cpu->type)
348 return NULL;
349
477251f8 350 switch (col) {
cc07239d 351 case COL_CPU_CPU:
63c5e7f8 352 snprintf(buf, bufsz, "%d", cpu->logical_id);
477251f8 353 break;
cc94324e 354 case COL_CPU_BOGOMIPS:
aff94add
KZ
355 if (!cpu->bogomips && !cpu->type->bogomips)
356 break;
357 snprintf(buf, bufsz, "%.2f", (float) c_strtod(
358 cpu->bogomips ? : cpu->type->bogomips, NULL));
cc94324e 359 break;
cc07239d 360 case COL_CPU_CORE:
63c5e7f8 361 fill_id(cxt, cpu, core, buf, bufsz);
477251f8 362 break;
cc07239d 363 case COL_CPU_SOCKET:
63c5e7f8 364 fill_id(cxt, cpu, socket, buf, bufsz);
477251f8 365 break;
73c0a766
MM
366 case COL_CPU_CLUSTER:
367 if (cxt->is_cluster)
368 fill_id(cxt, cpu, socket, buf, bufsz);
369 break;
cc07239d 370 case COL_CPU_DRAWER:
63c5e7f8 371 fill_id(cxt, cpu, drawer, buf, bufsz);
b3adf6ef 372 break;
cc07239d 373 case COL_CPU_BOOK:
63c5e7f8
KZ
374 fill_id(cxt, cpu, book, buf, bufsz);
375 break;
376 case COL_CPU_NODE:
377 if (cpuset_ary_isset(cpu->logical_id, cxt->nodemaps,
378 cxt->nnodes, cxt->setsize, &i) == 0)
379 snprintf(buf, bufsz, "%d", cxt->idx2nodenum[i]);
477251f8 380 break;
cc07239d 381 case COL_CPU_CACHE:
e3b3a2f3 382 {
63c5e7f8 383 const char *last = NULL;
e3b3a2f3
KZ
384 char *p = buf;
385 size_t sz = bufsz;
e3b3a2f3 386
63c5e7f8
KZ
387 for (i = 0; i < cxt->ncaches; i++) {
388 int x;
389 struct lscpu_cache *ca;
390 const char *name = cxt->caches[i].name;
e9d659ea 391
63c5e7f8
KZ
392 if (last && strcmp(last, name) == 0)
393 continue;
394 last = name;
395 ca = lscpu_cpu_get_cache(cxt, cpu, name);
396 if (!ca)
397 continue;
398 x = snprintf(p, sz, "%d", ca->id);
399 if (x < 0 || (size_t) x >= sz)
400 return NULL;
401 p += x;
402 sz -= x;
e07cca6b
KZ
403 if (sz < 2)
404 return NULL;
405 *p++ = cxt->show_compatible ? ',' : ':';
406 *p = '\0';
407 sz--;
5dd7507c 408 }
e07cca6b
KZ
409 if (p > buf && (*(p - 1) == ',' || *(p - 1) == ':'))
410 *(p - 1) = '\0';
477251f8 411 break;
e3b3a2f3 412 }
cc07239d 413 case COL_CPU_POLARIZATION:
63c5e7f8
KZ
414 if (cpu->polarization < 0)
415 break;
416 snprintf(buf, bufsz, "%s",
417 cxt->mode == LSCPU_OUTPUT_PARSABLE ?
418 polar_modes[cpu->polarization].parsable :
419 polar_modes[cpu->polarization].readable);
2b8fcb81 420 break;
cc07239d 421 case COL_CPU_ADDRESS:
63c5e7f8
KZ
422 if (cpu->address < 0)
423 break;
424 snprintf(buf, bufsz, "%d", cpu->address);
596b8845 425 break;
cc07239d 426 case COL_CPU_CONFIGURED:
17353ee0 427 get_cell_boolean(cxt, cpu->configured >= 0, cpu->configured, buf, bufsz);
d231eea1 428 break;
cc07239d 429 case COL_CPU_ONLINE:
17353ee0 430 get_cell_boolean(cxt, !!cxt->online, is_cpu_online(cxt, cpu), buf, bufsz);
a7e5300c 431 break;
6d880d3d 432 case COL_CPU_MHZ:
ff6513c7
KZ
433 if (cpu->mhz_cur_freq)
434 snprintf(buf, bufsz, "%.4f", cpu->mhz_cur_freq);
6d880d3d 435 break;
9b9e4f5d
KZ
436 case COL_CPU_SCALMHZ:
437 if (cpu->mhz_cur_freq && cpu->mhz_max_freq)
438 snprintf(buf, bufsz, "%.0f%%", cpu->mhz_cur_freq / cpu->mhz_max_freq * 100);
6d880d3d 439 break;
cc07239d 440 case COL_CPU_MAXMHZ:
63c5e7f8
KZ
441 if (cpu->mhz_max_freq)
442 snprintf(buf, bufsz, "%.4f", cpu->mhz_max_freq);
e065a597 443 break;
cc07239d 444 case COL_CPU_MINMHZ:
63c5e7f8
KZ
445 if (cpu->mhz_min_freq)
446 snprintf(buf, bufsz, "%.4f", cpu->mhz_min_freq);
44320710 447 break;
1d956847
KZ
448 case COL_CPU_MODELNAME:
449 if (cpu->type && cpu->type->modelname)
450 xstrncpy(buf, cpu->type->modelname, bufsz);
451 break;
477251f8 452 }
e3b3a2f3
KZ
453 return buf;
454}
455
63c5e7f8
KZ
456static char *get_cell_header(
457 struct lscpu_cxt *cxt, int col,
458 char *buf, size_t bufsz)
e3b3a2f3
KZ
459{
460 *buf = '\0';
461
cc07239d 462 if (col == COL_CPU_CACHE) {
63c5e7f8 463 const char *last = NULL;
e3b3a2f3
KZ
464 char *p = buf;
465 size_t sz = bufsz;
63c5e7f8
KZ
466 size_t i;
467
468 for (i = 0; i < cxt->ncaches; i++) {
469 struct lscpu_cache *ca = &cxt->caches[i];
470 int x;
471
472 if (last && strcmp(last, ca->name) == 0)
473 continue;
474 last = ca->name;
e3b3a2f3 475
63c5e7f8 476 x = snprintf(p, sz, "%s", ca->name);
06fa5817 477 if (x < 0 || (size_t) x >= sz)
e3b3a2f3
KZ
478 return NULL;
479 sz -= x;
480 p += x;
e07cca6b
KZ
481 if (sz < 2)
482 return NULL;
483 *p++ = cxt->show_compatible ? ',' : ':';
484 *p = '\0';
485 sz--;
e3b3a2f3 486 }
e07cca6b
KZ
487 if (p > buf && (*(p - 1) == ',' || *(p - 1) == ':'))
488 *(p - 1) = '\0';
63c5e7f8 489 if (cxt->ncaches)
e3b3a2f3
KZ
490 return buf;
491 }
cc07239d 492 snprintf(buf, bufsz, "%s", coldescs_cpu[col].name);
e3b3a2f3 493 return buf;
477251f8
KZ
494}
495
1766641a 496
9d480e57
KZ
497static void caches_add_line(struct lscpu_cxt *cxt,
498 struct libscols_table *tb,
499 struct lscpu_cache *ca,
500 int cols[], size_t ncols)
501{
502 struct libscols_line *ln;
503 size_t c;
504
505 ln = scols_table_new_line(tb, NULL);
506 if (!ln)
507 err(EXIT_FAILURE, _("failed to allocate output line"));
508
509 for (c = 0; c < ncols; c++) {
510 char *data = NULL;
511 int col = cols[c];
512
513 switch (col) {
514 case COL_CACHE_NAME:
515 if (ca->name)
516 data = xstrdup(ca->name);
517 break;
518 case COL_CACHE_ONESIZE:
519 if (!ca->size)
520 break;
521 if (cxt->bytes)
522 xasprintf(&data, "%" PRIu64, ca->size);
523 else
524 data = size_to_human_string(SIZE_SUFFIX_1LETTER, ca->size);
525 break;
526 case COL_CACHE_ALLSIZE:
527 {
b9b28b64
KZ
528 uint64_t sz = 0;
529 if (ca->name)
9dadd3e6 530 sz = lscpu_get_cache_full_size(cxt, ca->name, NULL);
9d480e57
KZ
531 if (!sz)
532 break;
533 if (cxt->bytes)
534 xasprintf(&data, "%" PRIu64, sz);
535 else
536 data = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
537 break;
538 }
539 case COL_CACHE_WAYS:
540 if (ca->ways_of_associativity)
541 xasprintf(&data, "%u", ca->ways_of_associativity);
542 break;
543
544 case COL_CACHE_TYPE:
545 if (ca->type)
546 data = xstrdup(ca->type);
547 break;
548 case COL_CACHE_LEVEL:
549 if (ca->level)
550 xasprintf(&data, "%d", ca->level);
551 break;
552 case COL_CACHE_ALLOCPOL:
553 if (ca->allocation_policy)
554 data = xstrdup(ca->allocation_policy);
555 break;
556 case COL_CACHE_WRITEPOL:
557 if (ca->write_policy)
558 data = xstrdup(ca->write_policy);
559 break;
560 case COL_CACHE_PHYLINE:
561 if (ca->physical_line_partition)
562 xasprintf(&data, "%u", ca->physical_line_partition);
563 break;
564 case COL_CACHE_SETS:
565 if (ca->number_of_sets)
566 xasprintf(&data, "%u", ca->number_of_sets);
567 break;
568 case COL_CACHE_COHERENCYSIZE:
569 if (ca->coherency_line_size)
570 xasprintf(&data, "%u", ca->coherency_line_size);
571 break;
572 }
573
574 if (data && scols_line_refer_data(ln, c, data))
575 err(EXIT_FAILURE, _("failed to add output data"));
576 }
577}
578
579
0e86bc84
KZ
580/*
581 * [-C] backend
582 */
1766641a 583static void print_caches_readable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
0e86bc84 584{
1766641a
KZ
585 size_t i;
586 struct libscols_table *tb;
587 const char *last = NULL;
0e86bc84
KZ
588
589 scols_init_debug(0);
590
1766641a
KZ
591 tb = scols_new_table();
592 if (!tb)
0e86bc84 593 err(EXIT_FAILURE, _("failed to allocate output table"));
1766641a
KZ
594 if (cxt->json) {
595 scols_table_enable_json(tb, 1);
596 scols_table_set_name(tb, "caches");
0e86bc84
KZ
597 }
598
599 for (i = 0; i < ncols; i++) {
600 struct lscpu_coldesc *cd = &coldescs_cache[cols[i]];
17353ee0
TW
601 struct libscols_column *cl;
602
603 cl = scols_table_new_column(tb, cd->name, 0, cd->flags);
17353ee0 604 if (cl == NULL)
0e86bc84 605 err(EXIT_FAILURE, _("failed to allocate output column"));
17353ee0
TW
606 if (cxt->json)
607 scols_column_set_json_type(cl, cd->json_type);
0e86bc84
KZ
608 }
609
9d480e57 610 /* standard caches */
1766641a
KZ
611 for (i = 0; i < cxt->ncaches; i++) {
612 struct lscpu_cache *ca = &cxt->caches[i];
0e86bc84 613
1766641a
KZ
614 if (last && strcmp(last, ca->name) == 0)
615 continue;
1766641a 616 last = ca->name;
9d480e57
KZ
617 caches_add_line(cxt, tb, ca, cols, ncols);
618 }
1766641a 619
9d480e57
KZ
620 /* extra caches */
621 for (i = 0; i < cxt->necaches; i++) {
622 struct lscpu_cache *ca = &cxt->ecaches[i];
318542e0 623
9d480e57
KZ
624 if (last && strcmp(last, ca->name) == 0)
625 continue;
626 last = ca->name;
627 caches_add_line(cxt, tb, ca, cols, ncols);
0e86bc84
KZ
628 }
629
1766641a
KZ
630 scols_print_table(tb);
631 scols_unref_table(tb);
0e86bc84
KZ
632}
633
477251f8 634/*
ba45d8c1 635 * [-p] backend, we support two parsable formats:
477251f8
KZ
636 *
637 * 1) "compatible" -- this format is compatible with the original lscpu(1)
638 * output and it contains fixed set of the columns. The CACHE columns are at
639 * the end of the line and the CACHE is not printed if the number of the caches
640 * is zero. The CACHE columns are separated by two commas, for example:
641 *
642 * $ lscpu --parse
643 * # CPU,Core,Socket,Node,,L1d,L1i,L2
644 * 0,0,0,0,,0,0,0
645 * 1,1,0,0,,1,1,0
646 *
647 * 2) "user defined output" -- this format prints always all columns without
648 * special prefix for CACHE column. If there are not CACHEs then the column is
649 * empty and the header "Cache" is printed rather than a real name of the cache.
650 * The CACHE columns are separated by ':'.
651 *
652 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
653 * # CPU,Core,Socket,Node,L1d:L1i:L2
654 * 0,0,0,0,0:0:0
655 * 1,1,0,0,1:1:0
656 */
0710bb13 657static void print_cpus_parsable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
477251f8 658{
e3b3a2f3 659 char buf[BUFSIZ], *data;
0710bb13 660 size_t i;
477251f8 661
e3b3a2f3
KZ
662 /*
663 * Header
664 */
477251f8
KZ
665 printf(_(
666 "# The following is the parsable format, which can be fed to other\n"
667 "# programs. Each different item in every column has an unique ID\n"
6321d34f 668 "# starting usually from zero.\n"));
477251f8
KZ
669
670 fputs("# ", stdout);
671 for (i = 0; i < ncols; i++) {
3d27b76a 672 int col = cols[i];
b9d18bc3 673
cc07239d 674 if (col == COL_CPU_CACHE) {
0710bb13 675 if (cxt->show_compatible && !cxt->ncaches)
477251f8 676 continue;
0710bb13 677 if (cxt->show_compatible && i != 0)
477251f8 678 putchar(',');
477251f8 679 }
e3b3a2f3
KZ
680 if (i > 0)
681 putchar(',');
682
0710bb13 683 data = get_cell_header(cxt, col, buf, sizeof(buf));
cc07239d
KZ
684 if (data && * data && col != COL_CPU_CACHE &&
685 !coldescs_cpu[col].is_abbr) {
3d27b76a
KZ
686 /*
687 * For normal column names use mixed case (e.g. "Socket")
688 */
689 char *p = data + 1;
690
14e8be8a
PU
691 while (p && *p != '\0') {
692 *p = tolower((unsigned int) *p);
693 p++;
694 }
3d27b76a 695 }
e3b3a2f3 696 fputs(data && *data ? data : "", stdout);
477251f8
KZ
697 }
698 putchar('\n');
699
e3b3a2f3
KZ
700 /*
701 * Data
702 */
0710bb13
KZ
703 for (i = 0; i < cxt->npossibles; i++) {
704 struct lscpu_cpu *cpu = cxt->cpus[i];
705 size_t c;
e3b3a2f3 706
0710bb13
KZ
707 if (cxt->online) {
708 if (!cxt->show_offline && !is_cpu_online(cxt, cpu))
6dd7b74b 709 continue;
0710bb13 710 if (!cxt->show_online && is_cpu_online(cxt, cpu))
6dd7b74b
SK
711 continue;
712 }
0710bb13 713 if (cxt->present && !is_cpu_present(cxt, cpu))
a5cfffff 714 continue;
0710bb13 715
477251f8 716 for (c = 0; c < ncols; c++) {
0710bb13
KZ
717 if (cxt->show_compatible && cols[c] == COL_CPU_CACHE) {
718 if (!cxt->ncaches)
477251f8
KZ
719 continue;
720 if (c > 0)
721 putchar(',');
722 }
723 if (c > 0)
724 putchar(',');
e3b3a2f3 725
0710bb13 726 data = get_cell_data(cxt, cpu, cols[c], buf, sizeof(buf));
e3b3a2f3 727 fputs(data && *data ? data : "", stdout);
bdda3543 728 *buf = '\0';
477251f8 729 }
5dd7507c
CQ
730 putchar('\n');
731 }
732}
733
ba45d8c1
KZ
734/*
735 * [-e] backend
736 */
63c5e7f8 737static void print_cpus_readable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
ba45d8c1 738{
63c5e7f8 739 size_t i;
e7213e34
KZ
740 char buf[BUFSIZ];
741 const char *data;
63c5e7f8 742 struct libscols_table *tb;
ba45d8c1 743
710ed55d
KZ
744 scols_init_debug(0);
745
63c5e7f8
KZ
746 tb = scols_new_table();
747 if (!tb)
780ce22c 748 err(EXIT_FAILURE, _("failed to allocate output table"));
63c5e7f8
KZ
749 if (cxt->json) {
750 scols_table_enable_json(tb, 1);
751 scols_table_set_name(tb, "cpus");
19a5510b 752 }
ba45d8c1
KZ
753
754 for (i = 0; i < ncols; i++) {
63c5e7f8 755 data = get_cell_header(cxt, cols[i], buf, sizeof(buf));
17353ee0
TW
756 struct lscpu_coldesc *cd = &coldescs_cpu[cols[i]];
757 struct libscols_column *cl;
758
759 cl = scols_table_new_column(tb, data, 0, cd->flags);
760 if (cl == NULL)
780ce22c 761 err(EXIT_FAILURE, _("failed to allocate output column"));
17353ee0
TW
762 if (cxt->json)
763 scols_column_set_json_type(cl, cd->json_type);
ba45d8c1
KZ
764 }
765
63c5e7f8
KZ
766 for (i = 0; i < cxt->npossibles; i++) {
767 size_t c;
768 struct libscols_line *ln;
769 struct lscpu_cpu *cpu = cxt->cpus[i];
ba45d8c1 770
63c5e7f8
KZ
771 if (cxt->online) {
772 if (!cxt->show_offline && !is_cpu_online(cxt, cpu))
6dd7b74b 773 continue;
63c5e7f8 774 if (!cxt->show_online && is_cpu_online(cxt, cpu))
6dd7b74b
SK
775 continue;
776 }
63c5e7f8
KZ
777
778 if (cxt->present && !is_cpu_present(cxt, cpu))
a5cfffff 779 continue;
ba45d8c1 780
63c5e7f8
KZ
781 ln = scols_table_new_line(tb, NULL);
782 if (!ln)
780ce22c 783 err(EXIT_FAILURE, _("failed to allocate output line"));
ba45d8c1
KZ
784
785 for (c = 0; c < ncols; c++) {
63c5e7f8 786 data = get_cell_data(cxt, cpu, cols[c], buf, sizeof(buf));
e7213e34
KZ
787 if (!data || !*data)
788 data = "-";
63c5e7f8 789 if (scols_line_set_data(ln, c, data))
780ce22c 790 err(EXIT_FAILURE, _("failed to add output data"));
ba45d8c1
KZ
791 }
792 }
793
63c5e7f8
KZ
794 scols_print_table(tb);
795 scols_unref_table(tb);
ba45d8c1 796}
5dd7507c 797
e3f21318 798static struct libscols_line *
91eef60c 799 __attribute__ ((__format__(printf, 4, 5)))
c82b12a0 800 add_summary_sprint(struct libscols_table *tb,
e3f21318 801 struct libscols_line *sec,
c82b12a0
KZ
802 const char *txt,
803 const char *fmt,
804 ...)
805{
91eef60c 806 struct libscols_line *ln;
c82b12a0
KZ
807 va_list args;
808
c9121791
KZ
809 /* Don't print section lines without data */
810 if (!hierarchic && fmt == NULL)
91eef60c
KZ
811 return NULL;
812
813 ln = scols_table_new_line(tb, sec);
c82b12a0 814 if (!ln)
780ce22c 815 err(EXIT_FAILURE, _("failed to allocate output line"));
c82b12a0
KZ
816
817 /* description column */
a0661407
KZ
818 if (txt && scols_line_set_data(ln, 0, txt))
819 err(EXIT_FAILURE, _("failed to add output data"));
c82b12a0
KZ
820
821 /* data column */
91eef60c
KZ
822 if (fmt) {
823 char *data;
824 va_start(args, fmt);
825 xvasprintf(&data, fmt, args);
826 va_end(args);
827
828 if (data && scols_line_refer_data(ln, 1, data))
829 err(EXIT_FAILURE, _("failed to add output data"));
830 }
e3f21318
KZ
831
832 return ln;
c82b12a0
KZ
833}
834
91eef60c 835#define add_summary_e(tb, sec, txt) add_summary_sprint(tb, sec, txt, NULL)
e3f21318
KZ
836#define add_summary_n(tb, sec, txt, num) add_summary_sprint(tb, sec, txt, "%zu", num)
837#define add_summary_s(tb, sec, txt, str) add_summary_sprint(tb, sec, txt, "%s", str)
838#define add_summary_x(tb, sec, txt, fmt, x) add_summary_sprint(tb, sec, txt, fmt, x)
5dd7507c
CQ
839
840static void
d8813bb3
KZ
841print_cpuset(struct lscpu_cxt *cxt,
842 struct libscols_table *tb,
91eef60c 843 struct libscols_line *sec,
d8813bb3 844 const char *key, cpu_set_t *set)
4f912c6a 845{
d8813bb3 846 size_t setbuflen = 7 * cxt->maxcpus;
4f912c6a
KZ
847 char setbuf[setbuflen], *p;
848
93a1bb10
KZ
849 assert(set);
850 assert(key);
851 assert(tb);
852 assert(cxt);
853
d8813bb3
KZ
854 if (cxt->hex) {
855 p = cpumask_create(setbuf, setbuflen, set, cxt->setsize);
91eef60c 856 add_summary_s(tb, sec, key, p);
4f912c6a 857 } else {
d8813bb3 858 p = cpulist_create(setbuf, setbuflen, set, cxt->setsize);
91eef60c 859 add_summary_s(tb, sec, key, p);
4f912c6a 860 }
4f912c6a
KZ
861}
862
2f5e2730
KZ
863static void
864print_summary_cputype(struct lscpu_cxt *cxt,
865 struct lscpu_cputype *ct,
91eef60c
KZ
866 struct libscols_table *tb,
867 struct libscols_line *sec)
5dd7507c 868{
38e93216 869 sec = add_summary_s(tb, sec, _("Model name:"), ct->modelname ? ct->modelname : "-");
8014104b
MM
870 if (ct->bios_modelname)
871 add_summary_s(tb, sec, _("BIOS Model name:"), ct->bios_modelname);
4cae2104
HS
872 if (ct->bios_family)
873 add_summary_s(tb, sec, _("BIOS CPU family:"), ct->bios_family);
2f5e2730 874 if (ct->machinetype)
91eef60c 875 add_summary_s(tb, sec, _("Machine type:"), ct->machinetype);
2f5e2730 876 if (ct->family)
91eef60c 877 add_summary_s(tb, sec, _("CPU family:"), ct->family);
2f5e2730 878 if (ct->model || ct->revision)
91eef60c 879 add_summary_s(tb, sec, _("Model:"), ct->revision ? ct->revision : ct->model);
2f5e2730 880
91eef60c 881 add_summary_n(tb, sec, _("Thread(s) per core:"), ct->nthreads_per_core);
73c0a766
MM
882 if (cxt->is_cluster)
883 add_summary_n(tb, sec, _("Core(s) per cluster:"), ct->ncores_per_socket);
884 else
885 add_summary_n(tb, sec, _("Core(s) per socket:"), ct->ncores_per_socket);
19ddc05e 886
2f5e2730 887 if (ct->nbooks) {
91eef60c 888 add_summary_n(tb, sec, _("Socket(s) per book:"), ct->nsockets_per_book);
19ddc05e 889 if (ct->ndrawers_per_system || ct->ndrawers) {
91eef60c 890 add_summary_n(tb, sec, _("Book(s) per drawer:"), ct->nbooks_per_drawer);
19ddc05e 891 add_summary_n(tb, sec, _("Drawer(s):"), ct->ndrawers_per_system ?: ct->ndrawers);
2f5e2730 892 } else
19ddc05e 893 add_summary_n(tb, sec, _("Book(s):"), ct->nbooks_per_drawer ?: ct->nbooks);
73c0a766 894 } else {
f42f105b
MM
895 if (cxt->is_cluster) {
896 if (ct->nr_socket_on_cluster > 0)
897 add_summary_n(tb, sec, _("Socket(s):"), ct->nr_socket_on_cluster);
898 else
899 add_summary_s(tb, sec, _("Socket(s):"), "-");
900
73c0a766
MM
901 add_summary_n(tb, sec, _("Cluster(s):"),
902 ct->nsockets_per_book ?: ct->nsockets);
f42f105b 903 } else
73c0a766
MM
904 add_summary_n(tb, sec, _("Socket(s):"),
905 ct->nsockets_per_book ?: ct->nsockets);
906 }
2f5e2730 907
93a1bb10 908 if (ct->stepping)
91eef60c 909 add_summary_s(tb, sec, _("Stepping:"), ct->stepping);
93a1bb10 910 if (ct->freqboost >= 0)
91eef60c 911 add_summary_s(tb, sec, _("Frequency boost:"), ct->freqboost ?
16ca0551 912 _("enabled") : _("disabled"));
01bea871
KZ
913
914 /* s390 -- from the first CPU where is dynamic/static MHz */
93a1bb10 915 if (ct->dynamic_mhz)
91eef60c 916 add_summary_s(tb, sec, _("CPU dynamic MHz:"), ct->dynamic_mhz);
93a1bb10 917 if (ct->static_mhz)
91eef60c 918 add_summary_s(tb, sec, _("CPU static MHz:"), ct->static_mhz);
01bea871 919
93a1bb10 920 if (ct->has_freq) {
9b9e4f5d
KZ
921 float scal = lsblk_cputype_get_scalmhz(cxt, ct);
922 if (scal > 0.0)
923 add_summary_x(tb, sec, _("CPU(s) scaling MHz:"), "%.0f%%", scal);
91eef60c
KZ
924 add_summary_x(tb, sec, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt, ct));
925 add_summary_x(tb, sec, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct));
bd9b94d1 926 }
93a1bb10 927 if (ct->bogomips)
aff94add 928 add_summary_x(tb, sec, _("BogoMIPS:"), "%.2f", (float) c_strtod(ct->bogomips, NULL));
91eef60c 929
93a1bb10 930 if (ct->dispatching >= 0)
91eef60c 931 add_summary_s(tb, sec, _("Dispatching mode:"), _(disp_modes[ct->dispatching]));
93a1bb10
KZ
932
933 if (ct->physsockets) {
91eef60c
KZ
934 add_summary_n(tb, sec, _("Physical sockets:"), ct->physsockets);
935 add_summary_n(tb, sec, _("Physical chips:"), ct->physchips);
936 add_summary_n(tb, sec, _("Physical cores/chip:"), ct->physcoresperchip);
639eeb28
KZ
937 }
938
93a1bb10 939 if (ct->flags)
91eef60c 940 add_summary_s(tb, sec, _("Flags:"), ct->flags);
2f5e2730
KZ
941}
942
943/*
944 * default output
945 */
946static void print_summary(struct lscpu_cxt *cxt)
947{
948 struct lscpu_cputype *ct;
91eef60c 949 char field[256];
2f5e2730
KZ
950 size_t i = 0;
951 struct libscols_table *tb;
e3f21318 952 struct libscols_line *sec = NULL;
071d3135 953 int hdr_caches = 0;
2f5e2730
KZ
954
955 scols_init_debug(0);
956
957 tb = scols_new_table();
958 if (!tb)
959 err(EXIT_FAILURE, _("failed to allocate output table"));
960
961 scols_table_enable_noheadings(tb, 1);
962 if (cxt->json) {
963 scols_table_enable_json(tb, 1);
964 scols_table_set_name(tb, "lscpu");
c9121791 965 } else if (hierarchic) {
91eef60c
KZ
966 struct libscols_symbols *sy = scols_new_symbols();
967
968 if (!sy)
969 err_oom();
970 scols_symbols_set_branch(sy, " ");
971 scols_symbols_set_vertical(sy, " ");
972 scols_symbols_set_right(sy, " ");
973 scols_table_set_symbols(tb, sy);
d4cb6a03 974 scols_unref_symbols(sy);
2f5e2730
KZ
975 }
976
c9121791 977 if (scols_table_new_column(tb, "field", 0, hierarchic ? SCOLS_FL_TREE : 0) == NULL ||
2f5e2730
KZ
978 scols_table_new_column(tb, "data", 0, SCOLS_FL_NOEXTREMES | SCOLS_FL_WRAP) == NULL)
979 err(EXIT_FAILURE, _("failed to initialize output column"));
980
981 ct = lscpu_cputype_get_default(cxt);
982
91eef60c 983 /* Section: architecture */
2f5e2730 984 if (cxt->arch)
e3f21318 985 sec = add_summary_s(tb, NULL, _("Architecture:"), cxt->arch->name);
2f5e2730
KZ
986 if (cxt->arch && (cxt->arch->bit32 || cxt->arch->bit64)) {
987 char buf[32], *p = buf;
988
989 if (cxt->arch->bit32) {
990 strcpy(p, "32-bit, ");
991 p += 8;
992 }
993 if (cxt->arch->bit64) {
994 strcpy(p, "64-bit, ");
995 p += 8;
996 }
997 *(p - 2) = '\0';
e3f21318 998 add_summary_s(tb, sec, _("CPU op-mode(s):"), buf);
2f5e2730 999 }
0d7cef3d 1000 if (ct && ct->addrsz)
e3f21318 1001 add_summary_s(tb, sec, _("Address sizes:"), ct->addrsz);
83b418c1 1002#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
e3f21318 1003 add_summary_s(tb, sec, _("Byte Order:"), "Little Endian");
2f5e2730 1004#else
e3f21318 1005 add_summary_s(tb, sec, _("Byte Order:"), "Big Endian");
2f5e2730 1006#endif
91eef60c
KZ
1007
1008 /* Section: CPU lists */
1009 sec = add_summary_n(tb, NULL, _("CPU(s):"), cxt->npresents);
1010
2f5e2730 1011 if (cxt->online)
91eef60c 1012 print_cpuset(cxt, tb, sec,
2f5e2730
KZ
1013 cxt->hex ? _("On-line CPU(s) mask:") :
1014 _("On-line CPU(s) list:"),
1015 cxt->online);
1016
1017 if (cxt->online && cxt->nonlines != cxt->npresents) {
1018 cpu_set_t *set;
1019
1020 /* Linux kernel provides cpuset of off-line CPUs that contains
1021 * all configured CPUs (see /sys/devices/system/cpu/offline),
1022 * but want to print real (present in system) off-line CPUs only.
1023 */
1024 set = cpuset_alloc(cxt->maxcpus, NULL, NULL);
1025 if (!set)
1026 err(EXIT_FAILURE, _("failed to callocate cpu set"));
1027 CPU_ZERO_S(cxt->setsize, set);
1028 for (i = 0; i < cxt->npossibles; i++) {
1029 struct lscpu_cpu *cpu = cxt->cpus[i];
1030
1031 if (cpu && is_cpu_present(cxt, cpu) && !is_cpu_online(cxt, cpu))
1032 CPU_SET_S(cpu->logical_id, cxt->setsize, set);
1033 }
91eef60c 1034 print_cpuset(cxt, tb, sec,
2f5e2730
KZ
1035 cxt->hex ? _("Off-line CPU(s) mask:") :
1036 _("Off-line CPU(s) list:"), set);
1037 cpuset_free(set);
1038 }
8014104b 1039 sec = NULL;
2f5e2730 1040
91eef60c 1041 /* Section: cpu type description */
0d7cef3d 1042 if (ct && ct->vendor)
91eef60c 1043 sec = add_summary_s(tb, NULL, _("Vendor ID:"), ct->vendor);
0d7cef3d 1044 if (ct && ct->bios_vendor)
8014104b 1045 add_summary_s(tb, sec, _("BIOS Vendor ID:"), ct->bios_vendor);
91eef60c 1046
8014104b
MM
1047 for (i = 0; i < cxt->ncputypes; i++)
1048 print_summary_cputype(cxt, cxt->cputypes[i], tb, sec);
91eef60c 1049 sec = NULL;
2f5e2730 1050
91eef60c 1051 /* Section: vitualiazation */
93a1bb10 1052 if (cxt->virt) {
91eef60c 1053 sec = add_summary_e(tb, NULL, _("Virtualization features:"));
01bea871 1054 if (cxt->virt->cpuflag && !strcmp(cxt->virt->cpuflag, "svm"))
e3f21318 1055 add_summary_s(tb, sec, _("Virtualization:"), "AMD-V");
01bea871 1056 else if (cxt->virt->cpuflag && !strcmp(cxt->virt->cpuflag, "vmx"))
e3f21318 1057 add_summary_s(tb, sec, _("Virtualization:"), "VT-x");
93a1bb10
KZ
1058
1059 if (cxt->virt->hypervisor)
e3f21318 1060 add_summary_s(tb, sec, _("Hypervisor:"), cxt->virt->hypervisor);
93a1bb10 1061 if (cxt->virt->vendor) {
e3f21318
KZ
1062 add_summary_s(tb, sec, _("Hypervisor vendor:"), hv_vendors[cxt->virt->vendor]);
1063 add_summary_s(tb, sec, _("Virtualization type:"), _(virt_types[cxt->virt->type]));
93a1bb10 1064 }
e3f21318 1065 sec = NULL;
93a1bb10 1066 }
91eef60c
KZ
1067
1068 /* Section: caches */
01bea871
KZ
1069 if (cxt->ncaches) {
1070 const char *last = NULL;
93a1bb10 1071
01bea871
KZ
1072 /* The caches are sorted by name, cxt->caches[] may contains
1073 * multiple instances for the same name.
1074 */
1075 for (i = 0; i < cxt->ncaches; i++) {
1076 const char *name = cxt->caches[i].name;
1077 uint64_t sz;
9dadd3e6 1078 int n = 0;
93a1bb10 1079
01bea871 1080 if (last && strcmp(last, name) == 0)
93a1bb10 1081 continue;
9dadd3e6 1082 sz = lscpu_get_cache_full_size(cxt, name, &n);
01bea871 1083 if (!sz)
93a1bb10 1084 continue;
071d3135
KZ
1085 if (!hdr_caches) {
1086 sec = add_summary_e(tb, NULL, _("Caches (sum of all):"));
1087 hdr_caches = 1;
1088 }
1089
c9121791 1090 snprintf(field, sizeof(field), hierarchic ? _("%s:") : _("%s cache:"), name);
01bea871 1091 if (cxt->bytes)
9dadd3e6
KZ
1092 add_summary_sprint(tb, sec, field,
1093 P_("%" PRIu64 " (%d instance)",
1094 "%" PRIu64 " (%d instances)", n),
1095 sz, n);
01bea871
KZ
1096 else {
1097 char *tmp = size_to_human_string(
1098 SIZE_SUFFIX_3LETTER |
1099 SIZE_SUFFIX_SPACE,
1100 sz);
9dadd3e6
KZ
1101 add_summary_sprint(tb, sec, field,
1102 P_("%s (%d instance)",
1103 "%s (%d instances)", n),
1104 tmp, n);
01bea871
KZ
1105 free(tmp);
1106 }
1107 last = name;
93a1bb10
KZ
1108 }
1109 }
01bea871 1110
071d3135
KZ
1111 for (i = 0; i < cxt->necaches; i++) {
1112 struct lscpu_cache *ca = &cxt->ecaches[i];
93a1bb10 1113
071d3135
KZ
1114 if (ca->size == 0)
1115 continue;
1116 if (!hdr_caches) {
1117 sec = add_summary_e(tb, NULL, _("Caches:"));
1118 hdr_caches = 1;
1119 }
c9121791 1120 snprintf(field, sizeof(field), hierarchic ? _("%s:") : _("%s cache:"), ca->name);
071d3135
KZ
1121 if (cxt->bytes)
1122 add_summary_x(tb, sec, field, "%" PRIu64, ca->size);
1123 else {
1124 char *tmp = size_to_human_string(
1125 SIZE_SUFFIX_3LETTER |
1126 SIZE_SUFFIX_SPACE,
1127 ca->size);
1128 add_summary_s(tb, sec, field, tmp);
1129 free(tmp);
01bea871
KZ
1130 }
1131 }
7155a57d 1132 sec = NULL;
01bea871 1133
91eef60c 1134 /* Section: NUMA modes */
01bea871 1135 if (cxt->nnodes) {
91eef60c 1136 sec = add_summary_e(tb, NULL, _("NUMA:"));
e3f21318
KZ
1137
1138 add_summary_n(tb, sec,_("NUMA node(s):"), cxt->nnodes);
01bea871 1139 for (i = 0; i < cxt->nnodes; i++) {
91eef60c
KZ
1140 snprintf(field, sizeof(field), _("NUMA node%d CPU(s):"), cxt->idx2nodenum[i]);
1141 print_cpuset(cxt, tb, sec, field, cxt->nodemaps[i]);
93a1bb10 1142 }
e3f21318 1143 sec = NULL;
93a1bb10
KZ
1144 }
1145
91eef60c 1146 /* Section: Vulnerabilities */
01bea871 1147 if (cxt->vuls) {
91eef60c 1148 sec = add_summary_e(tb, NULL, _("Vulnerabilities:"));
e3f21318 1149
01bea871 1150 for (i = 0; i < cxt->nvuls; i++) {
c9121791 1151 snprintf(field, sizeof(field), hierarchic ?
91eef60c
KZ
1152 _("%s:") : _("Vulnerability %s:"), cxt->vuls[i].name);
1153 add_summary_s(tb, sec, field, cxt->vuls[i].text);
93a1bb10 1154 }
e3f21318 1155 sec = NULL;
93a1bb10 1156 }
c82b12a0
KZ
1157 scols_print_table(tb);
1158 scols_unref_table(tb);
5dd7507c
CQ
1159}
1160
6e1eda6f 1161static void __attribute__((__noreturn__)) usage(void)
5dd7507c 1162{
6e1eda6f 1163 FILE *out = stdout;
b9d18bc3
KZ
1164 size_t i;
1165
1166 fputs(USAGE_HEADER, out);
c6f095cf 1167 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
7f1ec5e8 1168
451dbcfa
BS
1169 fputs(USAGE_SEPARATOR, out);
1170 fputs(_("Display information about the CPU architecture.\n"), out);
1171
b9d18bc3 1172 fputs(USAGE_OPTIONS, out);
c6f095cf
BS
1173 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out);
1174 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out);
2011528b 1175 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out);
0e86bc84 1176 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out);
c6f095cf 1177 fputs(_(" -c, --offline print offline CPUs only\n"), out);
19a5510b 1178 fputs(_(" -J, --json use JSON for default or extended format\n"), out);
c6f095cf
BS
1179 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out);
1180 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out);
1181 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out);
1182 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out);
0d2b5d2a 1183 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out);
c9121791 1184 fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out);
0a31a242 1185 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out);
c6f095cf 1186 fputs(USAGE_SEPARATOR, out);
f45f3ec3 1187 printf(USAGE_HELP_OPTIONS(25));
b9d18bc3 1188
cc07239d
KZ
1189 fputs(_("\nAvailable output columns for -e or -p:\n"), out);
1190 for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++)
1191 fprintf(out, " %13s %s\n", coldescs_cpu[i].name, _(coldescs_cpu[i].help));
3d27b76a 1192
0e86bc84
KZ
1193 fputs(_("\nAvailable output columns for -C:\n"), out);
1194 for (i = 0; i < ARRAY_SIZE(coldescs_cache); i++)
1195 fprintf(out, " %13s %s\n", coldescs_cache[i].name, _(coldescs_cache[i].help));
1196
f45f3ec3 1197 printf(USAGE_MAN_TAIL("lscpu(1)"));
4f912c6a 1198
6e1eda6f 1199 exit(EXIT_SUCCESS);
5dd7507c
CQ
1200}
1201
1202int main(int argc, char *argv[])
1203{
27c349f9 1204 struct lscpu_cxt *cxt;
b73d38b1 1205 int c, all = 0;
b4f60062 1206 int columns[ARRAY_SIZE(coldescs_cpu)];
7fc12cd2 1207 int cpu_modifier_specified = 0;
1242c3fd 1208 char *outarg = NULL;
b4f60062 1209 size_t i, ncolumns = 0;
fbf0619b
SK
1210 enum {
1211 OPT_OUTPUT_ALL = CHAR_MAX + 1,
c9121791 1212 OPT_HIERARCHIC,
fbf0619b 1213 };
6c7d5ae9 1214 static const struct option longopts[] = {
87918040
SK
1215 { "all", no_argument, NULL, 'a' },
1216 { "online", no_argument, NULL, 'b' },
2011528b 1217 { "bytes", no_argument, NULL, 'B' },
0e86bc84 1218 { "caches", optional_argument, NULL, 'C' },
87918040
SK
1219 { "offline", no_argument, NULL, 'c' },
1220 { "help", no_argument, NULL, 'h' },
1221 { "extended", optional_argument, NULL, 'e' },
19a5510b 1222 { "json", no_argument, NULL, 'J' },
87918040
SK
1223 { "parse", optional_argument, NULL, 'p' },
1224 { "sysroot", required_argument, NULL, 's' },
1225 { "physical", no_argument, NULL, 'y' },
1226 { "hex", no_argument, NULL, 'x' },
1227 { "version", no_argument, NULL, 'V' },
fbf0619b 1228 { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
c9121791 1229 { "hierarchic", optional_argument, NULL, OPT_HIERARCHIC },
87918040 1230 { NULL, 0, NULL, 0 }
5dd7507c
CQ
1231 };
1232
8e97eb4b 1233 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
0e86bc84 1234 { 'C','e','p' },
a44cd891 1235 { 'a','b','c' },
8e97eb4b
KZ
1236 { 0 }
1237 };
1238 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1239
2f8f1388 1240 setlocale(LC_ALL, "");
5dd7507c
CQ
1241 bindtextdomain(PACKAGE, LOCALEDIR);
1242 textdomain(PACKAGE);
25b7045e 1243 close_stdout_atexit();
5dd7507c 1244
b73d38b1
KZ
1245 cxt = lscpu_new_context();
1246
2011528b 1247 while ((c = getopt_long(argc, argv, "aBbC::ce::hJp::s:xyV", longopts, NULL)) != -1) {
8e97eb4b
KZ
1248
1249 err_exclusive_options(c, longopts, excl, excl_st);
1250
5dd7507c 1251 switch (c) {
0ad29ff6 1252 case 'a':
b73d38b1 1253 cxt->show_online = cxt->show_offline = 1;
7fc12cd2 1254 cpu_modifier_specified = 1;
0ad29ff6 1255 break;
2011528b 1256 case 'B':
b73d38b1 1257 cxt->bytes = 1;
2011528b 1258 break;
23e9e95a 1259 case 'b':
b73d38b1 1260 cxt->show_online = 1;
7fc12cd2 1261 cpu_modifier_specified = 1;
23e9e95a 1262 break;
7afc2387 1263 case 'c':
b73d38b1 1264 cxt->show_offline = 1;
7fc12cd2 1265 cpu_modifier_specified = 1;
7afc2387 1266 break;
0e86bc84
KZ
1267 case 'C':
1268 if (optarg) {
1269 if (*optarg == '=')
1270 optarg++;
1242c3fd 1271 outarg = optarg;
0e86bc84 1272 }
b73d38b1 1273 cxt->mode = LSCPU_OUTPUT_CACHES;
0e86bc84 1274 break;
19a5510b 1275 case 'J':
b73d38b1 1276 cxt->json = 1;
19a5510b 1277 break;
5dd7507c 1278 case 'p':
ba45d8c1 1279 case 'e':
477251f8
KZ
1280 if (optarg) {
1281 if (*optarg == '=')
1282 optarg++;
1242c3fd 1283 outarg = optarg;
477251f8 1284 }
b73d38b1 1285 cxt->mode = c == 'p' ? LSCPU_OUTPUT_PARSABLE : LSCPU_OUTPUT_READABLE;
5dd7507c 1286 break;
47b6e8b6 1287 case 's':
b73d38b1
KZ
1288 cxt->prefix = optarg;
1289 cxt->noalive = 1;
47b6e8b6 1290 break;
4f912c6a 1291 case 'x':
b73d38b1 1292 cxt->hex = 1;
4f912c6a 1293 break;
0d2b5d2a 1294 case 'y':
b73d38b1 1295 cxt->show_physical = 1;
0d2b5d2a 1296 break;
fbf0619b 1297 case OPT_OUTPUT_ALL:
0e86bc84 1298 all = 1;
fbf0619b 1299 break;
c9121791
KZ
1300 case OPT_HIERARCHIC:
1301 if (optarg) {
1302 if (strcmp(optarg, "auto") == 0)
1303 hierarchic = -1;
1304 else if (strcmp(optarg, "never") == 0)
1305 hierarchic = 0;
1306 else if (strcmp(optarg, "always") == 0)
1307 hierarchic = 1;
1308 else
1309 errx(EXIT_FAILURE, _("unsupported --flat argument"));
1310 } else
1311 hierarchic = 1;
1312 break;
2c308875
KZ
1313 case 'h':
1314 usage();
1315 case 'V':
1316 print_version(EXIT_SUCCESS);
5dd7507c 1317 default:
677ec86c 1318 errtryhelp(EXIT_FAILURE);
5dd7507c
CQ
1319 }
1320 }
7bbb7829 1321
0a31a242 1322 if (all && ncolumns == 0) {
b73d38b1 1323 size_t maxsz = cxt->mode == LSCPU_OUTPUT_CACHES ?
0e86bc84
KZ
1324 ARRAY_SIZE(coldescs_cache) :
1325 ARRAY_SIZE(coldescs_cpu);
1326
b73d38b1
KZ
1327 for (i = 0; i < maxsz; i++)
1328 columns[ncolumns++] = i;
0e86bc84
KZ
1329 }
1330
b73d38b1 1331 if (cpu_modifier_specified && cxt->mode == LSCPU_OUTPUT_SUMMARY) {
7fc12cd2
HC
1332 fprintf(stderr,
1333 _("%s: options --all, --online and --offline may only "
ac56e555 1334 "be used with options --extended or --parse.\n"),
7fc12cd2
HC
1335 program_invocation_short_name);
1336 return EXIT_FAILURE;
1337 }
1338
6e1eda6f
RM
1339 if (argc != optind) {
1340 warnx(_("bad usage"));
1341 errtryhelp(EXIT_FAILURE);
1342 }
7bbb7829 1343
7afc2387 1344 /* set default cpu display mode if none was specified */
b73d38b1
KZ
1345 if (!cxt->show_online && !cxt->show_offline) {
1346 cxt->show_online = 1;
1347 cxt->show_offline = cxt->mode == LSCPU_OUTPUT_READABLE ? 1 : 0;
7afc2387 1348 }
6e509042 1349
91eef60c 1350
4b9cbc38 1351 lscpu_init_debug();
6e509042 1352
4b9cbc38 1353 lscpu_context_init_paths(cxt);
5dd7507c 1354
4b9cbc38
KZ
1355 lscpu_read_cpulists(cxt);
1356 lscpu_read_cpuinfo(cxt);
1357 cxt->arch = lscpu_read_architecture(cxt);
538b50cb 1358
4b9cbc38
KZ
1359 lscpu_read_archext(cxt);
1360 lscpu_read_vulnerabilities(cxt);
1361 lscpu_read_numas(cxt);
1362 lscpu_read_topology(cxt);
7e03f383 1363
4b9cbc38 1364 lscpu_decode_arm(cxt);
28b1658f 1365
4b9cbc38 1366 cxt->virt = lscpu_read_virtualization(cxt);
c8b64f6d 1367
c9121791
KZ
1368 if (hierarchic == -1)
1369 hierarchic = isatty(STDOUT_FILENO); /* default */
1370
d8813bb3 1371 switch(cxt->mode) {
30b912d3 1372 case LSCPU_OUTPUT_SUMMARY:
d8813bb3 1373 print_summary(cxt);
ba45d8c1 1374 break;
30b912d3 1375 case LSCPU_OUTPUT_CACHES:
0e86bc84
KZ
1376 if (!ncolumns) {
1377 columns[ncolumns++] = COL_CACHE_NAME;
1378 columns[ncolumns++] = COL_CACHE_ONESIZE;
1379 columns[ncolumns++] = COL_CACHE_ALLSIZE;
1380 columns[ncolumns++] = COL_CACHE_WAYS;
1381 columns[ncolumns++] = COL_CACHE_TYPE;
1382 columns[ncolumns++] = COL_CACHE_LEVEL;
cf3b6b71
KZ
1383 columns[ncolumns++] = COL_CACHE_SETS;
1384 columns[ncolumns++] = COL_CACHE_PHYLINE;
1385 columns[ncolumns++] = COL_CACHE_COHERENCYSIZE;
0e86bc84 1386 }
1242c3fd
KZ
1387 if (outarg && string_add_to_idarray(outarg, columns,
1388 ARRAY_SIZE(columns),
1389 &ncolumns, cache_column_name_to_id) < 0)
1390 return EXIT_FAILURE;
1391
1766641a 1392 print_caches_readable(cxt, columns, ncolumns);
0e86bc84 1393 break;
30b912d3 1394 case LSCPU_OUTPUT_READABLE:
ba45d8c1
KZ
1395 if (!ncolumns) {
1396 /* No list was given. Just print whatever is there. */
63c5e7f8
KZ
1397 struct lscpu_cputype *ct = lscpu_cputype_get_default(cxt);
1398
cc07239d 1399 columns[ncolumns++] = COL_CPU_CPU;
63c5e7f8 1400 if (cxt->nnodes)
cc07239d 1401 columns[ncolumns++] = COL_CPU_NODE;
63c5e7f8 1402 if (ct && ct->ndrawers)
cc07239d 1403 columns[ncolumns++] = COL_CPU_DRAWER;
63c5e7f8 1404 if (ct && ct->nbooks)
cc07239d 1405 columns[ncolumns++] = COL_CPU_BOOK;
73c0a766
MM
1406 if (ct && ct->nsockets) {
1407 if (cxt->is_cluster)
1408 columns[ncolumns++] = COL_CPU_CLUSTER;
1409 else
1410 columns[ncolumns++] = COL_CPU_SOCKET;
1411 }
63c5e7f8 1412 if (ct && ct->ncores)
cc07239d 1413 columns[ncolumns++] = COL_CPU_CORE;
63c5e7f8 1414 if (cxt->ncaches)
cc07239d 1415 columns[ncolumns++] = COL_CPU_CACHE;
63c5e7f8 1416 if (cxt->online)
cc07239d 1417 columns[ncolumns++] = COL_CPU_ONLINE;
63c5e7f8 1418 if (ct && ct->has_configured)
cc07239d 1419 columns[ncolumns++] = COL_CPU_CONFIGURED;
63c5e7f8 1420 if (ct && ct->has_polarization)
cc07239d 1421 columns[ncolumns++] = COL_CPU_POLARIZATION;
63c5e7f8 1422 if (ct && ct->has_addresses)
cc07239d 1423 columns[ncolumns++] = COL_CPU_ADDRESS;
63c5e7f8 1424 if (ct && ct->has_freq) {
cc07239d 1425 columns[ncolumns++] = COL_CPU_MAXMHZ;
cc07239d 1426 columns[ncolumns++] = COL_CPU_MINMHZ;
aa049eab 1427 columns[ncolumns++] = COL_CPU_MHZ;
63c5e7f8 1428 }
ba45d8c1 1429 }
1242c3fd
KZ
1430 if (outarg && string_add_to_idarray(outarg, columns,
1431 ARRAY_SIZE(columns),
1432 &ncolumns, cpu_column_name_to_id) < 0)
1433 return EXIT_FAILURE;
63c5e7f8
KZ
1434 print_cpus_readable(cxt, columns, ncolumns);
1435 break;
63c5e7f8
KZ
1436 case LSCPU_OUTPUT_PARSABLE:
1437 if (!ncolumns) {
1438 columns[ncolumns++] = COL_CPU_CPU;
1439 columns[ncolumns++] = COL_CPU_CORE;
73c0a766
MM
1440 if (cxt->is_cluster)
1441 columns[ncolumns++] = COL_CPU_CLUSTER;
1442 else
1443 columns[ncolumns++] = COL_CPU_SOCKET;
63c5e7f8
KZ
1444 columns[ncolumns++] = COL_CPU_NODE;
1445 columns[ncolumns++] = COL_CPU_CACHE;
0710bb13 1446 cxt->show_compatible = 1;
63c5e7f8 1447 }
1242c3fd
KZ
1448 if (outarg && string_add_to_idarray(outarg, columns,
1449 ARRAY_SIZE(columns),
1450 &ncolumns, cpu_column_name_to_id) < 0)
1451 return EXIT_FAILURE;
1452
0710bb13 1453 print_cpus_parsable(cxt, columns, ncolumns);
ba45d8c1 1454 break;
8005924a 1455 }
5dd7507c 1456
27c349f9
KZ
1457 lscpu_free_context(cxt);
1458
cf474aac 1459 return EXIT_SUCCESS;
5dd7507c 1460}