├── .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 | 8 | 9 |
macOSOpenBSDFreeBSDNetBSD
DragonFlyBSDMidnightBSDTrueOS?
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 | --------------------------------------------------------------------------------