cubecl_monitoring/
utilization.rs1use alloc::string::String;
2use core::fmt;
3
4use cubecl_ir::PciVendor;
5
6#[derive(Clone, Copy, Debug, PartialEq)]
8#[non_exhaustive]
9pub struct DeviceUtilization {
10 pub busy_percent: f32,
12}
13
14impl DeviceUtilization {
15 pub fn new(busy_percent: f32) -> Self {
17 Self {
18 busy_percent: busy_percent.clamp(0.0, 100.0),
19 }
20 }
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25#[non_exhaustive]
26pub enum UtilizationUnavailable {
27 RuntimeNotLinked,
30 RuntimeReadsNoCounter,
32 NoCard,
34 NoCounterForCard(Option<PciVendor>),
37 CardAddressNotReported,
41 DriverLibraryNotFound(String),
44 NoPreviousReading,
47 QueryFailed(String),
50}
51
52impl fmt::Display for UtilizationUnavailable {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::RuntimeNotLinked => f.write_str("this build does not link the device's runtime"),
56 Self::RuntimeReadsNoCounter => {
57 f.write_str("the device's runtime reads no utilization counter")
58 }
59 Self::NoCard => f.write_str("the device is no card: a software adapter"),
60 Self::NoCounterForCard(Some(vendor)) => {
61 write!(f, "no counter on this platform for a {vendor} card")
62 }
63 Self::NoCounterForCard(None) => {
64 f.write_str("no counter on this platform for a card of no known vendor")
65 }
66 Self::CardAddressNotReported => {
67 f.write_str("the runtime did not report the address the card's counter is found by")
68 }
69 Self::DriverLibraryNotFound(message) => {
70 write!(f, "the driver's library would not load: {message}")
71 }
72 Self::NoPreviousReading => {
73 f.write_str("the counter measures between two readings, and this was the first")
74 }
75 Self::QueryFailed(message) => write!(f, "the counter gave no reading: {message}"),
76 }
77 }
78}
79
80impl core::error::Error for UtilizationUnavailable {}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn a_reading_from_0_to_100_is_kept_as_it_is() {
88 for busy_percent in [0.0, 37.5, 100.0] {
89 assert_eq!(
90 DeviceUtilization::new(busy_percent).busy_percent,
91 busy_percent
92 );
93 }
94 }
95
96 #[test]
97 fn a_reading_above_100_is_held_to_100() {
98 for busy_percent in [100.5, f32::MAX] {
99 assert_eq!(DeviceUtilization::new(busy_percent).busy_percent, 100.0);
100 }
101 }
102}