pub mod common;
pub mod exporter_trait;
pub mod furiosa;
pub mod gaudi;
pub mod google_tpu;
pub mod rebellions;
#[cfg(target_os = "linux")]
pub mod tenstorrent;
use crate::api::metrics::{MetricBuilder, MetricExporter};
use crate::device::GpuInfo;
use exporter_trait::{CommonNpuMetrics, NpuExporter};
use std::sync::OnceLock;
static EXPORTER_POOL: OnceLock<Vec<Box<dyn NpuExporter + Send + Sync>>> = OnceLock::new();
pub struct NpuMetricExporter<'a> {
pub npu_info: &'a [GpuInfo],
common: common::CommonNpuExporter,
}
impl<'a> NpuMetricExporter<'a> {
pub fn new(npu_info: &'a [GpuInfo]) -> Self {
EXPORTER_POOL.get_or_init(|| {
#[allow(unused_mut)]
let mut exporters: Vec<Box<dyn NpuExporter + Send + Sync>> = vec![
Box::new(gaudi::GaudiExporter::new()),
Box::new(rebellions::RebellionsExporter::new()),
Box::new(furiosa::FuriosaExporter::new()),
Box::new(google_tpu::GoogleTpuExporter::new()),
];
#[cfg(target_os = "linux")]
exporters.insert(0, Box::new(tenstorrent::TenstorrentExporter::new()));
exporters
});
Self {
npu_info,
common: common::CommonNpuExporter::new(),
}
}
fn find_exporter(&self, info: &GpuInfo) -> Option<&(dyn NpuExporter + Send + Sync)> {
EXPORTER_POOL.get().and_then(|exporters| {
let name = &info.name;
#[cfg(target_os = "linux")]
if name.contains("Tenstorrent") {
return Some(exporters[0].as_ref());
}
#[cfg(target_os = "linux")]
let (gaudi_idx, rebellions_idx, furiosa_idx, tpu_idx) = (1, 2, 3, 4);
#[cfg(not(target_os = "linux"))]
let (gaudi_idx, rebellions_idx, furiosa_idx, tpu_idx) = (0, 1, 2, 3);
if name.contains("Gaudi") || name.contains("HL-") {
return Some(exporters[gaudi_idx].as_ref());
} else if name.contains("Rebellions") {
return Some(exporters[rebellions_idx].as_ref());
} else if name.contains("Furiosa") || name.contains("RNGD") || name.contains("Warboy") {
return Some(exporters[furiosa_idx].as_ref());
} else if name.contains("TPU") || name.contains("Google") {
return Some(exporters[tpu_idx].as_ref());
}
exporters
.iter()
.find(|exporter| exporter.can_handle(info))
.map(|b| b.as_ref())
})
}
#[allow(dead_code)]
fn export_generic_npu_metrics(
&self,
builder: &mut MetricBuilder,
info: &GpuInfo,
index: usize,
) {
self.common.export_generic_npu_metrics(builder, info, index);
}
fn export_vendor_metrics(
&self,
builder: &mut MetricBuilder,
info: &GpuInfo,
index: usize,
index_str: &str,
) {
if let Some(exporter) = self.find_exporter(info) {
exporter.export_vendor_metrics(builder, info, index, index_str);
}
}
fn export_device_metrics(&self, builder: &mut MetricBuilder, info: &GpuInfo, index: usize) {
let index_str = index.to_string();
self.export_generic_npu_metrics_with_str(builder, info, &index_str);
self.export_vendor_metrics(builder, info, index, &index_str);
}
fn export_generic_npu_metrics_with_str(
&self,
builder: &mut MetricBuilder,
info: &GpuInfo,
index_str: &str,
) {
self.common
.export_generic_npu_metrics_str(builder, info, index_str);
}
}
impl<'a> MetricExporter for NpuMetricExporter<'a> {
fn export_metrics(&self) -> String {
let mut builder = MetricBuilder::new();
for (i, info) in self.npu_info.iter().enumerate() {
if info.device_type == "NPU" || info.device_type == "TPU" {
self.export_device_metrics(&mut builder, info, i);
}
}
builder.build()
}
}