use query_planning::{
correlation::QueryId,
plan::{GraphAlgorithm, NodeId},
};
use super::QueryMetrics;
use crate::observability::graph_observation::{
GraphClaimExecutionState, GraphMeasuredPeakProvenance, GraphMeasuredPeakRow,
};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct GraphAlgorithmRuntimeMetrics {
pub query_id: Option<QueryId>,
pub node_id: String,
pub algorithm: String,
pub runtime_outcome: String,
pub input_boundary: String,
pub output_boundary: String,
pub construction_policy: String,
pub source_column: String,
pub destination_column: String,
pub weight_column: Option<String>,
pub directed: bool,
pub renumber: bool,
pub algorithm_parameters: String,
pub algorithm_metadata: String,
pub input_rows: u64,
pub input_columns: u64,
pub output_rows: u64,
pub output_columns: u64,
pub output_device_bytes: Option<u64>,
pub graph_peak_bytes: Option<u64>,
pub elapsed_ns: u64,
pub gpu_resident_input_handoffs: u64,
pub host_to_device_uploads: u64,
pub device_to_host_materializations: u64,
}
impl QueryMetrics {
pub fn record_graph_algorithm_runtime(&mut self, mut metrics: GraphAlgorithmRuntimeMetrics) {
if metrics.query_id.is_none() {
metrics.query_id = self.inherited_query_id();
}
self.graph_algorithm_runtime_rows.push(metrics);
}
pub fn record_graph_claim_calibration(&mut self, node_id: NodeId, algorithm: GraphAlgorithm) {
self.graph_claim_calibration_rows.push(GraphMeasuredPeakRow::pending(
self.inherited_query_id(),
node_id.to_string(),
node_id.index(),
algorithm,
));
}
pub fn record_graph_claim_calibration_measurement(
&mut self,
node_id: NodeId,
algorithm: GraphAlgorithm,
measured_peak_bytes: Option<u64>,
measured_peak_provenance: GraphMeasuredPeakProvenance,
) {
self.max_task_observed_peak_bytes = self.max_task_observed_peak_bytes.max(measured_peak_bytes);
let Some(row) = self
.graph_claim_calibration_rows
.iter_mut()
.rev()
.find(|row| row.node_index == node_id.index() && row.algorithm == algorithm)
else {
return;
};
row.record_measured_peak(measured_peak_bytes, measured_peak_provenance);
}
pub fn record_graph_claim_calibration_algorithm_started(&mut self, node_id: NodeId, algorithm: GraphAlgorithm) {
let Some(row) = self
.graph_claim_calibration_rows
.iter_mut()
.rev()
.find(|row| row.node_index == node_id.index() && row.algorithm == algorithm)
else {
return;
};
row.record_execution_state(GraphClaimExecutionState::AlgorithmStarted);
}
pub fn graph_claim_calibration_rows(&self) -> &[GraphMeasuredPeakRow] {
&self.graph_claim_calibration_rows
}
}
#[cfg(test)]
mod tests {
use query_planning::correlation::QueryId;
use super::*;
use crate::observability::graph_observation::{GraphClaimExecutionState, GraphMeasuredPeakProvenance};
#[test]
fn graph_claim_measurement_correlates_by_typed_node_and_algorithm() {
let node = NodeId::from_index_for_test(7);
let mut metrics = QueryMetrics::new("query-a");
metrics.graph_claim_calibration_rows.push(GraphMeasuredPeakRow::pending(
Some(QueryId::new("query-a")),
"n7",
node.index(),
GraphAlgorithm::Bfs,
));
metrics.graph_claim_calibration_rows.push(GraphMeasuredPeakRow::pending(
Some(QueryId::new("query-b")),
"n7",
node.index(),
GraphAlgorithm::PageRank,
));
metrics.record_graph_claim_calibration_measurement(
node,
GraphAlgorithm::PageRank,
Some(1_600),
GraphMeasuredPeakProvenance::CacheScopeHighWater,
);
let bfs = &metrics.graph_claim_calibration_rows[0];
assert_eq!(bfs.query_id.as_ref().map(QueryId::as_str), Some("query-a"));
assert_eq!(bfs.measured_peak_bytes, None, "same node but different algorithm must not correlate");
assert_eq!(bfs.measured_peak_provenance, GraphMeasuredPeakProvenance::Unavailable);
let pagerank = &metrics.graph_claim_calibration_rows[1];
assert_eq!(pagerank.query_id.as_ref().map(QueryId::as_str), Some("query-b"));
assert_eq!(pagerank.measured_peak_bytes, Some(1_600));
assert_eq!(pagerank.measured_peak_provenance, GraphMeasuredPeakProvenance::CacheScopeHighWater);
}
#[test]
fn graph_claim_execution_state_records_only_the_first_exact_boundary() {
let node = NodeId::from_index_for_test(7);
let mut metrics = QueryMetrics::new("query-a");
metrics.graph_claim_calibration_rows.push(GraphMeasuredPeakRow::pending(
Some(QueryId::new("query-a")),
"n7",
node.index(),
GraphAlgorithm::Bfs,
));
metrics.record_graph_claim_calibration_algorithm_started(node, GraphAlgorithm::Bfs);
metrics.record_graph_claim_calibration_algorithm_started(node, GraphAlgorithm::Bfs);
assert_eq!(
metrics.graph_claim_calibration_rows[0].execution_state,
GraphClaimExecutionState::AlgorithmStarted,
"an exact boundary must not be rewritten by a later call"
);
}
}