mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 06:16:59 +08:00
feat(y-octo): import y-octo monorepo (#11750)
This commit is contained in:
134
packages/common/y-octo/utils/bin/bench_result_render.rs
Normal file
134
packages/common/y-octo/utils/bin/bench_result_render.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{self, BufRead},
|
||||
};
|
||||
|
||||
fn process_duration(duration: &str) -> Option<(f64, f64)> {
|
||||
let dur_split: Vec<String> = duration.split('±').map(String::from).collect();
|
||||
if dur_split.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let units = dur_split[1]
|
||||
.chars()
|
||||
.skip_while(|c| c.is_ascii_digit())
|
||||
.collect::<String>();
|
||||
let dur_secs = dur_split[0].parse::<f64>().ok()?;
|
||||
let error_secs = dur_split[1]
|
||||
.chars()
|
||||
.take_while(|c| c.is_ascii_digit())
|
||||
.collect::<String>()
|
||||
.parse::<f64>()
|
||||
.ok()?;
|
||||
Some((
|
||||
convert_dur_to_seconds(dur_secs, &units),
|
||||
convert_dur_to_seconds(error_secs, &units),
|
||||
))
|
||||
}
|
||||
|
||||
fn convert_dur_to_seconds(dur: f64, units: &str) -> f64 {
|
||||
let factors: HashMap<_, _> = [
|
||||
("s", 1.0),
|
||||
("ms", 1.0 / 1000.0),
|
||||
("µs", 1.0 / 1_000_000.0),
|
||||
("ns", 1.0 / 1_000_000_000.0),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
dur * factors.get(units).unwrap_or(&1.0)
|
||||
}
|
||||
|
||||
fn is_significant(changes_dur: f64, changes_err: f64, base_dur: f64, base_err: f64) -> bool {
|
||||
if changes_dur < base_dur {
|
||||
changes_dur + changes_err < base_dur || base_dur - base_err > changes_dur
|
||||
} else {
|
||||
changes_dur - changes_err > base_dur || base_dur + base_err < changes_dur
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_to_markdown() -> impl Iterator<Item = String> {
|
||||
#[cfg(feature = "bench")]
|
||||
let re = regex::Regex::new(r"\s{2,}").unwrap();
|
||||
io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.skip(2)
|
||||
.flat_map(move |row| {
|
||||
if let Ok(_row) = row {
|
||||
let columns = {
|
||||
#[cfg(feature = "bench")]
|
||||
{
|
||||
re.split(&_row).collect::<Vec<_>>()
|
||||
}
|
||||
#[cfg(not(feature = "bench"))]
|
||||
Vec::<&str>::new()
|
||||
};
|
||||
let name = columns.first()?;
|
||||
let base_duration = columns.get(2)?;
|
||||
let changes_duration = columns.get(5)?;
|
||||
Some((
|
||||
name.to_string(),
|
||||
base_duration.to_string(),
|
||||
changes_duration.to_string(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flat_map(|(name, base_duration, changes_duration)| {
|
||||
let mut difference = "N/A".to_string();
|
||||
let base_undefined = base_duration == "?";
|
||||
let changes_undefined = changes_duration == "?";
|
||||
|
||||
if !base_undefined && !changes_undefined {
|
||||
let (base_dur_secs, base_err_secs) = process_duration(&base_duration)?;
|
||||
let (changes_dur_secs, changes_err_secs) = process_duration(&changes_duration)?;
|
||||
|
||||
let diff = -(1.0 - changes_dur_secs / base_dur_secs) * 100.0;
|
||||
difference = format!("{:+.2}%", diff);
|
||||
|
||||
if is_significant(
|
||||
changes_dur_secs,
|
||||
changes_err_secs,
|
||||
base_dur_secs,
|
||||
base_err_secs,
|
||||
) {
|
||||
difference = format!("**{}**", difference);
|
||||
}
|
||||
}
|
||||
|
||||
Some(format!(
|
||||
"| {} | {} | {} | {} |",
|
||||
name.replace('|', "\\|"),
|
||||
if base_undefined {
|
||||
"N/A"
|
||||
} else {
|
||||
&base_duration
|
||||
},
|
||||
if changes_undefined {
|
||||
"N/A"
|
||||
} else {
|
||||
&changes_duration
|
||||
},
|
||||
difference
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let platform = std::env::args().nth(1).expect("Missing platform argument");
|
||||
|
||||
let headers = vec![
|
||||
format!("## Benchmark for {}", platform),
|
||||
"<details>".to_string(),
|
||||
" <summary>Click to view benchmark</summary>".to_string(),
|
||||
"".to_string(),
|
||||
"| Test | Base | PR | % |".to_string(),
|
||||
"| --- | --- | --- | --- |".to_string(),
|
||||
];
|
||||
|
||||
for line in headers.into_iter().chain(convert_to_markdown()) {
|
||||
println!("{}", line);
|
||||
}
|
||||
println!("</details>");
|
||||
}
|
||||
100
packages/common/y-octo/utils/bin/doc_merger.rs
Normal file
100
packages/common/y-octo/utils/bin/doc_merger.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::{
|
||||
fs::read,
|
||||
io::{Error, ErrorKind},
|
||||
path::PathBuf,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use y_octo::Doc;
|
||||
|
||||
/// ybinary merger
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Path of the ybinary to read
|
||||
#[arg(short, long)]
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn load_path(path: &str) -> Result<Vec<Vec<u8>>, Error> {
|
||||
let path = PathBuf::from(path);
|
||||
if path.is_dir() {
|
||||
let mut updates = Vec::new();
|
||||
let mut paths = path
|
||||
.read_dir()?
|
||||
.filter_map(|entry| {
|
||||
let entry = entry.ok()?;
|
||||
if entry.path().is_file() {
|
||||
Some(entry.path())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
paths.sort();
|
||||
|
||||
for path in paths {
|
||||
println!("read {:?}", path);
|
||||
updates.push(read(path)?);
|
||||
}
|
||||
Ok(updates)
|
||||
} else if path.is_file() {
|
||||
Ok(vec![read(path)?])
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::NotFound, "not a file or directory"))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
jwst_merge(&args.path);
|
||||
}
|
||||
|
||||
fn jwst_merge(path: &str) {
|
||||
let updates = load_path(path).unwrap();
|
||||
|
||||
let mut doc = Doc::default();
|
||||
for (i, update) in updates.iter().enumerate() {
|
||||
println!("apply update{i} {} bytes", update.len());
|
||||
doc.apply_update_from_binary_v1(update.clone()).unwrap();
|
||||
}
|
||||
|
||||
println!("press enter to continue");
|
||||
std::io::stdin().read_line(&mut String::new()).unwrap();
|
||||
let ts = Instant::now();
|
||||
let history = doc.history().parse_store(Default::default());
|
||||
println!("history: {:?}", ts.elapsed());
|
||||
for history in history.iter().take(100) {
|
||||
println!("history: {:?}", history);
|
||||
}
|
||||
|
||||
doc.gc().unwrap();
|
||||
|
||||
let binary = {
|
||||
let binary = doc.encode_update_v1().unwrap();
|
||||
|
||||
println!("merged {} bytes", binary.len());
|
||||
|
||||
binary
|
||||
};
|
||||
|
||||
{
|
||||
let mut doc = Doc::default();
|
||||
doc.apply_update_from_binary_v1(binary.clone()).unwrap();
|
||||
let new_binary = doc.encode_update_v1().unwrap();
|
||||
|
||||
println!("re-encoded {} bytes", new_binary.len(),);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ignore = "only for debug"]
|
||||
fn test_gc() {
|
||||
jwst_merge("/Users/ds/Downloads/out");
|
||||
}
|
||||
}
|
||||
79
packages/common/y-octo/utils/bin/memory_leak_test.rs
Normal file
79
packages/common/y-octo/utils/bin/memory_leak_test.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use y_octo::*;
|
||||
|
||||
fn run_text_test(seed: u64) {
|
||||
let doc = Doc::with_client(1);
|
||||
let mut rand = ChaCha20Rng::seed_from_u64(seed);
|
||||
let mut text = doc.get_or_create_text("test").unwrap();
|
||||
text.insert(0, "This is a string with length 32.").unwrap();
|
||||
|
||||
let iteration = 20;
|
||||
let mut len = 32;
|
||||
|
||||
for i in 0..iteration {
|
||||
let mut text = text.clone();
|
||||
let ins = i % 2 == 0;
|
||||
let pos = rand.random_range(0..if ins { text.len() } else { len / 2 });
|
||||
if ins {
|
||||
let str = format!("hello {i}");
|
||||
text.insert(pos, &str).unwrap();
|
||||
len += str.len() as u64;
|
||||
} else {
|
||||
text.remove(pos, 6).unwrap();
|
||||
len -= 6;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(text.to_string().len(), len as usize);
|
||||
assert_eq!(text.len(), len);
|
||||
}
|
||||
|
||||
fn run_array_test(seed: u64) {
|
||||
let doc = Doc::with_client(1);
|
||||
let mut rand = ChaCha20Rng::seed_from_u64(seed);
|
||||
let mut array = doc.get_or_create_array("test").unwrap();
|
||||
array.push(1).unwrap();
|
||||
|
||||
let iteration = 20;
|
||||
let mut len = 1;
|
||||
|
||||
for i in 0..iteration {
|
||||
let mut array = array.clone();
|
||||
let ins = i % 2 == 0;
|
||||
let pos = rand.random_range(0..if ins { array.len() } else { len / 2 });
|
||||
if ins {
|
||||
array.insert(pos, 1).unwrap();
|
||||
len += 1;
|
||||
} else {
|
||||
array.remove(pos, 1).unwrap();
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(array.len(), len);
|
||||
}
|
||||
|
||||
fn run_map_test() {
|
||||
let base_text = "test1 test2 test3 test4 test5 test6 test7 test8 test9"
|
||||
.split(' ')
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let doc = Doc::default();
|
||||
let mut map = doc.get_or_create_map("test").unwrap();
|
||||
for (idx, key) in base_text.iter().enumerate() {
|
||||
map.insert(key.to_string(), idx).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut rand = ChaCha20Rng::seed_from_u64(rand::rng().random());
|
||||
for _ in 0..10000 {
|
||||
let seed = rand.random();
|
||||
run_array_test(seed);
|
||||
run_text_test(seed);
|
||||
run_map_test();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user