use std::collections::HashMap;
use std::time::Duration;
use super::composition::CompositionMode;
use super::context::ExecutionContext;
use super::error::{GrammarError, GrammarResult};
use super::policy::ExecutionPolicy;
use super::resources::ResourceMapping;
use super::strategy::{ExecutionStrategy, StrategyLayer};
use super::transform::DataTransform;
use super::workload::WorkloadSpec;
#[derive(Debug, Clone)]
pub struct ExecutionResult {
pub duration: Duration,
pub gflops: f64,
pub bandwidth_gbps: f64,
pub strategy_used: String,
pub metrics: HashMap<String, f64>,
}
#[derive(Debug, Clone)]
pub struct BuiltComputeBlock {
pub(crate) inner: ComputeBlock,
}
impl BuiltComputeBlock {
pub fn execute(&self) -> GrammarResult<ExecutionResult> {
let start = std::time::Instant::now();
let mut strategies = self.inner.strategies.clone();
strategies.sort_by(|a, b| b.priority.cmp(&a.priority));
let strategy_used = if let Some(layer) = strategies.first() {
format!("{:?}", layer.strategy)
} else {
"Sequential".to_string()
};
let duration = start.elapsed();
let flops = self
.inner
.workload
.as_ref()
.map(|w| w.flop_count())
.unwrap_or(0);
let gflops = if duration.as_secs_f64() > 0.0 {
flops as f64 / duration.as_secs_f64() / 1e9
} else {
0.0
};
Ok(ExecutionResult {
duration,
gflops,
bandwidth_gbps: 0.0,
strategy_used,
metrics: HashMap::new(),
})
}
pub fn workload(&self) -> Option<&WorkloadSpec> {
self.inner.workload.as_ref()
}
}
#[derive(Debug, Clone, Default)]
pub struct ComputeBlock {
pub(crate) workload: Option<WorkloadSpec>,
pub(crate) resources: ResourceMapping,
pub(crate) strategies: Vec<StrategyLayer>,
pub(crate) transform: DataTransform,
pub(crate) context: ExecutionContext,
pub(crate) composition: CompositionMode,
pub(crate) policy: ExecutionPolicy,
pub(crate) facet_params: Option<(String, Vec<f64>)>,
}
impl ComputeBlock {
pub fn builder() -> ComputeBlockBuilder {
ComputeBlockBuilder::new()
}
fn validate(&self) -> GrammarResult<()> {
if self.workload.is_none() {
return Err(GrammarError::MissingWorkload);
}
Ok(())
}
pub fn build(self) -> GrammarResult<BuiltComputeBlock> {
self.validate()?;
Ok(BuiltComputeBlock { inner: self })
}
}
#[derive(Debug, Clone, Default)]
pub struct ComputeBlockBuilder {
inner: ComputeBlock,
}
impl ComputeBlockBuilder {
pub fn new() -> Self {
Self {
inner: ComputeBlock {
transform: DataTransform::Identity,
context: ExecutionContext::Cpu {
affinity: None,
numa_node: None,
},
composition: CompositionMode::None,
policy: ExecutionPolicy::default(),
..Default::default()
},
}
}
pub fn workload(mut self, workload: WorkloadSpec) -> Self {
self.inner.workload = Some(workload);
self
}
pub fn resources(mut self, resources: ResourceMapping) -> Self {
self.inner.resources = resources;
self
}
pub fn strategy(mut self, strategy: ExecutionStrategy) -> Self {
self.inner.strategies.push(StrategyLayer::new(strategy));
self
}
pub fn strategy_with_priority(mut self, strategy: ExecutionStrategy, priority: i32) -> Self {
self.inner
.strategies
.push(StrategyLayer::new(strategy).priority(priority));
self
}
pub fn transform(mut self, transform: DataTransform) -> Self {
self.inner.transform = transform;
self
}
pub fn context(mut self, context: ExecutionContext) -> Self {
self.inner.context = context;
self
}
pub fn composition(mut self, composition: CompositionMode) -> Self {
self.inner.composition = composition;
self
}
pub fn policy(mut self, policy: ExecutionPolicy) -> Self {
self.inner.policy = policy;
self
}
pub fn facet_by(mut self, param: impl Into<String>, values: Vec<f64>) -> Self {
self.inner.facet_params = Some((param.into(), values));
self
}
pub fn build(self) -> GrammarResult<BuiltComputeBlock> {
self.inner.build()
}
}