Skip to main content

large_data_retention_benchmark/
large_data_retention_benchmark.rs

1use std::time::Instant;
2
3use zirium::{
4    dialect::DialectRegistry,
5    parser::ParsedFile,
6    semantic::{LoweringMode, RetentionProfile, lower_with_dialect_registry_and_retention},
7};
8
9fn source(elements: usize) -> Vec<u8> {
10    let mut dense = String::from("dense<[");
11    for index in 0..elements {
12        if index != 0 {
13            dense.push_str(", ");
14        }
15        dense.push_str(&(index % 10).to_string());
16    }
17    dense.push_str("]> : tensor<");
18    dense.push_str(&elements.to_string());
19    dense.push_str("xi8>");
20
21    let mut sparse_indices = String::from("[");
22    let mut sparse_values = String::from("[");
23    for index in 0..elements {
24        if index != 0 {
25            sparse_indices.push_str(", ");
26            sparse_values.push_str(", ");
27        }
28        sparse_indices.push_str(&format!("[{index}, 0]"));
29        sparse_values.push_str(&(index % 10).to_string());
30    }
31    sparse_indices.push(']');
32    sparse_values.push(']');
33
34    let opaque = "#vendor.attr<{ note = \"body\" }>";
35    format!(
36        "\"bench.payload\"() {{dense_value = {dense}, sparse_value = sparse<{sparse_indices}, {sparse_values}> : tensor<{elements}x1xi8>, resource_value = dense_resource<resource_handle> : tensor<1xi8>, wide_value = 0x1234567890abcdef : i128, opaque_value = {opaque} }} : () -> ()\n"
37    )
38    .into_bytes()
39}
40
41#[derive(Debug)]
42struct Measurement {
43    source_bytes: usize,
44    semantic_attributes: usize,
45    payload_bytes: usize,
46    payload_blobs: usize,
47    cst_nodes: usize,
48    mappings: usize,
49    direct_owned_bytes: usize,
50    document_index_bytes: usize,
51    retained_cst_bytes: usize,
52    source_shared: bool,
53    cst_shared: bool,
54    lower_us: u128,
55}
56
57fn measure(elements: usize, profile: RetentionProfile) -> Measurement {
58    let bytes = source(elements);
59    let source_len = bytes.len();
60    let parsed = ParsedFile::parse(bytes).expect("benchmark input parses");
61    let started = Instant::now();
62    let result = lower_with_dialect_registry_and_retention(
63        &parsed,
64        LoweringMode::Strict,
65        profile,
66        &DialectRegistry::EMPTY,
67    );
68    assert!(result.diagnostics.is_empty(), "{:?}", result.diagnostics);
69    let document = result.document.expect("benchmark input lowers");
70    document.validate().expect("benchmark document validates");
71    let stats = document.statistics();
72    assert_eq!(document.retention_profile(), profile);
73    assert_eq!(
74        stats.retained_source_bytes,
75        match profile {
76            RetentionProfile::SemanticOnly => 0,
77            RetentionProfile::SyntaxOnly | RetentionProfile::Hybrid => source_len,
78        }
79    );
80    assert_eq!(
81        stats.retained_cst_nodes > 0,
82        profile != RetentionProfile::SemanticOnly
83    );
84    assert_eq!(
85        stats.retained_mapping_entries,
86        match profile {
87            RetentionProfile::Hybrid => 1,
88            RetentionProfile::SyntaxOnly | RetentionProfile::SemanticOnly => 0,
89        }
90    );
91    Measurement {
92        source_bytes: source_len,
93        semantic_attributes: stats.local_attributes,
94        payload_bytes: stats.payload_blob_bytes,
95        payload_blobs: stats.payload_blobs,
96        cst_nodes: stats.retained_cst_nodes,
97        mappings: stats.retained_mapping_entries,
98        direct_owned_bytes: stats.direct_owned_bytes,
99        document_index_bytes: stats.document_index_bytes,
100        retained_cst_bytes: stats.retained_cst_bytes,
101        source_shared: stats.source_storage_shared,
102        cst_shared: stats.cst_storage_shared,
103        lower_us: started.elapsed().as_micros(),
104    }
105}
106
107fn main() {
108    let small = [
109        measure(100, RetentionProfile::SyntaxOnly),
110        measure(100, RetentionProfile::SemanticOnly),
111        measure(100, RetentionProfile::Hybrid),
112    ];
113    let large = [
114        measure(10_000, RetentionProfile::SyntaxOnly),
115        measure(10_000, RetentionProfile::SemanticOnly),
116        measure(10_000, RetentionProfile::Hybrid),
117    ];
118    for (small, large) in small.iter().zip(large.iter()) {
119        assert_eq!(small.semantic_attributes, large.semantic_attributes);
120        assert_eq!(small.payload_blobs, large.payload_blobs);
121        assert!(large.payload_bytes > small.payload_bytes * 50);
122    }
123    assert_eq!(small[0].cst_nodes, large[0].cst_nodes);
124    assert_eq!(small[2].mappings, 1);
125    assert_eq!(large[2].mappings, 1);
126
127    println!(
128        "elements,profile,source_bytes,semantic_attributes,payload_blobs,payload_bytes,cst_nodes,mappings,direct_owned_bytes,document_index_bytes,retained_cst_bytes,source_shared,cst_shared,lower_us"
129    );
130    for (elements, measurements) in [(100, &small), (10_000, &large)] {
131        for (profile, measurement) in [
132            ("SyntaxOnly", &measurements[0]),
133            ("SemanticOnly", &measurements[1]),
134            ("Hybrid", &measurements[2]),
135        ] {
136            println!(
137                "{elements},{profile},{},{},{},{},{},{},{},{},{},{},{},{}",
138                measurement.source_bytes,
139                measurement.semantic_attributes,
140                measurement.payload_blobs,
141                measurement.payload_bytes,
142                measurement.cst_nodes,
143                measurement.mappings,
144                measurement.direct_owned_bytes,
145                measurement.document_index_bytes,
146                measurement.retained_cst_bytes,
147                measurement.source_shared,
148                measurement.cst_shared,
149                measurement.lower_us
150            );
151        }
152    }
153}