Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,323 @@
|
||||
use indexmap::IndexMap;
|
||||
|
||||
struct Lookup {
|
||||
generated: Map<i64, i64>,
|
||||
reference: IndexMap<i64, i64>,
|
||||
keys: Vec<i64>,
|
||||
}
|
||||
|
||||
struct TextLookup {
|
||||
generated: Map<String, i64>,
|
||||
reference: IndexMap<String, i64>,
|
||||
keys: Vec<String>,
|
||||
}
|
||||
|
||||
fn text_lookup_generated(values: &[TextLookup]) -> Result<i64, Fault> {
|
||||
values.first().map_or(Ok(0), |value| {
|
||||
GENERATED_TEXT_LOOKUP(&value.generated, &value.keys)
|
||||
})
|
||||
}
|
||||
|
||||
fn text_lookup_reference(values: &[TextLookup]) -> Result<i64, Fault> {
|
||||
let Some(value) = values.first() else {
|
||||
return Ok(0);
|
||||
};
|
||||
let mut total = 0i64;
|
||||
for key in &value.keys {
|
||||
total = total
|
||||
.checked_add(value.reference.get(key.as_str()).copied().unwrap_or(0))
|
||||
.ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
fn text_lookup_same_table(values: &[TextLookup]) -> Result<i64, Fault> {
|
||||
let Some(value) = values.first() else {
|
||||
return Ok(0);
|
||||
};
|
||||
let mut total = 0i64;
|
||||
for key in &value.keys {
|
||||
total = total
|
||||
.checked_add(value.generated.get(key.as_str()).copied().unwrap_or(0))
|
||||
.ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
fn text_lookup_comparisons() {
|
||||
let reference_first = match std::env::var("DEVER_BENCH_MAP_ORDER")
|
||||
.as_deref()
|
||||
.unwrap_or("dever-first")
|
||||
{
|
||||
"dever-first" => false,
|
||||
"rust-first" => true,
|
||||
order => panic!("unknown table construction order: {order}"),
|
||||
};
|
||||
for count in [512, 1024, 2048, 4096] {
|
||||
let keys: Vec<_> = (0..count)
|
||||
.map(|index| format!("lookup-key-{index}"))
|
||||
.collect();
|
||||
let (mut generated, mut reference) = if reference_first {
|
||||
let reference = IndexMap::with_capacity(count);
|
||||
(Map::with_capacity(count), reference)
|
||||
} else {
|
||||
(Map::with_capacity(count), IndexMap::with_capacity(count))
|
||||
};
|
||||
for key in &keys {
|
||||
if reference_first {
|
||||
reference.insert(key.clone(), 120);
|
||||
generated.insert(key.clone(), 120);
|
||||
} else {
|
||||
generated.insert(key.clone(), 120);
|
||||
reference.insert(key.clone(), 120);
|
||||
}
|
||||
}
|
||||
assert_eq!(
|
||||
GENERATED_TEXT_LOOKUP(&generated, &["missing".to_owned()]).unwrap(),
|
||||
0
|
||||
);
|
||||
let values = [TextLookup {
|
||||
generated,
|
||||
reference,
|
||||
keys,
|
||||
}];
|
||||
compare(
|
||||
&format!("map_text_lookup_{count}"),
|
||||
&values,
|
||||
200,
|
||||
text_lookup_generated,
|
||||
text_lookup_reference,
|
||||
|value| *value as u64,
|
||||
);
|
||||
// 同表只隔离生成层;独立 IndexMap 参照不能被这个控制组替代。
|
||||
compare_named(
|
||||
&format!("map_text_lookup_{count}_same_table"),
|
||||
&values,
|
||||
200,
|
||||
text_lookup_generated,
|
||||
text_lookup_same_table,
|
||||
|value| *value as u64,
|
||||
"rust_runtime",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn overflow() -> Fault {
|
||||
&FaultInfo {
|
||||
message: "integer overflow",
|
||||
source: "reference.dever",
|
||||
line: 1,
|
||||
column: 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_generated(values: &[Lookup]) -> Result<i64, Fault> {
|
||||
match values.first() {
|
||||
Some(value) => GENERATED_LOOKUP(&value.generated, &value.keys),
|
||||
None => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_reference(values: &[Lookup]) -> Result<i64, Fault> {
|
||||
let Some(value) = values.first() else {
|
||||
return Ok(0);
|
||||
};
|
||||
let mut answer = 0i64;
|
||||
for key in &value.keys {
|
||||
answer = answer
|
||||
.checked_add(value.reference.get(key).copied().unwrap_or(0))
|
||||
.ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(answer)
|
||||
}
|
||||
|
||||
fn lookup_same_table(values: &[Lookup]) -> Result<i64, Fault> {
|
||||
let Some(value) = values.first() else {
|
||||
return Ok(0);
|
||||
};
|
||||
let mut answer = 0i64;
|
||||
for key in &value.keys {
|
||||
answer = answer
|
||||
.checked_add(value.generated.get(key).copied().unwrap_or(0))
|
||||
.ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(answer)
|
||||
}
|
||||
|
||||
fn scan_generated(values: &[Lookup]) -> Result<i64, Fault> {
|
||||
match values.first() {
|
||||
Some(value) => GENERATED_SCAN(&value.generated),
|
||||
None => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_reference(values: &[Lookup]) -> Result<i64, Fault> {
|
||||
let Some(value) = values.first() else {
|
||||
return Ok(0);
|
||||
};
|
||||
value.reference.values().try_fold(0i64, |total, item| {
|
||||
total.checked_add(*item).ok_or_else(overflow)
|
||||
})
|
||||
}
|
||||
|
||||
fn map_generated(values: &[i64]) -> Result<Vec<(i64, i64)>, Fault> {
|
||||
GENERATED_ENTRIES(values)
|
||||
}
|
||||
|
||||
fn map_reference(values: &[i64]) -> Result<Vec<(i64, i64)>, Fault> {
|
||||
let mut result = IndexMap::new();
|
||||
for value in values {
|
||||
result.insert(*value, *value);
|
||||
}
|
||||
Ok(result.into_iter().collect())
|
||||
}
|
||||
|
||||
fn list_reference(values: &[i64]) -> Result<Vec<i64>, Fault> {
|
||||
let mut result = Vec::new();
|
||||
for value in values {
|
||||
result.push(*value);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn buffer_reference(values: &dever_runtime::Bytes) -> Result<BUFFER_STATE, Fault> {
|
||||
let mut items = Vec::new();
|
||||
let mut count = 0i64;
|
||||
for value in values.iter() {
|
||||
items.push(i64::from(*value));
|
||||
count = count.checked_add(1).ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(BUFFER_STATE {
|
||||
field0: items,
|
||||
field1: count,
|
||||
})
|
||||
}
|
||||
|
||||
fn buffer_inspect_reference(values: &dever_runtime::Bytes) -> Result<BUFFER_STATE, Fault> {
|
||||
let mut items = Vec::new();
|
||||
let mut count = 0i64;
|
||||
for value in values.iter() {
|
||||
count = (items.len() as i64).checked_add(1).ok_or_else(overflow)?;
|
||||
items.push(i64::from(*value));
|
||||
}
|
||||
Ok(BUFFER_STATE {
|
||||
field0: items,
|
||||
field1: count,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_records_reference(values: &[SCALAR_ROW]) -> Result<i64, Fault> {
|
||||
let mut total = 0i64;
|
||||
for row in values {
|
||||
let projected = row
|
||||
.field0
|
||||
.checked_add(row.field1)
|
||||
.ok_or_else(overflow)?
|
||||
.checked_add(row.field2)
|
||||
.ok_or_else(overflow)?;
|
||||
total = total.checked_add(projected).ok_or_else(overflow)?;
|
||||
}
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let values: Vec<i64> = (0..1024).collect();
|
||||
let lookup = Lookup {
|
||||
generated: GENERATED_BUILD_MAP(&values).unwrap(),
|
||||
reference: values.iter().map(|value| (*value, *value)).collect(),
|
||||
keys: (0..1024).map(|index| (index * 17) % 1152).collect(),
|
||||
};
|
||||
let lookups = [lookup];
|
||||
let overflow_case = [Lookup {
|
||||
generated: GENERATED_BUILD_MAP(&[i64::MAX, 1]).unwrap(),
|
||||
reference: [(i64::MAX, i64::MAX), (1, 1)].into_iter().collect(),
|
||||
keys: vec![i64::MAX, 1],
|
||||
}];
|
||||
assert!(scan_generated(&overflow_case).is_err());
|
||||
assert!(scan_reference(&overflow_case).is_err());
|
||||
assert!(lookup_generated(&overflow_case).is_err());
|
||||
assert!(lookup_reference(&overflow_case).is_err());
|
||||
assert_eq!(
|
||||
map_generated(&[3, 1, 3, 2]).unwrap(),
|
||||
map_reference(&[3, 1, 3, 2]).unwrap()
|
||||
);
|
||||
println!("case,sample,implementation,elapsed_ns,checksum");
|
||||
text_lookup_comparisons();
|
||||
for count in [512, 1024, 2048, 4096] {
|
||||
let bytes = dever_runtime::Bytes::from(vec![120u8; count]);
|
||||
let rows: Vec<_> = bytes
|
||||
.iter()
|
||||
.map(|value| SCALAR_ROW {
|
||||
field0: i64::from(*value),
|
||||
field1: 0,
|
||||
field2: 0,
|
||||
})
|
||||
.collect();
|
||||
compare(
|
||||
&format!("list_record_read_{count}"),
|
||||
&rows,
|
||||
1000,
|
||||
GENERATED_RECORD_READ,
|
||||
read_records_reference,
|
||||
|value| *value as u64,
|
||||
);
|
||||
compare_bytes(
|
||||
&format!("record_update_{count}"),
|
||||
&bytes,
|
||||
1000,
|
||||
GENERATED_BUFFER_BUILD,
|
||||
buffer_reference,
|
||||
|value| value.field1 as u64,
|
||||
);
|
||||
compare_bytes(
|
||||
&format!("record_inspect_{count}"),
|
||||
&bytes,
|
||||
1000,
|
||||
GENERATED_BUFFER_INSPECT,
|
||||
buffer_inspect_reference,
|
||||
|value| value.field1 as u64,
|
||||
);
|
||||
}
|
||||
compare(
|
||||
"map_lookup",
|
||||
&lookups,
|
||||
2000,
|
||||
lookup_generated,
|
||||
lookup_reference,
|
||||
|value| *value as u64,
|
||||
);
|
||||
// 同一张表隔离随机哈希布局;独立 IndexMap 参照仍保留。
|
||||
compare_named(
|
||||
"map_lookup_same_table",
|
||||
&lookups,
|
||||
2000,
|
||||
lookup_generated,
|
||||
lookup_same_table,
|
||||
|value| *value as u64,
|
||||
"rust_runtime",
|
||||
);
|
||||
compare(
|
||||
"map_scan",
|
||||
&lookups,
|
||||
20000,
|
||||
scan_generated,
|
||||
scan_reference,
|
||||
|value| *value as u64,
|
||||
);
|
||||
compare(
|
||||
"map_build",
|
||||
&values[..512],
|
||||
400,
|
||||
map_generated,
|
||||
map_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
compare(
|
||||
"list_build",
|
||||
&values,
|
||||
1000,
|
||||
GENERATED_BUILD_LIST,
|
||||
list_reference,
|
||||
|value| value.len() as u64,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user