@@ -76,7 +76,7 @@ const PLR_RING_BITS: &[(u32, &str)] = &[
7676] ;
7777
7878/// Status/log bit pairs shared by IA32_THERM_STATUS and
79- /// IA32_PACKAGE_THERM_STATUS. Bit 12/13 differs between the two .
79+ /// IA32_PACKAGE_THERM_STATUS. The log bit is always one bit higher .
8080const THERM_STATUS_BITS : & [ ( u32 , & str ) ] = & [
8181 ( 0 , "Thermal Monitor" ) ,
8282 ( 2 , "PROCHOT/FORCEPR" ) ,
@@ -85,6 +85,10 @@ const THERM_STATUS_BITS: &[(u32, &str)] = &[
8585 ( 8 , "Threshold #2" ) ,
8686 ( 10 , "Power Limit" ) ,
8787] ;
88+ /// Bits above 11 that only exist in the per core IA32_THERM_STATUS
89+ const THERM_STATUS_CORE_BITS : & [ ( u32 , & str ) ] = & [ ( 12 , "Current Limit" ) , ( 14 , "Cross Domain Limit" ) ] ;
90+ /// Bits above 11 that only exist in IA32_PACKAGE_THERM_STATUS
91+ const THERM_STATUS_PKG_BITS : & [ ( u32 , & str ) ] = & [ ( 12 , "Pmax Limit" ) ] ;
8892
8993fn bit ( value : u64 , bit : u32 ) -> bool {
9094 ( value >> bit) & 1 == 1
@@ -471,22 +475,7 @@ pub fn print_thermal_msrs() {
471475 ) ;
472476 }
473477 println ! ( " Package Thermal Status ({:#010X})" , pkg. raw) ;
474- println ! ( " {:<24} {:>6} {:>6}" , "Condition" , "Active" , "Logged" ) ;
475- for ( b, name) in THERM_STATUS_BITS {
476- println ! (
477- " {:<24} {:>6} {:>6}" ,
478- format!( "{}:" , name) ,
479- yes_no( bit( pkg. raw, * b) ) ,
480- yes_no( bit( pkg. raw, b + 1 ) )
481- ) ;
482- }
483- // Bit 12/13 is Pmax in the package MSR, Current Limit per core
484- println ! (
485- " {:<24} {:>6} {:>6}" ,
486- "Pmax Limit:" ,
487- yes_no( bit( pkg. raw, 12 ) ) ,
488- yes_no( bit( pkg. raw, 13 ) )
489- ) ;
478+ print_therm_status_table ( pkg. raw , THERM_STATUS_PKG_BITS ) ;
490479 }
491480 }
492481
@@ -506,16 +495,40 @@ pub fn print_thermal_msrs() {
506495 print_power_ctl ( ) ;
507496}
508497
509- /// Print the hottest core and which cores are currently being throttled
498+ /// Print the Active/Logged table of a THERM_STATUS style MSR
499+ ///
500+ /// The bits above 11 differ between the per core and the package register, so
501+ /// the caller passes those in.
502+ fn print_therm_status_table ( raw : u64 , extra : & [ ( u32 , & str ) ] ) {
503+ println ! ( " {:<24} {:>6} {:>6}" , "Condition" , "Active" , "Logged" ) ;
504+ for ( b, name) in THERM_STATUS_BITS . iter ( ) . chain ( extra) {
505+ println ! (
506+ " {:<24} {:>6} {:>6}" ,
507+ format!( "{}:" , name) ,
508+ yes_no( bit( raw, * b) ) ,
509+ yes_no( bit( raw, b + 1 ) )
510+ ) ;
511+ }
512+ }
513+
514+ /// Print the hottest core and the thermal status across all cores
510515fn print_core_therm_status ( ref_temp : u8 ) {
511516 let cpus = cpu_count ( ) ;
512517 let mut hottest: Option < ( u32 , i32 ) > = None ;
513518 let mut throttling = Vec :: new ( ) ;
519+ // The status bits are per core, so OR them together to see whether any
520+ // core ever hit a condition. Reading every core individually is far too
521+ // much output on a system with dozens of them.
522+ let mut any = 0 ;
523+ let mut read = 0 ;
514524
515525 for cpu in 0 ..cpus {
516526 let Some ( status) = read_msr ( cpu, MSR_IA32_THERM_STATUS ) . map ( ThermStatus :: from) else {
517527 continue ;
518528 } ;
529+ read += 1 ;
530+ // Mask off temperature, resolution and valid, they're not status bits
531+ any |= status. raw & 0xFFFF ;
519532 if let Some ( temp) = status. temp ( ref_temp) {
520533 match hottest {
521534 Some ( ( _, hottest_temp) ) if temp <= hottest_temp => { }
@@ -527,19 +540,25 @@ fn print_core_therm_status(ref_temp: u8) {
527540 }
528541 }
529542
543+ if read == 0 {
544+ return ;
545+ }
530546 if let Some ( ( cpu, temp) ) = hottest {
531547 println ! ( " Hottest Core Temp: {:>4} C (CPU {})" , temp, cpu) ;
532548 }
533- if cpus > 0 {
534- println ! (
535- " Cores Throttling: {:>4}" ,
536- if throttling. is_empty( ) {
537- "None" . to_string( )
538- } else {
539- throttling. join( ", " )
540- }
541- ) ;
542- }
549+ println ! (
550+ " Cores Throttling: {:>4}" ,
551+ if throttling. is_empty( ) {
552+ "None" . to_string( )
553+ } else {
554+ throttling. join( ", " )
555+ }
556+ ) ;
557+ println ! (
558+ " Core Thermal Status, any of {} cores ({:#06X})" ,
559+ read, any
560+ ) ;
561+ print_therm_status_table ( any, THERM_STATUS_CORE_BITS ) ;
543562}
544563
545564/// Print which limits are clipping the core, graphics and ring frequency
0 commit comments