Skip to content

Commit 70a62a9

Browse files
committed
Update benchmark results and improve code clarity in various modules
1 parent e7a9db8 commit 70a62a9

11 files changed

Lines changed: 73 additions & 57 deletions

File tree

README.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,23 +128,26 @@ current performance guarantee.
128128
## Representative benchmark results
129129

130130
The versioned [result-analysis package](./data/result-analysis/) contains the
131-
CSV summaries and figures behind the following comparison with Oxigraph. The
132-
historical-access values are mean ± standard deviation; the storage values are
133-
medians from 35 iterations. They describe the included workloads and should
134-
not be interpreted as a general-purpose database benchmark.
135-
136-
| Workload | Janus | Oxigraph | Relative result |
137-
| --- | ---: | ---: | --- |
138-
| Point lookup, 1M quads | 0.068 ± 0.004 ms | 818.002 ± 8.683 ms | 12,029× lower mean latency |
139-
| Fixed 60-second range, 1M quads | 1.247 ± 0.060 ms | 845.388 ± 6.130 ms | 678× lower mean latency |
140-
| 50% historical range, 1M quads | 541.342 ± 6.438 ms | 1,125.296 ± 5.510 ms | 2.08× lower mean latency |
141-
| Full historical range, 1M quads | 1,075.730 ± 2.685 ms | 1,454.357 ± 8.035 ms | 1.35× lower mean latency |
142-
| Persistent footprint, 1M events | 23.14 MB | 302.83 MB | 13.1× smaller median footprint |
143-
| Storage ingestion, 1M events | 1.06M events/s | 0.121M events/s | 8.8× higher median throughput |
144-
145-
See the [historical-access CSV](./data/result-analysis/historical_access_latency_parsed.csv),
146-
[storage-footprint CSV](./data/result-analysis/storage_footprint_summary.csv),
147-
and the accompanying [historical-access figure](./data/result-analysis/historical_access_latency_5panel_shared_yaxis.png).
131+
figures for the included Janus/Oxigraph workloads. They are workload- and
132+
machine-dependent, not general-purpose database guarantees.
133+
134+
### Historical access latency
135+
136+
![Historical access latency comparison](./data/result-analysis/historical_access_latency_5panel_shared_yaxis.png)
137+
138+
### Storage footprint
139+
140+
![Storage footprint comparison](./data/result-analysis/resource_storage_footprint_combined.png)
141+
142+
### Memory and CPU
143+
144+
![Median memory and CPU comparison](./data/result-analysis/memory_cpu_1m_median_side_by_side.png)
145+
146+
![Peak memory comparison](./data/result-analysis/peak_memory_1m_lineplot.png)
147+
148+
![Median peak memory comparison](./data/result-analysis/peak_memory_1m_median_lineplot.png)
149+
150+
![Compact median peak memory comparison](./data/result-analysis/peak_memory_1m_median_lineplot_compact.png)
148151

149152
## Development
150153

benches/historical_fixed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ fn setup(n: usize) -> (Arc<StreamingSegmentedStorage>, WindowDefinition) {
1717
populate_storage(&storage, n, 1_000, 1, GRAPH_URI);
1818
let window = WindowDefinition {
1919
window_name: "w".to_string(),
20-
source_kind: SourceKind::Stream,
21-
stream_name: GRAPH_URI.to_string(),
20+
source_kind: SourceKind::Log,
21+
source_name: GRAPH_URI.to_string(),
2222
width: n as u64,
2323
slide: n as u64,
2424
offset: None,

benches/historical_sliding.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ fn setup(n: usize) -> (Arc<StreamingSegmentedStorage>, WindowDefinition) {
2626
populate_storage(&storage, n, start_ts, step_ms, GRAPH_URI);
2727
let window = WindowDefinition {
2828
window_name: "w".to_string(),
29-
source_kind: SourceKind::Stream,
30-
stream_name: GRAPH_URI.to_string(),
29+
source_kind: SourceKind::Log,
30+
source_name: GRAPH_URI.to_string(),
3131
width: RANGE_MS,
3232
slide: SLIDE_MS,
3333
offset: Some(OFFSET_MS),

src/bin/hybrid_scaling_combined.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::too_many_arguments)]
2+
13
use clap::Parser;
24
use janus::core::RDFEvent;
35
use janus::execution::result_converter::parse_rsprs_binding_string;
@@ -393,9 +395,10 @@ fn normalize_binding_term(raw: &str) -> String {
393395
return without_prefix[..end].to_string();
394396
}
395397
}
396-
if trimmed.starts_with('<') && trimmed.ends_with('>') && trimmed.len() > 2 {
397-
trimmed[1..trimmed.len() - 1].to_string()
398-
} else if trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() > 2 {
398+
if ((trimmed.starts_with('<') && trimmed.ends_with('>'))
399+
|| (trimmed.starts_with('"') && trimmed.ends_with('"')))
400+
&& trimmed.len() > 2
401+
{
399402
trimmed[1..trimmed.len() - 1].to_string()
400403
} else {
401404
trimmed.to_string()
@@ -750,7 +753,11 @@ fn congestion_value_for_historical(index: usize) -> f64 {
750753
fn congestion_value_for_live(index: usize) -> f64 {
751754
let sensor_idx = index % SENSOR_COUNT;
752755
let sample_idx = index / SENSOR_COUNT;
753-
let bias = if sensor_idx % 2 == 0 { 8.0 } else { -8.0 };
756+
let bias = if sensor_idx.is_multiple_of(2) {
757+
8.0
758+
} else {
759+
-8.0
760+
};
754761
let oscillation = ((sample_idx * 5 + sensor_idx) % 5) as f64 - 2.0;
755762
historical_sensor_base(sensor_idx) + bias + oscillation
756763
}
@@ -824,14 +831,14 @@ fn safe_takeaway_label(system: &str, query_type: &str) -> &'static str {
824831
fn format_size_label(size: usize) -> String {
825832
match size {
826833
1_000_000 => "1M quads".to_string(),
827-
1_000..=999_999 if size % 1_000 == 0 => format!("{}k quads", size / 1_000),
834+
1_000..=999_999 if size.is_multiple_of(1_000) => format!("{}k quads", size / 1_000),
828835
_ => format!("{size} quads"),
829836
}
830837
}
831838

832-
fn find_first_baseline_definition<'a>(
833-
parsed: &'a ParsedJanusQuery,
834-
) -> Result<(&'a BaselineDefinition, &'a BaselineGraphTemplate), Box<dyn std::error::Error>> {
839+
fn find_first_baseline_definition(
840+
parsed: &ParsedJanusQuery,
841+
) -> Result<(&BaselineDefinition, &BaselineGraphTemplate), Box<dyn std::error::Error>> {
835842
let definition = parsed
836843
.ast
837844
.baseline_definitions
@@ -1040,10 +1047,11 @@ fn run_janus_unified(
10401047
first_hybrid_result_ms = Some(*received_at);
10411048
window_processing_overhead_ms = Some(*overhead);
10421049
}
1043-
} else if slides.len() >= 2 && res.timestamp_to == slides[1] {
1044-
if main_window_result_ms.is_none() {
1045-
main_window_result_ms = Some(*received_at);
1046-
}
1050+
} else if slides.len() >= 2
1051+
&& res.timestamp_to == slides[1]
1052+
&& main_window_result_ms.is_none()
1053+
{
1054+
main_window_result_ms = Some(*received_at);
10471055
}
10481056
}
10491057

@@ -1172,12 +1180,12 @@ fn run_decomposed_oxigraph(
11721180
{
11731181
Term::NamedNode(NamedNode::new(&event.object)?)
11741182
} else {
1175-
let literal = if let Ok(_) = event.object.parse::<f64>() {
1183+
let literal = if event.object.parse::<f64>().is_ok() {
11761184
oxigraph::model::Literal::new_typed_literal(
11771185
&event.object,
11781186
NamedNode::new("http://www.w3.org/2001/XMLSchema#decimal").unwrap(),
11791187
)
1180-
} else if let Ok(_) = event.object.parse::<i64>() {
1188+
} else if event.object.parse::<i64>().is_ok() {
11811189
oxigraph::model::Literal::new_typed_literal(
11821190
&event.object,
11831191
NamedNode::new("http://www.w3.org/2001/XMLSchema#integer").unwrap(),
@@ -1192,7 +1200,7 @@ fn run_decomposed_oxigraph(
11921200
// Quad 2: Event timestamp in Default Graph
11931201
let event_node = NamedNode::new(&event_graph_uri)?;
11941202
let ts_literal = Term::Literal(oxigraph::model::Literal::new_typed_literal(
1195-
&event.timestamp.to_string(),
1203+
event.timestamp.to_string(),
11961204
NamedNode::new("http://www.w3.org/2001/XMLSchema#integer").unwrap(),
11971205
));
11981206
store.insert(&Quad::new(
@@ -1221,7 +1229,7 @@ fn run_decomposed_oxigraph(
12211229
let evaluator = build_evaluator();
12221230
let parsed_query = evaluator
12231231
.parse_query(&sparql_query)
1224-
.map_err(|e| oxigraph::sparql::QueryEvaluationError::from(e))?;
1232+
.map_err(oxigraph::sparql::QueryEvaluationError::from)?;
12251233
let results = parsed_query.on_store(&store).execute()?;
12261234

12271235
let mut external_bindings = Vec::new();
@@ -1341,10 +1349,11 @@ fn run_decomposed_oxigraph(
13411349
window_processing_overhead_ms = Some(*overhead);
13421350
external_merge_ms_total = Some(*merge_ms);
13431351
}
1344-
} else if slides.len() >= 2 && res.timestamp_to == slides[1] {
1345-
if main_window_result_ms.is_none() {
1346-
main_window_result_ms = Some(*received_at + *merge_ms);
1347-
}
1352+
} else if slides.len() >= 2
1353+
&& res.timestamp_to == slides[1]
1354+
&& main_window_result_ms.is_none()
1355+
{
1356+
main_window_result_ms = Some(*received_at + *merge_ms);
13481357
}
13491358
}
13501359

@@ -1429,7 +1438,7 @@ fn write_reports(
14291438
let mut query_types = rows.iter().map(|r| r.historical_query_type.clone()).collect::<Vec<_>>();
14301439
query_types.sort_unstable();
14311440
query_types.dedup();
1432-
let preferred_order = vec![
1441+
let preferred_order = [
14331442
"point_lookup".to_string(),
14341443
"fixed_60s".to_string(),
14351444
"range_10_percent".to_string(),

src/execution/historical_executor.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,7 @@ impl<'a> Iterator for SlidingWindowIterator<'a> {
435435

436436
fn next(&mut self) -> Option<Self::Item> {
437437
let window_start = self.current_start;
438-
let window_end = match window_start.checked_add(self.width) {
439-
Some(window_end) => window_end,
440-
None => return None,
441-
};
438+
let window_end = window_start.checked_add(self.width)?;
442439

443440
if window_end > self.evaluation_time {
444441
return None;

src/paper_bench/harness/data_gen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,5 @@ fn congestion_value_for_live(index: usize) -> f64 {
209209
}
210210

211211
fn historical_end_timestamp(start_ts: u64, events: usize) -> u64 {
212-
start_ts + events.saturating_sub(1) as u64 * HISTORICAL_INTERVAL_MS
212+
start_ts + events.max(1) as u64 * HISTORICAL_INTERVAL_MS
213213
}

src/paper_bench/harness/helpers.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::implicit_hasher)]
2+
13
use super::types::{
24
SustainedRunConfig, TimeMode, BASELINE_NS, CONGESTION_PREDICATE, GRAPH_URI, LIVE_STREAM_URI,
35
};
@@ -213,20 +215,19 @@ pub fn hybrid_query(start_ts: u64, end_ts: u64) -> String {
213215
}
214216

215217
pub fn historical_baseline_sparql_query() -> Result<String, Box<dyn std::error::Error>> {
216-
Ok(format!(
217-
r#"
218+
Ok(r#"
218219
PREFIX ex: <http://example.org/>
219220
220221
SELECT ?sensor
221222
(AVG(?historicalCongestion) AS ?historicalAvgCongestion)
222-
WHERE {{
223-
GRAPH ex:citybench {{
223+
WHERE {
224+
GRAPH ex:citybench {
224225
?sensor ex:congestionLevel ?historicalCongestion .
225-
}}
226-
}}
226+
}
227+
}
227228
GROUP BY ?sensor
228229
"#
229-
))
230+
.to_string())
230231
}
231232

232233
pub fn live_only_rspql() -> String {

src/paper_bench/query_defined_baseline/rdf.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::implicit_hasher)]
2+
13
use oxigraph::model::{BlankNode, GraphName, NamedNode, NamedOrBlankNode, Quad, Term};
24
use std::collections::{HashMap, HashSet};
35

src/paper_bench/query_defined_baseline/validation.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::implicit_hasher)]
2+
13
use std::collections::{BTreeMap, HashMap};
24

35
use super::rdf::{normalize_binding_term, parse_numeric};

src/paper_bench/storage_footprint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ fn median(values: &[f64]) -> f64 {
690690
sorted.sort_by(f64::total_cmp);
691691
let mid = sorted.len() / 2;
692692
if sorted.len() % 2 == 0 {
693-
(sorted[mid - 1] + sorted[mid]) / 2.0
693+
f64::midpoint(sorted[mid - 1], sorted[mid])
694694
} else {
695695
sorted[mid]
696696
}

0 commit comments

Comments
 (0)