├── .travis.yml
├── Makefile
├── lscpu.1
├── .gitignore
├── LICENSE
├── README.md
└── lscpu.c
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | compiler: cc
4 |
5 | os: osx
6 |
7 | script: make
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # lscpu Makefile
2 | # Public Domain
3 |
4 | CC ?= cc
5 | CFLAGS ?= -g -O2 -Wall
6 | PREFIX ?= /usr/local
7 |
8 | all:
9 | ${CC} ${CFLAGS} ${LDFLAGS} -o lscpu lscpu.c
10 |
11 | install:
12 | install -c -s -m 555 lscpu ${PREFIX}/bin
13 | install -c -m 444 lscpu.1 ${PREFIX}/man/man1
14 |
15 | clean:
16 | rm -f lscpu
17 |
--------------------------------------------------------------------------------
/lscpu.1:
--------------------------------------------------------------------------------
1 | .Dd April 27, 2018
2 | .Dt LSCPU 1
3 | .Os
4 | .Sh NAME
5 | .Nm lscpu
6 | .Nd display CPU information
7 | .Sh SYNOPSIS
8 | .Nm
9 | .Op Fl h|--help
10 | .Sh DESCRIPTION
11 | .Nm
12 | is a utility that displays CPU information for the system.
13 | .Pp
14 | The options are as follows:
15 | .Bl -tag -width Ds
16 | .It Fl h|--help
17 | Print usage information and exit.
18 | .El
19 | .Sh EXIT STATUS
20 | The
21 | .Nm
22 | utility exits 0 on success, and >0 if an error occurs.
23 | .Sh AUTHORS
24 | .Nm
25 | was written by
26 | .An Nan Xiao Aq Mt nan@chinadtrace.org .
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 | lscpu
39 |
40 | # Debug files
41 | *.dSYM/
42 | *.su
43 | *.idb
44 | *.pdb
45 |
46 | # Kernel Module Compile Results
47 | *.mod*
48 | *.cmd
49 | .tmp_versions/
50 | modules.order
51 | Module.symvers
52 | Mkfile.old
53 | dkms.conf
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Nan Xiao
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lscpu
2 | lscpu for BSDs. The main usage of this program should be for x86 architecture since it leverages [CPUID](https://en.wikipedia.org/wiki/CPUID) instructions. For other architectures, it just shows very limited facts.
3 |
4 | lscpu has been verified to work on following BSDs:
5 |
6 |
7 | | macOS | OpenBSD | FreeBSD | NetBSD |
8 | | DragonFlyBSD | MidnightBSD | TrueOS | ? |
9 |
10 |
11 | It should also work on other BSDs, though not tested. If you find lscpu also runs on other BSDs, please tell me by [mail](mailto:nan@chinadtrace.org) or just open a new [issue](https://github.com/NanXiao/lscpu/issues/new), thanks very much in advance!
12 |
13 | ## Usage
14 |
15 | $ git clone https://github.com/NanXiao/lscpu.git
16 | $ cd lscpu
17 | $ make
18 | $ ./lscpu
19 |
20 | ## Output
21 |
22 | $ ./lscpu
23 | Architecture: i386
24 | Byte Order: Little Endian
25 | Active CPU(s): 2
26 | Total CPU(s): 2
27 | Thread(s) per core: 1
28 | Core(s) per socket: 2
29 | Socket(s): 1
30 | Vendor: GenuineIntel
31 | CPU family: 6
32 | Model: 63
33 | Model name: Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz ("GenuineIntel" 686-class)
34 | Stepping: 2
35 | CPU MHz: 2401
36 | L1d cache: 32K
37 | L1i cache: 32K
38 | L2 cache: 256K
39 | L3 cache: 15M
40 | Flags: fpu vme de pse tsc msr mce cx8 apic sep mtrr pge mca cmov pat pse36 cflsh mmx fxsr sse sse2 htt sse3 pclmulqdq ssse3 cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx rdrnd fpcsds syscall pdpe1gb lahf_lm
41 | ## Acknowledgement
42 | Thanks to [yggdr](https://github.com/yggdr) for testing on AMD processors.
43 | Thanks to [bit_of_hope](https://www.reddit.com/r/BSD/comments/72bi57/lscpu_for_openbsdfreebsd/dnhnifm/) for testing on NetBSD.
44 | Thanks to Aleksej Lebedev for testing on DragonFlyBSD.
45 | Thanks to [Lucas Holt](https://github.com/laffer1) for testing on MidnightBSD and adding lscpu to the [MidnightBSD mports tree](http://svn.midnightbsd.org/svn/mports/trunk/sysutils/lscpu/).
46 | Thanks to [zi0r](https://github.com/zi0r) for adding lscpu to the [FreeBSD ports tree](https://www.freshports.org/sysutils/lscpu).
47 | Thanks to [Brian Callahan](https://github.com/ibara) for adding lscpu to the [OpenBSD ports tree](https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/sysutils/lscpu/).
48 |
--------------------------------------------------------------------------------
/lscpu.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #if defined(__amd64__) || defined(__i386__)
13 | #include
14 | #endif
15 |
16 | /* macro definitions */
17 | #define CACHE_SIZE_LEN (8)
18 |
19 | #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
20 |
21 | #define CPUID_STANDARD_0_MASK (0x00)
22 | #define CPUID_STANDARD_1_MASK (0x01)
23 | #define CPUID_STANDARD_2_MASK (0x02)
24 | #define CPUID_STANDARD_4_MASK (0x04)
25 | #define CPUID_STANDARD_7_MASK (0x07)
26 | #define CPUID_STANDARD_B_MASK (0x0B)
27 |
28 |
29 | #define CPUID_EXTENDED_1_MASK (0x01)
30 | #define CPUID_EXTENDED_5_MASK (0x05)
31 | #define CPUID_EXTENDED_6_MASK (0x06)
32 | #define CPUID_EXTENDED_8_MASK (0x08)
33 | #define CPUID_EXTENDED_1E_MASK (0x1E)
34 |
35 |
36 | #define CPUID_MAX_STANDARD_FUNCTION (0x17)
37 | #define CPUID_MAX_EXTENDED_FUNCTION (0x1E)
38 |
39 | /* struct definitions */
40 | typedef struct
41 | {
42 | char arch[16];
43 | int byte_order;
44 | char model[128];
45 | char vendor[32];
46 | int active_cpu_num;
47 | int total_cpu_num;
48 | int speed;
49 | } gen_cpu_info;
50 |
51 | typedef struct
52 | {
53 | int mib_code;
54 | void *old;
55 | size_t old_len;
56 | char *err_msg;
57 | } sysctl_get_cpu_info;
58 |
59 | typedef struct
60 | {
61 | int standard_mask;
62 | int extended_mask;
63 | int intel_use_leaf_4_get_cache;
64 | char vendor[13];
65 | unsigned char stepping;
66 | unsigned char model;
67 | unsigned short family;
68 | int threads_per_core;
69 | int cores_per_socket;
70 | char *l1d_cache;
71 | char *l1i_cache;
72 | char *l2_cache;
73 | char *l3_cache;
74 | char flags[2048];
75 | } x86_cpu_info;
76 |
77 |
78 | /* function declarations */
79 | #if defined(__amd64__) || defined(__i386__)
80 | static int is_amd_cpu(char *vendor);
81 | static int is_intel_cpu(char *vendor);
82 | static int x86_cpu_support_standard_flag(int flag, int mask);
83 | static int get_x86_cpu_standard_flags(int intel, uint32_t ecx, uint32_t edx, char *flags, size_t len);
84 | static int get_x86_cpu_structured_extended_flags(int intel, uint32_t ebx, uint32_t ecx, char *flags, size_t len);
85 | static int get_x86_cpu_extended_flags(int intel, uint32_t ecx, uint32_t edx, char *flags, size_t len);
86 | static void get_x86_cpu_info(x86_cpu_info *x86_info);
87 | #endif
88 |
89 | static void usage(void);
90 | static void print_cpu_info(gen_cpu_info *gen_info, x86_cpu_info *x86_info);
91 |
92 |
93 | /* variables definitions */
94 | gen_cpu_info gen_info;
95 | x86_cpu_info x86_info;
96 | char intel_l1d_cache[CACHE_SIZE_LEN];
97 | char intel_l1i_cache[CACHE_SIZE_LEN];
98 | char intel_l2_cache[CACHE_SIZE_LEN];
99 | char intel_l3_cache[CACHE_SIZE_LEN];
100 | char amd_l1d_cache[CACHE_SIZE_LEN];
101 | char amd_l1i_cache[CACHE_SIZE_LEN];
102 | char amd_l2_cache[CACHE_SIZE_LEN];
103 | char amd_l3_cache[CACHE_SIZE_LEN];
104 |
105 |
106 | /* function definitions */
107 | #if defined(__amd64__) || defined(__i386__)
108 | static int is_amd_cpu(char *vendor)
109 | {
110 | return (!strcmp(vendor, "AMDisbetter!") || !strcmp(vendor, "AuthenticAMD"));
111 | }
112 |
113 | static int is_intel_cpu(char *vendor)
114 | {
115 | return !strcmp(vendor, "GenuineIntel");
116 | }
117 |
118 | static int x86_cpu_support_standard_flag(int flag, int mask)
119 | {
120 | return (flag & (1 << mask));
121 | }
122 |
123 | static void parse_intel_cache_value(x86_cpu_info *x86_info, unsigned char value)
124 | {
125 | switch (value)
126 | {
127 | case 0x06:
128 | {
129 | x86_info->l1i_cache = "8K";
130 | break;
131 | }
132 | case 0x08:
133 | {
134 | x86_info->l1i_cache = "16K";
135 | break;
136 | }
137 | case 0x09:
138 | case 0x30:
139 | {
140 | x86_info->l1i_cache = "32K";
141 | break;
142 | }
143 | case 0x0A:
144 | case 0x66:
145 | {
146 | x86_info->l1d_cache = "8K";
147 | break;
148 | }
149 | case 0x0C:
150 | case 0x0D:
151 | case 0x60:
152 | case 0x67:
153 | {
154 | x86_info->l1d_cache = "16K";
155 | break;
156 | }
157 | case 0x68:
158 | case 0x2C:
159 | {
160 | x86_info->l1d_cache = "32K";
161 | break;
162 | }
163 | case 0x39:
164 | case 0x3B:
165 | case 0x41:
166 | case 0x79:
167 | {
168 | x86_info->l2_cache = "128K";
169 | break;
170 | }
171 | case 0x3A:
172 | {
173 | x86_info->l2_cache = "192K";
174 | break;
175 | }
176 | case 0x3C:
177 | case 0x42:
178 | case 0x7A:
179 | case 0x82:
180 | {
181 | x86_info->l2_cache = "256K";
182 | break;
183 | }
184 | case 0x3D:
185 | {
186 | x86_info->l2_cache = "384K";
187 | break;
188 | }
189 | case 0x3E:
190 | case 0x43:
191 | case 0x7B:
192 | case 0x7F:
193 | case 0x83:
194 | case 0x86:
195 | {
196 | x86_info->l2_cache = "512K";
197 | break;
198 | }
199 | case 0x44:
200 | case 0x7C:
201 | case 0x84:
202 | case 0x87:
203 | {
204 | x86_info->l2_cache = "1M";
205 | break;
206 | }
207 | case 0x45:
208 | case 0x7D:
209 | case 0x85:
210 | {
211 | x86_info->l2_cache = "2M";
212 | break;
213 | }
214 | case 0x48:
215 | {
216 | x86_info->l2_cache = "3M";
217 | break;
218 | }
219 | case 0x4E:
220 | {
221 | x86_info->l2_cache = "6M";
222 | break;
223 | }
224 | case 0x49:
225 | {
226 | x86_info->l3_cache = x86_info->l2_cache = "4M";
227 | break;
228 | }
229 | case 0xD0:
230 | {
231 | x86_info->l3_cache = "512K";
232 | break;
233 | }
234 | case 0x23:
235 | case 0xD1:
236 | case 0xD6:
237 | {
238 | x86_info->l3_cache = "1M";
239 | break;
240 | }
241 | case 0xDC:
242 | {
243 | x86_info->l3_cache = "1.5M";
244 | break;
245 | }
246 | case 0xDD:
247 | {
248 | x86_info->l3_cache = "3M";
249 | break;
250 | }
251 | case 0x25:
252 | case 0xD2:
253 | case 0xD7:
254 | case 0xE2:
255 | {
256 | x86_info->l3_cache = "2M";
257 | break;
258 | }
259 | case 0x29:
260 | case 0x46:
261 | case 0xD8:
262 | case 0xE3:
263 | {
264 | x86_info->l3_cache = "4M";
265 | break;
266 | }
267 | case 0x4A:
268 | case 0xDE:
269 | {
270 | x86_info->l3_cache = "6M";
271 | break;
272 | }
273 | case 0x47:
274 | case 0x4B:
275 | case 0xE4:
276 | {
277 | x86_info->l3_cache = "8M";
278 | break;
279 | }
280 | case 0x4C:
281 | case 0xEA:
282 | {
283 | x86_info->l3_cache = "12M";
284 | break;
285 | }
286 | case 0x4D:
287 | {
288 | x86_info->l3_cache = "16M";
289 | break;
290 | }
291 | case 0xEB:
292 | {
293 | x86_info->l3_cache = "18M";
294 | break;
295 | }
296 | case 0xEC:
297 | {
298 | x86_info->l3_cache = "24M";
299 | break;
300 | }
301 | case 0xFF:
302 | {
303 | x86_info->intel_use_leaf_4_get_cache = 1;
304 | break;
305 | }
306 | default:
307 | {
308 | break;
309 | }
310 | }
311 | return;
312 | }
313 |
314 | static int get_x86_cpu_standard_flags(int intel, uint32_t ecx, uint32_t edx, char *flags, size_t len)
315 | {
316 | return snprintf(flags, len,
317 | /* edx*/
318 | "%s%s%s%s"
319 | "%s%s%s%s"
320 | "%s%s%s"
321 | "%s%s%s%s"
322 | "%s%s%s%s"
323 | "%s%s%s"
324 | "%s%s%s%s"
325 | "%s%s%s"
326 |
327 | /* ecx */
328 | "%s%s%s%s"
329 | "%s%s%s%s"
330 | "%s%s%s%s"
331 | "%s%s%s%s"
332 | "%s%s%s"
333 | "%s%s%s%s"
334 | "%s%s%s%s"
335 | "%s%s%s%s",
336 |
337 | edx & 0x00000001 ? "fpu " : "",
338 | edx & 0x00000002 ? "vme " : "",
339 | edx & 0x00000004 ? "de " : "",
340 | edx & 0x00000008 ? "pse " : "",
341 |
342 | edx & 0x00000010 ? "tsc " : "",
343 | edx & 0x00000020 ? "msr " : "",
344 | edx & 0x00000040 ? "pae " : "",
345 | edx & 0x00000080 ? "mce " : "",
346 |
347 | edx & 0x00000100 ? "cx8 " : "",
348 | edx & 0x00000200 ? "apic " : "",
349 | edx & 0x00000800 ? "sep " : "",
350 |
351 | edx & 0x00001000 ? "mtrr " : "",
352 | edx & 0x00002000 ? "pge " : "",
353 | edx & 0x00004000 ? "mca " : "",
354 | edx & 0x00008000 ? "cmov " : "",
355 |
356 | edx & 0x00010000 ? "pat " : "",
357 | edx & 0x00020000 ? "pse36 " : "",
358 | intel ? (edx & 0x00040000 ? "psn " : "") : "",
359 | edx & 0x00080000 ? "cflsh " : "",
360 |
361 | intel ? (edx & 0x00200000 ? "ds " : "") : "",
362 | intel ? (edx & 0x00400000 ? "acpi " : "") : "",
363 | edx & 0x00800000 ? "mmx " : "",
364 |
365 | edx & 0x01000000 ? "fxsr " : "",
366 | edx & 0x02000000 ? "sse " : "",
367 | edx & 0x04000000 ? "sse2 " : "",
368 | intel ? (edx & 0x08000000 ? "ss " : "") : "",
369 |
370 | edx & 0x10000000 ? "htt " : "",
371 | intel ? (edx & 0x20000000 ? "tm " : "") : "",
372 | intel ? (edx & 0x80000000 ? "pbe " : "") : "",
373 |
374 | ecx & 0x00000001 ? "sse3 " : "",
375 | ecx & 0x00000002 ? "pclmulqdq " : "",
376 | intel ? (ecx & 0x00000004 ? "dtes64 " : "") : "",
377 | ecx & 0x00000008 ? "monitor " : "",
378 |
379 | intel ? (ecx & 0x00000010 ? "ds_cpl " : "") : "",
380 | intel ? (ecx & 0x00000020 ? "vmx " : "") : "",
381 | intel ? (ecx & 0x00000040 ? "smx " : "") : "",
382 | intel ? (ecx & 0x00000080 ? "est " : "") : "",
383 |
384 | intel ? (ecx & 0x00000100 ? "tm2 " : "") : "",
385 | ecx & 0x00000200 ? "ssse3 " : "",
386 | intel ? (ecx & 0x00000400 ? "cnxt-id " : "") : "",
387 | intel ? (ecx & 0x00000800 ? "sdbg " : "") : "",
388 |
389 | ecx & 0x00001000 ? "fma " : "",
390 | ecx & 0x00002000 ? "cx16 " : "",
391 | intel ? (ecx & 0x00004000 ? "xtpr " : "") : "",
392 | intel ? (ecx & 0x00008000 ? "pdcm " : "") : "",
393 |
394 | intel ? (ecx & 0x00020000 ? "pcid " : "") : "",
395 | intel ? (ecx & 0x00040000 ? "dca " : "") : "",
396 | ecx & 0x00080000 ? "sse4_1 " : "",
397 |
398 | ecx & 0x00100000 ? "sse4_2 " : "",
399 | intel ? (ecx & 0x00200000 ? "x2apic " : "") : "",
400 | intel ? (ecx & 0x00400000 ? "movbe " : "") : "",
401 | ecx & 0x00800000 ? "popcnt " : "",
402 |
403 | intel ? (ecx & 0x01000000 ? "tsc_deadline " : "") : "",
404 | ecx & 0x02000000 ? "aes " : "",
405 | ecx & 0x04000000 ? "xsave " : "",
406 | ecx & 0x08000000 ? "osxsave " : "",
407 |
408 | ecx & 0x10000000 ? "avx " : "",
409 | ecx & 0x20000000 ? "f16c " : "",
410 | ecx & 0x40000000 ? "rdrnd " : "",
411 | ecx & 0x80000000 ? "hypervisor " : "");
412 | }
413 |
414 | static int get_x86_cpu_structured_extended_flags(int intel, uint32_t ebx, uint32_t ecx, char *flags, size_t len)
415 | {
416 | return snprintf(flags, len,
417 | /* ebx */
418 | "%s%s%s%s"
419 | "%s%s%s%s"
420 | "%s%s%s%s"
421 | "%s%s%s%s"
422 | "%s%s%s%s"
423 | "%s%s"
424 | "%s%s"
425 | "%s"
426 | /* ecx */
427 | "%s%s%s"
428 | "%s"
429 | "%s"
430 | "%s",
431 |
432 | ebx & 0x00000001 ? "fsgsbase " : "",
433 | intel ? (ebx & 0x00000002 ? "tsc_adjust " : "") : "",
434 | intel ? (ebx & 0x00000004 ? "sgx " : "") : "",
435 | ebx & 0x00000008 ? "bmi1 " : "",
436 |
437 | intel ? (ebx & 0x00000010 ? "hle " : "") : "",
438 | ebx & 0x00000020 ? "avx2 " : "",
439 | intel ? (ebx & 0x00000040 ? "fp_dp " : "") : "",
440 | ebx & 0x00000080 ? "smep " : "",
441 |
442 | ebx & 0x00000100 ? "bmi2 " : "",
443 | intel ? (ebx & 0x00000200 ? "erms " : "") : "",
444 | intel ? (ebx & 0x00000400 ? "invpcid " : "") : "",
445 | intel ? (ebx & 0x00000800 ? "rtm " : "") : "",
446 |
447 | intel ? (ebx & 0x00001000 ? "pqm " : "") : "",
448 | intel ? (ebx & 0x00002000 ? "fpcsds " : "") : "",
449 | intel ? (ebx & 0x00004000 ? "mpx " : "") : "",
450 | intel ? (ebx & 0x00008000 ? "pqe " : "") : "",
451 |
452 | intel ? (ebx & 0x00010000 ? "pat " : "") : "",
453 | intel ? (ebx & 0x00020000 ? "pse36 " : "") : "",
454 | intel ? (ebx & 0x00040000 ? "rdseed " : "") : "",
455 | intel ? (ebx & 0x00080000 ? "adx " : "") : "",
456 |
457 | intel ? (ebx & 0x00100000 ? "smap " : "") : "",
458 | intel ? (ebx & 0x00800000 ? "clflushopt " : "") : "",
459 |
460 | intel ? (ebx & 0x01000000 ? "clwb " : "") : "",
461 | intel ? (ebx & 0x02000000 ? "intel_pt " : "") : "",
462 |
463 | intel ? (ebx & 0x10000000 ? "sha " : "") : "",
464 |
465 | intel ? (ecx & 0x00000001 ? "prefetchwt1 " : "") : "",
466 | intel ? (ecx & 0x00000004 ? "umip " : "") : "",
467 | intel ? (ecx & 0x00000008 ? "pku " : "") : "",
468 |
469 | intel ? (ecx & 0x00000010 ? "ospke " : "") : "",
470 |
471 | intel ? (ecx & 0x00040000 ? "rdpid " : "") : "",
472 |
473 | intel ? (ecx & 0x40000000 ? "sgx_lc " : "") : "");
474 | }
475 |
476 | static int get_x86_cpu_extended_flags(int intel, uint32_t ecx, uint32_t edx, char *flags, size_t len)
477 | {
478 | return snprintf(flags, len,
479 | /* edx*/
480 | ""
481 | ""
482 | "%s"
483 | ""
484 | "%s"
485 | "%s%s"
486 | "%s%s%s"
487 | "%s%s%s"
488 |
489 | /* ecx */
490 | "%s%s%s%s"
491 | "%s%s%s%s"
492 | "%s%s%s%s"
493 | "%s%s%s"
494 | "%s%s%s"
495 | "%s%s%s"
496 | "%s%s%s"
497 | "%s",
498 |
499 | edx & 0x00000800 ? "syscall " : "",
500 |
501 | intel ? "" : (edx & 0x00080000 ? "mp " : ""),
502 |
503 | edx & 0x00100000 ? "nx " : "",
504 | intel ? "" : (edx & 0x00400000 ? "mmxext " : ""),
505 |
506 | intel ? "" : (edx & 0x02000000 ? "fxsr_opt " : ""),
507 | edx & 0x04000000 ? "pdpe1gb " : "",
508 | edx & 0x08000000 ? "rdtscp " : "",
509 |
510 | edx & 0x20000000 ? "lm " : "",
511 | intel ? "" : (edx & 0x40000000 ? "3dnowext " : ""),
512 | intel ? "" : (edx & 0x80000000 ? "3dnow " : ""),
513 |
514 | ecx & 0x00000001 ? "lahf_lm " : "",
515 | intel ? "" : (ecx & 0x00000002 ? "cmp_legacy " : ""),
516 | intel ? "" : (ecx & 0x00000004 ? "svm " : ""),
517 | intel ? "" : (ecx & 0x00000008 ? "extapic " : ""),
518 |
519 | intel ? "" : (ecx & 0x00000010 ? "cr8_legacy " : ""),
520 | ecx & 0x00000020 ? "lzcnt " : "",
521 | intel ? "" : (ecx & 0x00000040 ? "sse4a " : ""),
522 | intel ? "" : (ecx & 0x00000080 ? "misalignsse " : ""),
523 |
524 | intel ? "" : (ecx & 0x00000100 ? "3dnowprefetch " : ""),
525 | intel ? "" : (ecx & 0x00000200 ? "osvw " : ""),
526 | intel ? "" : (ecx & 0x00000400 ? "ibs " : ""),
527 | intel ? "" : (ecx & 0x00000800 ? "xop " : ""),
528 |
529 | intel ? "" : (ecx & 0x00001000 ? "skinit " : ""),
530 | intel ? "" : (ecx & 0x00002000 ? "wdt " : ""),
531 | intel ? "" : (ecx & 0x00008000 ? "lwp " : ""),
532 |
533 | intel ? "" : (ecx & 0x00010000 ? "fma4 " : ""),
534 | intel ? "" : (ecx & 0x00020000 ? "tce " : ""),
535 | intel ? "" : (ecx & 0x00080000 ? "nodeid_msr " : ""),
536 |
537 | intel ? "" : (ecx & 0x00200000 ? "tbm " : ""),
538 | intel ? "" : (ecx & 0x00400000 ? "topoext " : ""),
539 | intel ? "" : (ecx & 0x00800000 ? "perfctr_core " : ""),
540 |
541 | intel ? "" : (ecx & 0x01000000 ? "perfctr_nb " : ""),
542 | intel ? "" : (ecx & 0x02000000 ? "dbx " : ""),
543 | intel ? "" : (ecx & 0x08000000 ? "perftsc " : ""),
544 |
545 | intel ? "" : (ecx & 0x10000000 ? "pcx_l2i " : ""));
546 | }
547 |
548 |
549 | static void get_x86_cpu_info(x86_cpu_info *x86_info)
550 | {
551 | int i = 0, flag_len = 0;
552 | uint32_t eax, ebx, ecx, edx;
553 |
554 | __cpuid(0, eax, ebx, ecx, edx);
555 | memcpy(x86_info->vendor, &ebx, sizeof(ebx));
556 | memcpy(&(x86_info->vendor[4]), &edx, sizeof(edx));
557 | memcpy(&(x86_info->vendor[8]), &ecx, sizeof(ecx));
558 | for (i = 0; (i <= eax) && (i <= CPUID_MAX_STANDARD_FUNCTION); i++)
559 | {
560 | x86_info->standard_mask |= (1 << i);
561 | }
562 |
563 | __cpuid(0x80000000, eax, ebx, ecx, edx);
564 | eax &= ~0x80000000;
565 | for (i = 0; (i <= eax) && (i <= CPUID_MAX_EXTENDED_FUNCTION); i++)
566 | {
567 | x86_info->extended_mask |= (1 << i);
568 | }
569 |
570 | eax = CPUID_STANDARD_1_MASK;
571 | if (x86_info->standard_mask & (1 << eax))
572 | {
573 | __cpuid(eax, eax, ebx, ecx, edx);
574 | x86_info->stepping = eax & 0xF;
575 | x86_info->family = (eax >> 8) & 0xF;
576 | x86_info->model = (eax >> 4) & 0xF;
577 | if ((x86_info->family == 6) || (x86_info->family == 15))
578 | {
579 | x86_info->model |= (eax >> 12) & 0xF0;
580 | if (x86_info->family == 15)
581 | {
582 | x86_info->family += (eax >> 20) & 0xFF;
583 | }
584 | }
585 | if (is_intel_cpu(x86_info->vendor))
586 | {
587 | flag_len += get_x86_cpu_standard_flags(1, ecx, edx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
588 | }
589 | else if (is_amd_cpu(x86_info->vendor))
590 | {
591 | flag_len += get_x86_cpu_standard_flags(0, ecx, edx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
592 | }
593 | }
594 |
595 | eax = CPUID_STANDARD_2_MASK;
596 | if ((is_intel_cpu(x86_info->vendor)) && (x86_info->standard_mask & (1 << eax)))
597 | {
598 | int i = 0, count = 0;
599 | uint32_t cache[4]; /* eax, ebx, ecx, edx */
600 |
601 | __cpuid(eax, cache[0], cache[1], cache[2], cache[3]);
602 | count = cache[0] & 0xFF;
603 | while (count--)
604 | {
605 | for (i = 0; i < 4; i++)
606 | {
607 | if (!(cache[i] & 0x80000000))
608 | {
609 | if (i)
610 | {
611 | parse_intel_cache_value(x86_info, cache[i] & 0xFF);
612 | }
613 | parse_intel_cache_value(x86_info, (cache[i] >> 8) & (0xFF));
614 | parse_intel_cache_value(x86_info, (cache[i] >> 16) & (0xFF));
615 | parse_intel_cache_value(x86_info, (cache[i] >> 24) & (0xFF));
616 | }
617 | }
618 | }
619 | }
620 |
621 | if ((is_intel_cpu(x86_info->vendor)) && (x86_info->standard_mask & (1 << eax)) && (x86_info->intel_use_leaf_4_get_cache))
622 | {
623 | int subleaf = 0;
624 | for (subleaf = 0; ; subleaf++)
625 | {
626 | unsigned char cache_type = 0, cache_level = 0;
627 | int cache_size;
628 |
629 | __cpuid_count(CPUID_STANDARD_4_MASK, subleaf, eax, ebx, ecx, edx);
630 |
631 | cache_type = eax & 0x1F;
632 | if (!cache_type)
633 | {
634 | break;
635 | }
636 |
637 | cache_size = (int)((((ebx >> 22) & 0x3FF) + 1) * (((ebx >> 10) & 0x3FF) + 1) *
638 | ((ebx & 0xFFF) + 1) * (ecx + 1) / 1024);
639 | if (!cache_size)
640 | {
641 | break;
642 | }
643 |
644 | cache_level = (eax >> 5) & 0x7;
645 | switch (cache_level)
646 | {
647 | case 1:
648 | {
649 | if (cache_type == 1)
650 | {
651 | snprintf(intel_l1d_cache, sizeof(intel_l1d_cache), "%dK", cache_size);
652 | x86_info->l1d_cache = intel_l1d_cache;
653 | }
654 | else if (cache_type == 2)
655 | {
656 | snprintf(intel_l1i_cache, sizeof(intel_l1i_cache), "%dK", cache_size);
657 | x86_info->l1i_cache = intel_l1i_cache;
658 | }
659 | break;
660 | }
661 | case 2:
662 | {
663 | if (cache_type == 3)
664 | {
665 | snprintf(intel_l2_cache, sizeof(intel_l2_cache), "%dK", cache_size);
666 | x86_info->l2_cache = intel_l2_cache;
667 | }
668 | break;
669 | }
670 | case 3:
671 | {
672 | if (cache_type == 3)
673 | {
674 | int mega_size = cache_size / 1024;
675 | if (mega_size)
676 | {
677 | snprintf(intel_l3_cache, sizeof(intel_l3_cache), "%dM", cache_size / 1024);
678 | }
679 | else
680 | {
681 | snprintf(intel_l3_cache, sizeof(intel_l3_cache), "%dK", cache_size);
682 | }
683 | x86_info->l3_cache = intel_l3_cache;
684 | }
685 | break;
686 | }
687 | default:
688 | {
689 | break;
690 | }
691 | }
692 | }
693 | }
694 |
695 | eax = CPUID_STANDARD_7_MASK;
696 | ecx = 0;
697 | if (x86_info->standard_mask & (1 << eax))
698 | {
699 | __cpuid(eax, eax, ebx, ecx, edx);
700 | if (is_intel_cpu(x86_info->vendor))
701 | {
702 | flag_len += get_x86_cpu_structured_extended_flags(1, ebx, ecx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
703 | }
704 | else if (is_amd_cpu(x86_info->vendor))
705 | {
706 | flag_len += get_x86_cpu_structured_extended_flags(0, ebx, ecx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
707 | }
708 | }
709 |
710 | if ((is_intel_cpu(x86_info->vendor)) && (x86_info->standard_mask & (1 << CPUID_STANDARD_B_MASK)))
711 | {
712 | int subleaf = 0;
713 | for (subleaf = 0; ; subleaf++)
714 | {
715 | int level_type = 0;
716 | __cpuid_count(CPUID_STANDARD_B_MASK, subleaf, eax, ebx, ecx, edx);
717 |
718 | if (!eax && !ebx)
719 | {
720 | break;
721 | }
722 |
723 | level_type = (ecx >> 8) & 0xFF;
724 | if (level_type == 1)
725 | {
726 | x86_info->threads_per_core = ebx;
727 | }
728 | else if (level_type == 2)
729 | {
730 | x86_info->cores_per_socket = ebx;
731 | }
732 | }
733 |
734 | if (x86_info->threads_per_core)
735 | {
736 | x86_info->cores_per_socket = x86_info->cores_per_socket / x86_info->threads_per_core;
737 | }
738 | }
739 |
740 | if (x86_info->extended_mask & (1 << CPUID_EXTENDED_1_MASK))
741 | {
742 | __cpuid(0x80000000 | CPUID_EXTENDED_1_MASK, eax, ebx, ecx, edx);
743 | if (is_intel_cpu(x86_info->vendor))
744 | {
745 | flag_len += get_x86_cpu_extended_flags(1, ecx, edx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
746 | }
747 | else if (is_amd_cpu(x86_info->vendor))
748 | {
749 | flag_len += get_x86_cpu_extended_flags(0, ecx, edx, x86_info->flags + flag_len, sizeof(x86_info->flags) - flag_len);
750 | }
751 | }
752 |
753 | if ((is_amd_cpu(x86_info->vendor)) && (x86_info->extended_mask & (1 << CPUID_EXTENDED_5_MASK)))
754 | {
755 | int kilo_size = 0;
756 | __cpuid(0x80000000 | CPUID_EXTENDED_5_MASK, eax, ebx, ecx, edx);
757 |
758 | kilo_size = (ecx >> 24) & 0xFF;
759 | if (kilo_size)
760 | {
761 | snprintf(amd_l1d_cache, sizeof(amd_l1d_cache), "%dK", kilo_size);
762 | x86_info->l1d_cache = amd_l1d_cache;
763 | }
764 |
765 | kilo_size = (edx >> 24) & 0xFF;
766 | if (kilo_size)
767 | {
768 | snprintf(amd_l1i_cache, sizeof(amd_l1i_cache), "%dK", kilo_size);
769 | x86_info->l1i_cache = amd_l1i_cache;
770 | }
771 | }
772 |
773 | if ((is_amd_cpu(x86_info->vendor)) && (x86_info->extended_mask & (1 << CPUID_EXTENDED_6_MASK)))
774 | {
775 | int kilo_size = 0, mega_size = 0;
776 |
777 | __cpuid(0x80000000 | CPUID_EXTENDED_6_MASK, eax, ebx, ecx, edx);
778 |
779 | kilo_size = (ecx >> 16) & 0xFFFF;
780 | if (kilo_size)
781 | {
782 | snprintf(amd_l2_cache, sizeof(amd_l2_cache), "%dK", kilo_size);
783 | x86_info->l2_cache = amd_l2_cache;
784 | }
785 |
786 | kilo_size = ((edx >> 18) & 0x3FFF) * 512;
787 | if (kilo_size)
788 | {
789 | mega_size = kilo_size / 1024;
790 |
791 | if (mega_size)
792 | {
793 | snprintf(amd_l3_cache, sizeof(amd_l3_cache), "%dM", mega_size);
794 | }
795 | else
796 | {
797 | snprintf(amd_l3_cache, sizeof(amd_l3_cache), "%dK", kilo_size);
798 | }
799 | x86_info->l3_cache = amd_l3_cache;
800 | }
801 | }
802 |
803 | if (is_amd_cpu(x86_info->vendor))
804 | {
805 | if (x86_info->extended_mask & (1 << CPUID_EXTENDED_8_MASK))
806 | {
807 | __cpuid(0x80000000 | CPUID_EXTENDED_8_MASK, eax, ebx, ecx, edx);
808 | x86_info->cores_per_socket = (ecx & 0xFF) + 1;
809 | }
810 | else
811 | {
812 | /* fall back to standard CPUID leaf 1 on old processors */
813 | __cpuid(0x00000001, eax, ebx, ecx, edx);
814 | x86_info->cores_per_socket = (ebx >> 16) & 0xFF;
815 | }
816 |
817 | if (x86_info->extended_mask & (1 << CPUID_EXTENDED_1E_MASK))
818 | {
819 | __cpuid(0x80000000 | CPUID_EXTENDED_1E_MASK, eax, ebx, ecx, edx);
820 | x86_info->threads_per_core = ((ebx >> 8) & 0xFF) + 1;
821 |
822 | if (x86_info->threads_per_core)
823 | {
824 | x86_info->cores_per_socket = x86_info->cores_per_socket / x86_info->threads_per_core;
825 | }
826 | }
827 | }
828 |
829 | /* Remove last space */
830 | if (flag_len && (x86_info->flags[flag_len - 1] == ' '))
831 | {
832 | x86_info->flags[flag_len - 1] = '\0';
833 | }
834 | return;
835 | }
836 | #endif
837 |
838 | static void usage(void)
839 | {
840 | fprintf(stderr, "usage: lscpu [-h|--help]\n");
841 | exit(1);
842 | }
843 |
844 | static void print_cpu_info(gen_cpu_info *gen_info, x86_cpu_info *x86_info)
845 | {
846 | printf("%-24s %s\n", "Architecture:", gen_info->arch);
847 | printf("%-24s %s\n", "Byte Order:", gen_info->byte_order == 1234 ? "Little Endian" : "Big Endian");
848 | #ifdef __OpenBSD__
849 | printf("%-24s %d\n", "Active CPU(s):", gen_info->active_cpu_num);
850 | printf("%-24s %d\n", "Total CPU(s):", gen_info->total_cpu_num);
851 | #else /* Other BSDs */
852 | printf("%-24s %d\n", "Total CPU(s):", gen_info->active_cpu_num);
853 | #endif
854 |
855 | #if defined(__amd64__) || defined(__i386__)
856 | if (x86_info->threads_per_core)
857 | {
858 | printf("%-24s %d\n", "Thread(s) per core:", x86_info->threads_per_core);
859 | }
860 |
861 | if (x86_info->cores_per_socket)
862 | {
863 | printf("%-24s %d\n", "Core(s) per socket:", x86_info->cores_per_socket);
864 | }
865 |
866 | if ((x86_info->threads_per_core) && (x86_info->cores_per_socket))
867 | {
868 | #ifdef __OpenBSD__
869 | int total_cpu_num = gen_info->total_cpu_num;
870 | #else /* Other BSDs */
871 | int total_cpu_num = gen_info->active_cpu_num;
872 | #endif
873 | printf("%-24s %d\n", "Socket(s):", total_cpu_num / ((x86_info->threads_per_core) * (x86_info->cores_per_socket)));
874 | }
875 |
876 | if (x86_cpu_support_standard_flag(x86_info->standard_mask, CPUID_STANDARD_0_MASK))
877 | {
878 | printf("%-24s %s\n", "Vendor:", x86_info->vendor);
879 | }
880 | else
881 | {
882 | #ifdef __OpenBSD__
883 | printf("%-24s %s\n", "Vendor:", gen_info->vendor);
884 | #endif
885 | }
886 |
887 | if (x86_cpu_support_standard_flag(x86_info->standard_mask, CPUID_STANDARD_1_MASK))
888 | {
889 | printf("%-24s %d\n", "CPU family:", x86_info->family);
890 | printf("%-24s %d\n", "Model:", x86_info->model);
891 | }
892 | printf("%-24s %s\n", "Model name:", gen_info->model);
893 | if (x86_cpu_support_standard_flag(x86_info->standard_mask, CPUID_STANDARD_1_MASK))
894 | {
895 | printf("%-24s %d\n", "Stepping:", x86_info->stepping);
896 | }
897 |
898 | #ifdef __OpenBSD__
899 | printf("%-24s %d\n", "CPU MHz:", gen_info->speed);
900 | #endif
901 |
902 | if (x86_info->l1d_cache)
903 | {
904 | printf("%-24s %s\n", "L1d cache:", x86_info->l1d_cache);
905 | }
906 | if (x86_info->l1i_cache)
907 | {
908 | printf("%-24s %s\n", "L1i cache:", x86_info->l1i_cache);
909 | }
910 | if (x86_info->l2_cache)
911 | {
912 | printf("%-24s %s\n", "L2 cache:", x86_info->l2_cache);
913 | }
914 | if (x86_info->l3_cache)
915 | {
916 | printf("%-24s %s\n", "L3 cache:", x86_info->l3_cache);
917 | }
918 |
919 | if (x86_info->flags[0])
920 | {
921 | printf("%-24s %s\n", "Flags:", x86_info->flags);
922 | }
923 | #else /* Other architectures */
924 | printf("%-24s %s\n", "Model name:", gen_info->model);
925 | #ifdef __OpenBSD__
926 | printf("%-24s %d\n", "CPU MHz:", gen_info->speed);
927 | #endif
928 | #endif
929 |
930 | return;
931 | }
932 |
933 | int main(int argc, char **argv)
934 | {
935 | int mib[2], ch = 0, i = 0;
936 |
937 | struct option longopts[] = {
938 | {"help", no_argument, NULL, 'h'},
939 | {NULL, 0, NULL, 0}
940 | };
941 |
942 | sysctl_get_cpu_info sysctl_array[] = {
943 | #ifdef __FreeBSD__
944 | {HW_MACHINE_ARCH, gen_info.arch, sizeof(gen_info.arch), "HW_MACHINE_ARCH"},
945 | #else
946 | {HW_MACHINE, gen_info.arch, sizeof(gen_info.arch), "HW_MACHINE"},
947 | #endif
948 | {HW_BYTEORDER, &(gen_info.byte_order), sizeof(gen_info.byte_order), "HW_BYTEORDER"},
949 | {HW_MODEL, gen_info.model, sizeof(gen_info.model), "HW_MODEL"},
950 | {HW_NCPU, &(gen_info.active_cpu_num), sizeof(gen_info.active_cpu_num), "HW_NCPU"},
951 | #ifdef __OpenBSD__
952 | {HW_VENDOR, gen_info.vendor, sizeof(gen_info.vendor), "HW_VENDOR"},
953 | {HW_NCPUFOUND, &(gen_info.total_cpu_num), sizeof(gen_info.total_cpu_num), "HW_NCPUFOUND"},
954 | {HW_CPUSPEED, &(gen_info.speed), sizeof(gen_info.speed), "HW_CPUSPEED"},
955 | #endif
956 | };
957 |
958 | while ((ch = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
959 | {
960 | switch (ch)
961 | {
962 | case 'h':
963 | case '?':
964 | default:
965 | {
966 | usage();
967 | }
968 | }
969 | }
970 |
971 | argc -= optind;
972 | argv += optind;
973 |
974 | if (argc)
975 | {
976 | usage();
977 | }
978 |
979 | for (i = 0; i < ARRAY_LEN(sysctl_array); i++)
980 | {
981 | mib[0] = CTL_HW;
982 | mib[1] = sysctl_array[i].mib_code;
983 | if (sysctl(mib, ARRAY_LEN(mib), sysctl_array[i].old, &sysctl_array[i].old_len, NULL, 0) == -1)
984 | {
985 | if (errno == EOPNOTSUPP)
986 | {
987 | continue;
988 | }
989 | err(1, "%s", sysctl_array[i].err_msg);
990 | }
991 | }
992 |
993 | #if defined(__amd64__) || defined(__i386__)
994 | get_x86_cpu_info(&x86_info);
995 | #endif
996 |
997 | print_cpu_info(&gen_info, &x86_info);
998 |
999 | return 0;
1000 | }
1001 |
1002 |
--------------------------------------------------------------------------------