Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 3 additions & 38 deletions crates/devtools/examples/canonical_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,12 @@
// One-off: pretty-print the `OperatorNode` DAG for one canonical query per variant,
// plus custom Join/SetOp/Dedup/CTE probes, to eyeball the actual shape.

use asap_devtools::corpora::{bgp_catalog, dqc_catalog};
use asap_devtools::lower_promql_with_sample_interval;
use asap_frontend_sql::{lower_sql_dialect, SqlCatalog};
use asap_frontend_sql::lower_sql_dialect;
use asap_types::ir::properties::AccuracyTarget;
use asap_types::ir::schema::{DataType, Field, Schema};
use asap_types::workload::SqlDialect;

fn col(name: &str, dtype: DataType) -> Field {
Field::plain(name, dtype, false)
}

fn packets_catalog() -> SqlCatalog {
SqlCatalog::new().with_table(
"packets",
Schema::new(vec![
col("srcip", DataType::Utf8),
col("dstip", DataType::Utf8),
col("srcport", DataType::Int64),
col("dstport", DataType::Int64),
col("proto", DataType::Utf8),
col("time", DataType::Float64),
col("pkt_len", DataType::Int64),
]),
)
}

fn bgp_catalog() -> SqlCatalog {
let updates = Schema::new(vec![
col("timestamp", DataType::Timestamp),
col("peer_asn", DataType::Int64),
col("prefix", DataType::Utf8),
]);
let rib = Schema::new(vec![
col("snapshot_ts", DataType::Timestamp),
col("collector", DataType::Utf8),
col("prefix", DataType::Utf8),
]);
SqlCatalog::new()
.with_table("bgp_updates", updates)
.with_table("bgp_rib_state", rib)
}

#[tokio::main]
async fn main() {
let promql_examples: &[(&str, &str)] = &[
Expand Down Expand Up @@ -77,7 +42,7 @@ async fn main() {
println!();
}

let packets = packets_catalog();
let packets = dqc_catalog();
let bgp = bgp_catalog();
let sql_examples: &[(&str, &str, &str)] = &[
("Filter + Scan", "packets", "SELECT * FROM packets WHERE proto = 'tcp'"),
Expand Down
90 changes: 4 additions & 86 deletions crates/devtools/src/bin/analyze_corpora.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
// Corpus mode dumps all four PromQL corpora as JSONL and writes a heuristic
// anomaly report. The default mode remains the ad-hoc SQL/PromQL inspector.

use asap_devtools::corpora::{
bgp_catalog, dqc_catalog, netflow_catalog, promql_lines, sql_statements,
};
use asap_devtools::{lower_promql_with_sample_interval, SqlCatalog};
use asap_frontend_sql::lower_sql_dialect;
use asap_types::ir::properties::AccuracyTarget;
use asap_types::ir::schema::{DataType, Field, Schema};
use asap_types::workload::SqlDialect;
use serde::Serialize;
use serde_json::Value;
Expand All @@ -29,82 +31,6 @@ const NETFLOW: &str = include_str!("../../../frontend-sql/tests/netflow/data/net
const BGP: &str = include_str!("../../../frontend-sql/tests/bgp_analytics/data/bgp_analytics.sql");
const BGP_WORKLOAD: &str = include_str!("../../../frontend-sql/tests/bgp_jan2024_workload/data/bgp_jan2024_rrc00_200_query_workload.yaml");

fn col(name: &str, dtype: DataType) -> Field {
Field::plain(name, dtype, false)
}

fn dqc_catalog() -> SqlCatalog {
SqlCatalog::new().with_table(
"packets",
Schema::new(vec![
col("srcip", DataType::Utf8),
col("dstip", DataType::Utf8),
col("srcport", DataType::Int64),
col("dstport", DataType::Int64),
col("proto", DataType::Utf8),
col("time", DataType::Float64),
col("pkt_len", DataType::Int64),
]),
)
}

fn netflow_catalog() -> SqlCatalog {
SqlCatalog::new().with_table(
"netflow_table",
Schema::with_time_index(
vec![
col("time", DataType::Timestamp),
col("srcip", DataType::Utf8),
col("dstip", DataType::Utf8),
col("srcport", DataType::Int64),
col("dstport", DataType::Int64),
col("proto", DataType::Utf8),
col("pkt_len", DataType::Int64),
],
0,
vec![],
),
)
}

fn bgp_catalog() -> SqlCatalog {
let updates = Schema::new(vec![
col("timestamp", DataType::Timestamp),
col("collector", DataType::Utf8),
col("peer_ip", DataType::Utf8),
col("peer_asn", DataType::Int64),
col("prefix", DataType::Utf8),
col("operation", DataType::Utf8),
col("as_path", DataType::Utf8),
col("origin", DataType::Utf8),
col("next_hop", DataType::Utf8),
col("local_pref", DataType::Utf8),
col("med", DataType::Utf8),
col("communities", DataType::Utf8),
col("atomic", DataType::Utf8),
col("aggr_asn", DataType::Utf8),
col("aggr_ip", DataType::Utf8),
col("source_file", DataType::Utf8),
]);
SqlCatalog::new()
.with_table("bgp_updates", updates.clone())
.with_table("bgp.bgp_updates", updates)
}

fn sql_statements(source: &str) -> Vec<String> {
source
.lines()
.map(str::trim)
.filter(|line| !line.is_empty() && !line.starts_with('#') && !line.starts_with("--"))
.collect::<Vec<_>>()
.join("\n")
.split(';')
.map(str::trim)
.filter(|query| !query.is_empty())
.map(str::to_string)
.collect()
}

#[derive(serde::Deserialize)]
struct Workload {
queries: Vec<WorkloadQuery>,
Expand All @@ -115,14 +41,6 @@ struct WorkloadQuery {
sql: String,
}

fn corpus_lines(corpus: &str) -> Vec<&str> {
corpus
.lines()
.map(str::trim)
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.collect()
}

#[derive(Serialize)]
struct DumpRecord {
corpus: String,
Expand Down Expand Up @@ -203,7 +121,7 @@ fn structural_shape(expression: &str) -> String {

fn run_corpus(name: &str, source: &str, interval_ms: u64) -> CorpusResult {
let mut result = CorpusResult::default();
for (index, expression) in corpus_lines(source).into_iter().enumerate() {
for (index, expression) in promql_lines(source).enumerate() {
let normalized_expression = normalize(expression);
let structural_shape = structural_shape(expression);
match lower_promql_with_sample_interval(expression, AccuracyTarget::exact(), interval_ms) {
Expand Down
109 changes: 6 additions & 103 deletions crates/devtools/src/bin/sketch_coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,103 +13,20 @@
// every corpus lowers with. Without an approximate target, Pass 1 offers no
// summary candidate.

use asap_devtools::lower_promql_with_sample_interval;
use asap_frontend_sql::{lower_sql_dialect, SqlCatalog};
use asap_devtools::corpora::{
bgp_catalog, dqc_catalog, netflow_catalog, parse_sample_interval, promql_lines, sql_statements,
};
use asap_devtools::{lower_promql_with_sample_interval, SqlCatalog};
use asap_frontend_sql::lower_sql_dialect;
use asap_logical_asap_optimization::pass1::per_computation_candidates::{
generate_per_computation_candidates, HowToComputeAggregateMeasure,
};
use asap_types::ir::properties::AccuracyTarget;
use asap_types::ir::schema::{DataType, Field, Schema};
use asap_types::ir::{OperatorNode, QueryRoot};
use asap_types::workload::SqlDialect;
use std::collections::BTreeSet;
use std::rc::Rc;

/// Line-based `#`/`--` comment stripping, then split on `;` — the shape every
/// SQL corpus test in this repo already uses (copied from `variant_coverage`
/// so both tools walk the exact same corpus text).
fn sql_stmts(corpus: &str) -> Vec<String> {
let sql: String = corpus
.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with("--") && !l.starts_with('#'))
.collect::<Vec<_>>()
.join("\n");
sql.split(';')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect()
}

fn promql_lines(corpus: &str) -> impl Iterator<Item = &str> {
corpus
.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with('#'))
}

fn col(name: &str, dtype: DataType) -> Field {
Field::plain(name, dtype, false)
}

fn dqc_catalog() -> SqlCatalog {
SqlCatalog::new().with_table(
"packets",
Schema::new(vec![
col("srcip", DataType::Utf8),
col("dstip", DataType::Utf8),
col("srcport", DataType::Int64),
col("dstport", DataType::Int64),
col("proto", DataType::Utf8),
col("time", DataType::Float64),
col("pkt_len", DataType::Int64),
]),
)
}

fn netflow_catalog() -> SqlCatalog {
SqlCatalog::new().with_table(
"netflow_table",
Schema::with_time_index(
vec![
col("time", DataType::Timestamp),
col("srcip", DataType::Utf8),
col("dstip", DataType::Utf8),
col("srcport", DataType::Int64),
col("dstport", DataType::Int64),
col("proto", DataType::Utf8),
col("pkt_len", DataType::Int64),
],
0,
vec![],
),
)
}

fn bgp_catalog() -> SqlCatalog {
let updates = Schema::new(vec![
col("timestamp", DataType::Timestamp),
col("collector", DataType::Utf8),
col("peer_ip", DataType::Utf8),
col("peer_asn", DataType::Int64),
col("prefix", DataType::Utf8),
col("operation", DataType::Utf8),
col("as_path", DataType::Utf8),
]);
let rib = Schema::new(vec![
col("snapshot_ts", DataType::Timestamp),
col("collector", DataType::Utf8),
col("peer_ip", DataType::Utf8),
col("peer_asn", DataType::Int64),
col("prefix", DataType::Utf8),
]);
SqlCatalog::new()
.with_table("bgp_updates", updates.clone())
.with_table("bgp.bgp_updates", updates)
.with_table("bgp_rib_state", rib.clone())
.with_table("bgp.bgp_rib_state", rib)
}

struct CorpusCoverage {
name: &'static str,
lowered: usize,
Expand Down Expand Up @@ -203,20 +120,6 @@ fn parse_max_error() -> f64 {
0.01
}

fn parse_sample_interval() -> u64 {
let mut args = std::env::args().skip(1);
while let Some(arg) = args.next() {
if arg == "--sample-interval-ms" {
return args
.next()
.expect("--sample-interval-ms requires a value")
.parse()
.expect("--sample-interval-ms must be an unsigned integer");
}
}
panic!("--sample-interval-ms is required")
}

#[tokio::main]
async fn main() {
let max_error = parse_max_error();
Expand Down Expand Up @@ -287,7 +190,7 @@ async fn main() {
let catalog = catalog_fn();
let mut roots = Vec::new();
let mut failed = 0;
for (i, q) in sql_stmts(corpus).into_iter().enumerate() {
for (i, q) in sql_statements(corpus).into_iter().enumerate() {
match lower_sql_dialect(&q, &catalog, dialect.clone(), accuracy.clone()).await {
Ok(qe) => roots.push((format!("q{i}"), qe)),
Err(_) => failed += 1,
Expand Down
Loading
Loading