192 } bits; 193 }; 194 195 union SefCpuid7Eax { 196 uint32_t value; 197 }; 198 199 union SefCpuid7Ebx { 200 uint32_t value; 201 struct { 202 uint32_t fsgsbase : 1, 203 : 2, 204 bmi1 : 1, 205 : 1, 206 avx2 : 1, 207 : 2, 208 bmi2 : 1, 209 erms : 1, 210 : 1, 211 rtm : 1, 212 : 7, 213 adx : 1, 214 : 12; 215 } bits; 216 }; 217 218 union XemXcr0Eax { 219 uint32_t value; 220 struct { 221 uint32_t x87 : 1, 222 sse : 1, 223 ymm : 1, 224 : 29; 225 } bits; 226 }; 227 228 protected: 229 static int _cpu; 230 static int _model; 231 static int _stepping; 232 static int _cpuFeatures; // features returned by the "cpuid" instruction 233 // 0 if this instruction is not available 234 static const char* _features_str; 235 236 static address _cpuinfo_segv_addr; // address of instruction which causes SEGV 237 static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV 238 239 enum { 240 CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) 241 CPU_CMOV = (1 << 1), 242 CPU_FXSR = (1 << 2), 243 CPU_HT = (1 << 3), 244 CPU_MMX = (1 << 4), 245 CPU_3DNOW_PREFETCH = (1 << 5), // Processor supports 3dnow prefetch and prefetchw instructions 246 // may not necessarily support other 3dnow instructions 247 CPU_SSE = (1 << 6), 248 CPU_SSE2 = (1 << 7), 249 CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX) 250 CPU_SSSE3 = (1 << 9), 251 CPU_SSE4A = (1 << 10), 252 CPU_SSE4_1 = (1 << 11), 253 CPU_SSE4_2 = (1 << 12), 254 CPU_POPCNT = (1 << 13), 255 CPU_LZCNT = (1 << 14), 256 CPU_TSC = (1 << 15), 257 CPU_TSCINV = (1 << 16), 258 CPU_AVX = (1 << 17), 259 CPU_AVX2 = (1 << 18), 260 CPU_AES = (1 << 19), 261 CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions 262 CPU_CLMUL = (1 << 21), // carryless multiply for CRC 263 CPU_BMI1 = (1 << 22), 264 CPU_BMI2 = (1 << 23), 265 CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions 266 CPU_ADX = (1 << 25) 267 } cpuFeatureFlags; 268 269 enum { 270 // AMD 271 CPU_FAMILY_AMD_11H = 0x11, 272 // Intel 273 CPU_FAMILY_INTEL_CORE = 6, 274 CPU_MODEL_NEHALEM = 0x1e, 275 CPU_MODEL_NEHALEM_EP = 0x1a, 276 CPU_MODEL_NEHALEM_EX = 0x2e, 277 CPU_MODEL_WESTMERE = 0x25, 278 CPU_MODEL_WESTMERE_EP = 0x2c, 279 CPU_MODEL_WESTMERE_EX = 0x2f, 280 CPU_MODEL_SANDYBRIDGE = 0x2a, 281 CPU_MODEL_SANDYBRIDGE_EP = 0x2d, 282 CPU_MODEL_IVYBRIDGE_EP = 0x3a, 283 CPU_MODEL_HASWELL_E3 = 0x3c, 284 CPU_MODEL_HASWELL_E7 = 0x3f, 285 CPU_MODEL_BROADWELL = 0x3d 286 } cpuExtendedFamily; 287 288 // cpuid information block. All info derived from executing cpuid with 289 // various function numbers is stored here. Intel and AMD info is 290 // merged in this block: accessor methods disentangle it. 291 // 292 // The info block is laid out in subblocks of 4 dwords corresponding to 293 // eax, ebx, ecx and edx, whether or not they contain anything useful. 294 struct CpuidInfo { 295 // cpuid function 0 296 uint32_t std_max_function; 297 uint32_t std_vendor_name_0; 298 uint32_t std_vendor_name_1; 299 uint32_t std_vendor_name_2; 300 301 // cpuid function 1 302 StdCpuid1Eax std_cpuid1_eax; 303 StdCpuid1Ebx std_cpuid1_ebx; 304 StdCpuid1Ecx std_cpuid1_ecx; 305 StdCpuid1Edx std_cpuid1_edx; 387 result += _cpuid_info.std_cpuid1_eax.bits.ext_family; 388 return result; 389 } 390 391 static uint32_t extended_cpu_model() { 392 uint32_t result = _cpuid_info.std_cpuid1_eax.bits.model; 393 result |= _cpuid_info.std_cpuid1_eax.bits.ext_model << 4; 394 return result; 395 } 396 397 static uint32_t cpu_stepping() { 398 uint32_t result = _cpuid_info.std_cpuid1_eax.bits.stepping; 399 return result; 400 } 401 402 static uint logical_processor_count() { 403 uint result = threads_per_core(); 404 return result; 405 } 406 407 static uint32_t feature_flags() { 408 uint32_t result = 0; 409 if (_cpuid_info.std_cpuid1_edx.bits.cmpxchg8 != 0) 410 result |= CPU_CX8; 411 if (_cpuid_info.std_cpuid1_edx.bits.cmov != 0) 412 result |= CPU_CMOV; 413 if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd() && 414 _cpuid_info.ext_cpuid1_edx.bits.fxsr != 0)) 415 result |= CPU_FXSR; 416 // HT flag is set for multi-core processors also. 417 if (threads_per_core() > 1) 418 result |= CPU_HT; 419 if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd() && 420 _cpuid_info.ext_cpuid1_edx.bits.mmx != 0)) 421 result |= CPU_MMX; 422 if (_cpuid_info.std_cpuid1_edx.bits.sse != 0) 423 result |= CPU_SSE; 424 if (_cpuid_info.std_cpuid1_edx.bits.sse2 != 0) 425 result |= CPU_SSE2; 426 if (_cpuid_info.std_cpuid1_ecx.bits.sse3 != 0) 427 result |= CPU_SSE3; 428 if (_cpuid_info.std_cpuid1_ecx.bits.ssse3 != 0) 429 result |= CPU_SSSE3; 430 if (_cpuid_info.std_cpuid1_ecx.bits.sse4_1 != 0) 431 result |= CPU_SSE4_1; 432 if (_cpuid_info.std_cpuid1_ecx.bits.sse4_2 != 0) 433 result |= CPU_SSE4_2; 434 if (_cpuid_info.std_cpuid1_ecx.bits.popcnt != 0) 435 result |= CPU_POPCNT; 436 if (_cpuid_info.std_cpuid1_ecx.bits.avx != 0 && 437 _cpuid_info.std_cpuid1_ecx.bits.osxsave != 0 && 438 _cpuid_info.xem_xcr0_eax.bits.sse != 0 && 439 _cpuid_info.xem_xcr0_eax.bits.ymm != 0) { 440 result |= CPU_AVX; 441 if (_cpuid_info.sef_cpuid7_ebx.bits.avx2 != 0) 442 result |= CPU_AVX2; 443 } 444 if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) 445 result |= CPU_BMI1; 446 if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0) 447 result |= CPU_TSC; 448 if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0) 449 result |= CPU_TSCINV; 450 if (_cpuid_info.std_cpuid1_ecx.bits.aes != 0) 451 result |= CPU_AES; 452 if (_cpuid_info.sef_cpuid7_ebx.bits.erms != 0) 453 result |= CPU_ERMS; 454 if (_cpuid_info.std_cpuid1_ecx.bits.clmul != 0) 455 result |= CPU_CLMUL; 456 if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) 457 result |= CPU_RTM; 458 459 // AMD features. 460 if (is_amd()) { 461 if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) || 462 (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0)) 620 static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; } 621 static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; } 622 static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; } 623 static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; } 624 static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; } 625 static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; } 626 static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } 627 static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } 628 static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } 629 static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; } 630 static bool supports_avx() { return (_cpuFeatures & CPU_AVX) != 0; } 631 static bool supports_avx2() { return (_cpuFeatures & CPU_AVX2) != 0; } 632 static bool supports_tsc() { return (_cpuFeatures & CPU_TSC) != 0; } 633 static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; } 634 static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; } 635 static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; } 636 static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } 637 static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } 638 static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } 639 static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; } 640 // Intel features 641 static bool is_intel_family_core() { return is_intel() && 642 extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } 643 644 static bool is_intel_tsc_synched_at_init() { 645 if (is_intel_family_core()) { 646 uint32_t ext_model = extended_cpu_model(); 647 if (ext_model == CPU_MODEL_NEHALEM_EP || 648 ext_model == CPU_MODEL_WESTMERE_EP || 649 ext_model == CPU_MODEL_SANDYBRIDGE_EP || 650 ext_model == CPU_MODEL_IVYBRIDGE_EP) { 651 // <= 2-socket invariant tsc support. EX versions are usually used 652 // in > 2-socket systems and likely don't synchronize tscs at 653 // initialization. 654 // Code that uses tsc values must be prepared for them to arbitrarily 655 // jump forward or backward. 656 return true; 657 } 658 } 659 return false; | 192 } bits; 193 }; 194 195 union SefCpuid7Eax { 196 uint32_t value; 197 }; 198 199 union SefCpuid7Ebx { 200 uint32_t value; 201 struct { 202 uint32_t fsgsbase : 1, 203 : 2, 204 bmi1 : 1, 205 : 1, 206 avx2 : 1, 207 : 2, 208 bmi2 : 1, 209 erms : 1, 210 : 1, 211 rtm : 1, 212 : 4, 213 avx512f : 1, 214 avx512dq : 1, 215 : 1, 216 adx : 1, 217 : 6, 218 avx512pf : 1, 219 avx512er : 1, 220 avx512cd : 1, 221 : 1, 222 avx512bw : 1, 223 avx512vl : 1; 224 } bits; 225 }; 226 227 union XemXcr0Eax { 228 uint32_t value; 229 struct { 230 uint32_t x87 : 1, 231 sse : 1, 232 ymm : 1, 233 : 2, 234 opmask : 1, 235 zmm512 : 1, 236 zmm32 : 1, 237 : 24; 238 } bits; 239 }; 240 241 protected: 242 static int _cpu; 243 static int _model; 244 static int _stepping; 245 static uint64_t _cpuFeatures; // features returned by the "cpuid" instruction 246 // 0 if this instruction is not available 247 static const char* _features_str; 248 249 static address _cpuinfo_segv_addr; // address of instruction which causes SEGV 250 static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV 251 252 enum { 253 CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) 254 CPU_CMOV = (1 << 1), 255 CPU_FXSR = (1 << 2), 256 CPU_HT = (1 << 3), 257 CPU_MMX = (1 << 4), 258 CPU_3DNOW_PREFETCH = (1 << 5), // Processor supports 3dnow prefetch and prefetchw instructions 259 // may not necessarily support other 3dnow instructions 260 CPU_SSE = (1 << 6), 261 CPU_SSE2 = (1 << 7), 262 CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX) 263 CPU_SSSE3 = (1 << 9), 264 CPU_SSE4A = (1 << 10), 265 CPU_SSE4_1 = (1 << 11), 266 CPU_SSE4_2 = (1 << 12), 267 CPU_POPCNT = (1 << 13), 268 CPU_LZCNT = (1 << 14), 269 CPU_TSC = (1 << 15), 270 CPU_TSCINV = (1 << 16), 271 CPU_AVX = (1 << 17), 272 CPU_AVX2 = (1 << 18), 273 CPU_AES = (1 << 19), 274 CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions 275 CPU_CLMUL = (1 << 21), // carryless multiply for CRC 276 CPU_BMI1 = (1 << 22), 277 CPU_BMI2 = (1 << 23), 278 CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions 279 CPU_ADX = (1 << 25), 280 CPU_AVX512F = (1 << 26), // AVX 512bit foundation instructions 281 CPU_AVX512DQ = (1 << 27), 282 CPU_AVX512PF = (1 << 28), 283 CPU_AVX512ER = (1 << 29), 284 CPU_AVX512CD = (1 << 30), 285 CPU_AVX512BW = (1 << 31) 286 } cpuFeatureFlags; 287 288 #define CPU_AVX512VL 0x100000000 // EVEX instructions with smaller vector length : enums are limited to 32bit 289 290 enum { 291 // AMD 292 CPU_FAMILY_AMD_11H = 0x11, 293 // Intel 294 CPU_FAMILY_INTEL_CORE = 6, 295 CPU_MODEL_NEHALEM = 0x1e, 296 CPU_MODEL_NEHALEM_EP = 0x1a, 297 CPU_MODEL_NEHALEM_EX = 0x2e, 298 CPU_MODEL_WESTMERE = 0x25, 299 CPU_MODEL_WESTMERE_EP = 0x2c, 300 CPU_MODEL_WESTMERE_EX = 0x2f, 301 CPU_MODEL_SANDYBRIDGE = 0x2a, 302 CPU_MODEL_SANDYBRIDGE_EP = 0x2d, 303 CPU_MODEL_IVYBRIDGE_EP = 0x3a, 304 CPU_MODEL_HASWELL_E3 = 0x3c, 305 CPU_MODEL_HASWELL_E7 = 0x3f, 306 CPU_MODEL_BROADWELL = 0x3d, 307 CPU_MODEL_SKYLAKE = CPU_MODEL_HASWELL_E3 308 } cpuExtendedFamily; 309 310 // cpuid information block. All info derived from executing cpuid with 311 // various function numbers is stored here. Intel and AMD info is 312 // merged in this block: accessor methods disentangle it. 313 // 314 // The info block is laid out in subblocks of 4 dwords corresponding to 315 // eax, ebx, ecx and edx, whether or not they contain anything useful. 316 struct CpuidInfo { 317 // cpuid function 0 318 uint32_t std_max_function; 319 uint32_t std_vendor_name_0; 320 uint32_t std_vendor_name_1; 321 uint32_t std_vendor_name_2; 322 323 // cpuid function 1 324 StdCpuid1Eax std_cpuid1_eax; 325 StdCpuid1Ebx std_cpuid1_ebx; 326 StdCpuid1Ecx std_cpuid1_ecx; 327 StdCpuid1Edx std_cpuid1_edx; 409 result += _cpuid_info.std_cpuid1_eax.bits.ext_family; 410 return result; 411 } 412 413 static uint32_t extended_cpu_model() { 414 uint32_t result = _cpuid_info.std_cpuid1_eax.bits.model; 415 result |= _cpuid_info.std_cpuid1_eax.bits.ext_model << 4; 416 return result; 417 } 418 419 static uint32_t cpu_stepping() { 420 uint32_t result = _cpuid_info.std_cpuid1_eax.bits.stepping; 421 return result; 422 } 423 424 static uint logical_processor_count() { 425 uint result = threads_per_core(); 426 return result; 427 } 428 429 static uint64_t feature_flags() { 430 uint64_t result = 0; 431 if (_cpuid_info.std_cpuid1_edx.bits.cmpxchg8 != 0) 432 result |= CPU_CX8; 433 if (_cpuid_info.std_cpuid1_edx.bits.cmov != 0) 434 result |= CPU_CMOV; 435 if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd() && 436 _cpuid_info.ext_cpuid1_edx.bits.fxsr != 0)) 437 result |= CPU_FXSR; 438 // HT flag is set for multi-core processors also. 439 if (threads_per_core() > 1) 440 result |= CPU_HT; 441 if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd() && 442 _cpuid_info.ext_cpuid1_edx.bits.mmx != 0)) 443 result |= CPU_MMX; 444 if (_cpuid_info.std_cpuid1_edx.bits.sse != 0) 445 result |= CPU_SSE; 446 if (_cpuid_info.std_cpuid1_edx.bits.sse2 != 0) 447 result |= CPU_SSE2; 448 if (_cpuid_info.std_cpuid1_ecx.bits.sse3 != 0) 449 result |= CPU_SSE3; 450 if (_cpuid_info.std_cpuid1_ecx.bits.ssse3 != 0) 451 result |= CPU_SSSE3; 452 if (_cpuid_info.std_cpuid1_ecx.bits.sse4_1 != 0) 453 result |= CPU_SSE4_1; 454 if (_cpuid_info.std_cpuid1_ecx.bits.sse4_2 != 0) 455 result |= CPU_SSE4_2; 456 if (_cpuid_info.std_cpuid1_ecx.bits.popcnt != 0) 457 result |= CPU_POPCNT; 458 if (_cpuid_info.std_cpuid1_ecx.bits.avx != 0 && 459 _cpuid_info.std_cpuid1_ecx.bits.osxsave != 0 && 460 _cpuid_info.xem_xcr0_eax.bits.sse != 0 && 461 _cpuid_info.xem_xcr0_eax.bits.ymm != 0) { 462 result |= CPU_AVX; 463 if (_cpuid_info.sef_cpuid7_ebx.bits.avx2 != 0) 464 result |= CPU_AVX2; 465 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512f != 0 && 466 _cpuid_info.xem_xcr0_eax.bits.opmask != 0 && 467 _cpuid_info.xem_xcr0_eax.bits.zmm512 != 0 && 468 _cpuid_info.xem_xcr0_eax.bits.zmm32 != 0) { 469 result |= CPU_AVX512F; 470 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512cd != 0) 471 result |= CPU_AVX512CD; 472 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512dq != 0) 473 result |= CPU_AVX512DQ; 474 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512pf != 0) 475 result |= CPU_AVX512PF; 476 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512er != 0) 477 result |= CPU_AVX512ER; 478 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512bw != 0) 479 result |= CPU_AVX512BW; 480 if (_cpuid_info.sef_cpuid7_ebx.bits.avx512vl != 0) 481 result |= CPU_AVX512VL; 482 } 483 } 484 if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) 485 result |= CPU_BMI1; 486 if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0) 487 result |= CPU_TSC; 488 if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0) 489 result |= CPU_TSCINV; 490 if (_cpuid_info.std_cpuid1_ecx.bits.aes != 0) 491 result |= CPU_AES; 492 if (_cpuid_info.sef_cpuid7_ebx.bits.erms != 0) 493 result |= CPU_ERMS; 494 if (_cpuid_info.std_cpuid1_ecx.bits.clmul != 0) 495 result |= CPU_CLMUL; 496 if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) 497 result |= CPU_RTM; 498 499 // AMD features. 500 if (is_amd()) { 501 if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) || 502 (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0)) 660 static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; } 661 static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; } 662 static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; } 663 static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; } 664 static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; } 665 static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; } 666 static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } 667 static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } 668 static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } 669 static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; } 670 static bool supports_avx() { return (_cpuFeatures & CPU_AVX) != 0; } 671 static bool supports_avx2() { return (_cpuFeatures & CPU_AVX2) != 0; } 672 static bool supports_tsc() { return (_cpuFeatures & CPU_TSC) != 0; } 673 static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; } 674 static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; } 675 static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; } 676 static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } 677 static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } 678 static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } 679 static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; } 680 static bool supports_evex() { return (_cpuFeatures & CPU_AVX512F) != 0; } 681 static bool supports_avx512dq() { return (_cpuFeatures & CPU_AVX512DQ) != 0; } 682 static bool supports_avx512pf() { return (_cpuFeatures & CPU_AVX512PF) != 0; } 683 static bool supports_avx512er() { return (_cpuFeatures & CPU_AVX512ER) != 0; } 684 static bool supports_avx512cd() { return (_cpuFeatures & CPU_AVX512CD) != 0; } 685 static bool supports_avx512bw() { return (_cpuFeatures & CPU_AVX512BW) != 0; } 686 static bool supports_avx512vl() { return (_cpuFeatures & CPU_AVX512VL) != 0; } 687 // Intel features 688 static bool is_intel_family_core() { return is_intel() && 689 extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } 690 691 static bool is_intel_tsc_synched_at_init() { 692 if (is_intel_family_core()) { 693 uint32_t ext_model = extended_cpu_model(); 694 if (ext_model == CPU_MODEL_NEHALEM_EP || 695 ext_model == CPU_MODEL_WESTMERE_EP || 696 ext_model == CPU_MODEL_SANDYBRIDGE_EP || 697 ext_model == CPU_MODEL_IVYBRIDGE_EP) { 698 // <= 2-socket invariant tsc support. EX versions are usually used 699 // in > 2-socket systems and likely don't synchronize tscs at 700 // initialization. 701 // Code that uses tsc values must be prepared for them to arbitrarily 702 // jump forward or backward. 703 return true; 704 } 705 } 706 return false; |