@@ -28,6 +28,7 @@ use super::{
2828 VIRTIO_BALLOON_S_OOM_KILL , VIRTIO_BALLOON_S_SWAP_IN , VIRTIO_BALLOON_S_SWAP_OUT ,
2929} ;
3030use crate :: devices:: virtio:: balloon:: BalloonError ;
31+ use crate :: devices:: virtio:: balloon:: metrics:: BalloonDeviceMetrics ;
3132use crate :: devices:: virtio:: device:: { ActiveState , VirtioDeviceType } ;
3233use crate :: devices:: virtio:: generated:: virtio_config:: VIRTIO_F_VERSION_1 ;
3334use crate :: devices:: virtio:: queue:: InvalidAvailIdx ;
@@ -226,7 +227,11 @@ impl BalloonStats {
226227 VIRTIO_BALLOON_S_ASYNC_RECLAIM => self . async_reclaim = val,
227228 VIRTIO_BALLOON_S_DIRECT_RECLAIM => self . direct_reclaim = val,
228229 tag => {
229- METRICS . stats_update_fails . inc ( ) ;
230+ METRICS
231+ . get ( )
232+ . expect ( "Balloon metrics uninitialized, failed to increment stats_update_fails" )
233+ . stats_update_fails
234+ . inc ( ) ;
230235 debug ! ( "balloon: unknown stats update tag: {tag}" ) ;
231236 }
232237 }
@@ -259,6 +264,8 @@ pub struct Balloon {
259264
260265 // Holds state for free page hinting
261266 pub ( crate ) hinting_state : HintingState ,
267+ // Device metrics instance.
268+ metrics : Arc < BalloonDeviceMetrics > ,
262269}
263270
264271impl Balloon {
@@ -303,6 +310,10 @@ impl Balloon {
303310 . collect :: < Result < Vec < _ > , _ > > ( ) ?;
304311
305312 let stats_timer = TimerFd :: new ( ) ;
313+ let metrics = Arc :: new ( BalloonDeviceMetrics :: default ( ) ) ;
314+ let _ = METRICS
315+ . set ( metrics. clone ( ) )
316+ . inspect_err ( |_| warn ! ( "Balloon metrics are already initialized!" ) ) ;
306317
307318 Ok ( Balloon {
308319 avail_features,
@@ -319,9 +330,10 @@ impl Balloon {
319330 stats_polling_interval_s,
320331 stats_timer,
321332 stats_desc_index : None ,
322- latest_stats : BalloonStats :: default ( ) ,
333+ latest_stats : BalloonStats :: default ( ) , // we need to pass the same metrics instance, just get it from the variable maybe?
323334 pfn_buffer : [ 0u32 ; MAX_PAGE_COMPACT_BUFFER ] ,
324335 hinting_state : Default :: default ( ) ,
336+ metrics,
325337 } )
326338 }
327339
@@ -372,7 +384,7 @@ impl Balloon {
372384 . active_state ( )
373385 . ok_or ( BalloonError :: DeviceNotActive ) ?
374386 . mem ;
375- METRICS . inflate_count . inc ( ) ;
387+ self . metrics . inflate_count . inc ( ) ;
376388
377389 let queue = & mut self . queues [ INFLATE_INDEX ] ;
378390 // The pfn buffer index used during descriptor processing.
@@ -459,7 +471,7 @@ impl Balloon {
459471 }
460472
461473 pub ( crate ) fn process_deflate_queue ( & mut self ) -> Result < ( ) , BalloonError > {
462- METRICS . deflate_count . inc ( ) ;
474+ self . metrics . deflate_count . inc ( ) ;
463475
464476 let queue = & mut self . queues [ DEFLATE_INDEX ] ;
465477 let mut needs_interrupt = false ;
@@ -480,7 +492,7 @@ impl Balloon {
480492 pub ( crate ) fn process_stats_queue ( & mut self ) -> Result < ( ) , BalloonError > {
481493 // This is safe since we checked in the event handler that the device is activated.
482494 let mem = & self . device_state . active_state ( ) . unwrap ( ) . mem ;
483- METRICS . stats_updates_count . inc ( ) ;
495+ self . metrics . stats_updates_count . inc ( ) ;
484496
485497 while let Some ( head) = self . queues [ STATS_INDEX ] . pop ( ) ? {
486498 if let Some ( prev_stats_desc) = self . stats_desc_index {
@@ -566,12 +578,12 @@ impl Balloon {
566578 continue ;
567579 }
568580
569- METRICS . free_page_hint_count . inc ( ) ;
581+ self . metrics . free_page_hint_count . inc ( ) ;
570582 if let Err ( err) = mem. discard_range ( desc. addr , desc. len as usize ) {
571- METRICS . free_page_hint_fails . inc ( ) ;
583+ self . metrics . free_page_hint_fails . inc ( ) ;
572584 error ! ( "balloon hinting: failed to remove range: {err:?}" ) ;
573585 } else {
574- METRICS . free_page_hint_freed . add ( desc. len as u64 ) ;
586+ self . metrics . free_page_hint_freed . add ( desc. len as u64 ) ;
575587 }
576588 }
577589
@@ -608,12 +620,12 @@ impl Balloon {
608620
609621 let mut last_desc = Some ( head) ;
610622 while let Some ( desc) = last_desc {
611- METRICS . free_page_report_count . inc ( ) ;
623+ self . metrics . free_page_report_count . inc ( ) ;
612624 if let Err ( err) = mem. discard_range ( desc. addr , desc. len as usize ) {
613- METRICS . free_page_report_fails . inc ( ) ;
625+ self . metrics . free_page_report_fails . inc ( ) ;
614626 error ! ( "balloon: failed to remove range: {err:?}" ) ;
615627 } else {
616- METRICS . free_page_report_freed . add ( desc. len as u64 ) ;
628+ self . metrics . free_page_report_freed . add ( desc. len as u64 ) ;
617629 }
618630 last_desc = desc. next_descriptor ( ) ;
619631 }
@@ -638,7 +650,7 @@ impl Balloon {
638650 . unwrap_or_else ( |_| panic ! ( "balloon: invalid queue id: {qidx}" ) ) ,
639651 ) )
640652 . map_err ( |err| {
641- METRICS . event_fails . inc ( ) ;
653+ self . metrics . event_fails . inc ( ) ;
642654 BalloonError :: InterruptError ( err)
643655 } )
644656 }
@@ -931,7 +943,7 @@ impl VirtioDevice for Balloon {
931943
932944 self . device_state = DeviceState :: Activated ( ActiveState { mem, interrupt } ) ;
933945 if self . activate_evt . write ( 1 ) . is_err ( ) {
934- METRICS . activate_fails . inc ( ) ;
946+ self . metrics . activate_fails . inc ( ) ;
935947 self . device_state = DeviceState :: Inactive ;
936948 return Err ( ActivateError :: EventFd ) ;
937949 }
@@ -1359,7 +1371,7 @@ pub(crate) mod tests {
13591371 ) ;
13601372
13611373 check_metric_after_block ! (
1362- METRICS . event_fails,
1374+ self . metrics . event_fails,
13631375 1 ,
13641376 balloon
13651377 . process_inflate_queue_event( )
@@ -1386,7 +1398,7 @@ pub(crate) mod tests {
13861398 ) ;
13871399
13881400 check_metric_after_block ! (
1389- METRICS . inflate_count,
1401+ self . metrics . inflate_count,
13901402 1 ,
13911403 invoke_handler_for_queue_event( & mut balloon, INFLATE_INDEX )
13921404 ) ;
@@ -1421,7 +1433,7 @@ pub(crate) mod tests {
14211433 VIRTQ_DESC_F_NEXT ,
14221434 ) ;
14231435 check_metric_after_block ! (
1424- METRICS . event_fails,
1436+ self . metrics . event_fails,
14251437 1 ,
14261438 balloon
14271439 . process_deflate_queue_event( )
@@ -1441,7 +1453,7 @@ pub(crate) mod tests {
14411453 VIRTQ_DESC_F_NEXT ,
14421454 ) ;
14431455 check_metric_after_block ! (
1444- METRICS . deflate_count,
1456+ self . metrics . deflate_count,
14451457 1 ,
14461458 invoke_handler_for_queue_event( & mut balloon, DEFLATE_INDEX )
14471459 ) ;
@@ -1472,7 +1484,7 @@ pub(crate) mod tests {
14721484 VIRTQ_DESC_F_NEXT ,
14731485 ) ;
14741486 check_metric_after_block ! (
1475- METRICS . event_fails,
1487+ self . metrics . event_fails,
14761488 1 ,
14771489 balloon
14781490 . process_stats_queue_event( )
@@ -1509,7 +1521,7 @@ pub(crate) mod tests {
15091521 2 * u32:: try_from ( SIZE_OF_STAT ) . unwrap ( ) ,
15101522 VIRTQ_DESC_F_NEXT ,
15111523 ) ;
1512- check_metric_after_block ! ( METRICS . stats_updates_count, 1 , {
1524+ check_metric_after_block ! ( self . metrics . stats_updates_count, 1 , {
15131525 // Trigger the queue event.
15141526 balloon. queue_events( ) [ STATS_INDEX ] . write( 1 ) . unwrap( ) ;
15151527 balloon. process_stats_queue_event( ) . unwrap( ) ;
@@ -1528,7 +1540,7 @@ pub(crate) mod tests {
15281540 // we could just process the timer event and it would not
15291541 // return an error.
15301542 std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
1531- check_metric_after_block ! ( METRICS . event_fails, 0 , {
1543+ check_metric_after_block ! ( self . metrics . event_fails, 0 , {
15321544 // Trigger the timer event, which consumes the stats
15331545 // descriptor index and signals the used queue.
15341546 assert!( balloon. stats_desc_index. is_some( ) ) ;
@@ -1560,7 +1572,7 @@ pub(crate) mod tests {
15601572
15611573 th. add_scatter_gather ( reporting_idx, 0 , & [ ( 0 , safe_addr, page_size_chain, 0 ) ] ) ;
15621574 check_metric_after_block ! (
1563- METRICS . free_page_report_freed,
1575+ self . metrics . free_page_report_freed,
15641576 page_size,
15651577 invoke_handler_for_queue_event( & mut th. device( ) , reporting_idx)
15661578 ) ;
@@ -1577,7 +1589,7 @@ pub(crate) mod tests {
15771589 ) ;
15781590
15791591 check_metric_after_block ! (
1580- METRICS . free_page_report_freed,
1592+ self . metrics . free_page_report_freed,
15811593 page_size * 3 ,
15821594 invoke_handler_for_queue_event( & mut th. device( ) , reporting_idx)
15831595 ) ;
@@ -1586,7 +1598,7 @@ pub(crate) mod tests {
15861598 th. add_scatter_gather ( reporting_idx, 0 , & [ ( 1 , safe_addr + 1 , page_size_chain, 0 ) ] ) ;
15871599
15881600 check_metric_after_block ! (
1589- METRICS . free_page_report_fails,
1601+ self . metrics . free_page_report_fails,
15901602 1 ,
15911603 invoke_handler_for_queue_event( & mut th. device( ) , reporting_idx)
15921604 ) ;
@@ -1665,7 +1677,7 @@ pub(crate) mod tests {
16651677 ] ,
16661678 ) ;
16671679 check_metric_after_block ! (
1668- METRICS . free_page_hint_freed,
1680+ self . metrics . free_page_hint_freed,
16691681 0 ,
16701682 self . th. device( ) . process_free_page_hinting_queue( )
16711683 ) ;
@@ -1708,7 +1720,7 @@ pub(crate) mod tests {
17081720 } ;
17091721 self . th . add_scatter_gather ( self . hinting_idx , 0 , & payload) ;
17101722 check_metric_after_block ! (
1711- METRICS . free_page_hint_freed,
1723+ self . metrics . free_page_hint_freed,
17121724 expected,
17131725 invoke_handler_for_queue_event( & mut self . th. device( ) , self . hinting_idx)
17141726 ) ;
@@ -1839,7 +1851,7 @@ pub(crate) mod tests {
18391851 ) ;
18401852
18411853 check_metric_after_block ! (
1842- METRICS . free_page_hint_fails,
1854+ self . metrics . free_page_hint_fails,
18431855 1 ,
18441856 ht. th. device( ) . process_free_page_hinting_queue( ) . unwrap( )
18451857 ) ;
0 commit comments