@@ -251,10 +251,11 @@ pub fn read_all_xgmi_stats() -> io::Result<Vec<XgmiSnapshot>> {
251251 }
252252 let bdfs: Vec < Option < u64 > > = handles. iter ( ) . map ( |& h| read_bdf ( api, h) ) . collect ( ) ;
253253 let names = gpu_names ( api, & handles) ;
254+ let speeds = link_speeds ( api, & handles) ;
254255
255256 let mut snapshots = Vec :: with_capacity ( handles. len ( ) ) ;
256257 for idx in 0 ..handles. len ( ) {
257- if let Some ( snap) = read_processor_snapshot ( api, & handles, & bdfs, names, idx) {
258+ if let Some ( snap) = read_processor_snapshot ( api, & handles, & bdfs, names, speeds , idx) {
258259 snapshots. push ( snap) ;
259260 }
260261 }
@@ -274,6 +275,17 @@ fn gpu_names(api: &Amdsmi, handles: &[ffi::ProcessorHandle]) -> &'static [String
274275 } )
275276}
276277
278+ /// Per-GPU (bit_rate, bandwidth) Gb/s, read once and cached by GPU index:
279+ /// link speed is static and `amdsmi_get_pcie_info` costs ~0.5 ms per call —
280+ /// roughly half of the whole refresh when polled for every GPU each second.
281+ fn link_speeds (
282+ api : & Amdsmi ,
283+ handles : & [ ffi:: ProcessorHandle ] ,
284+ ) -> & ' static [ ( Option < f64 > , Option < f64 > ) ] {
285+ static SPEEDS : OnceLock < Vec < ( Option < f64 > , Option < f64 > ) > > = OnceLock :: new ( ) ;
286+ SPEEDS . get_or_init ( || handles. iter ( ) . map ( |& h| read_link_speed ( api, h) ) . collect ( ) )
287+ }
288+
277289/// Flatten socket/processor enumeration into one ordered GPU handle list.
278290/// This order defines `gpu_index` and matches amdsmi's accumulator indexing.
279291fn enumerate_gpus ( api : & Amdsmi ) -> Vec < ffi:: ProcessorHandle > {
@@ -319,6 +331,7 @@ fn read_processor_snapshot(
319331 handles : & [ ffi:: ProcessorHandle ] ,
320332 bdfs : & [ Option < u64 > ] ,
321333 names : & [ String ] ,
334+ speeds : & [ ( Option < f64 > , Option < f64 > ) ] ,
322335 idx : usize ,
323336) -> Option < XgmiSnapshot > {
324337 let handle = handles[ idx] ;
@@ -330,7 +343,7 @@ fn read_processor_snapshot(
330343 let metrics = & metrics. value ;
331344
332345 let gpu_name = names. get ( idx) . cloned ( ) . unwrap_or_default ( ) ;
333- let ( bit_rate_gbps, speed_gbps) = read_link_speed ( api , handle ) ;
346+ let ( bit_rate_gbps, speed_gbps) = speeds . get ( idx ) . copied ( ) . unwrap_or ( ( None , None ) ) ;
334347 let ( correctable_errors, uncorrectable_errors) = read_wafl_errors ( api, handle) ;
335348
336349 let n = ( metrics. num_links as usize ) . min ( ffi:: AMDSMI_MAX_NUM_XGMI_PHYSICAL_LINK ) ;
0 commit comments