use std::hint::black_box;
use std::time::Instant;
use mdi_core::{parse_document, serialize_mdi_document};
const HUNDRED_THOUSAND: usize = 100_000;
const MILLION: usize = 1_000_000;
const TEN_MILLION: usize = 10_000_000;
const HUNDRED_MILLION: usize = 100_000_000;
fn book_source(characters: usize) -> String {
const CHAPTER: &str =
"# 第一章\n\n吾輩は{猫|ねこ}である。[[em:名前]]はまだない。第^12^話。\n\n";
const FILLER: &str = "本文は静かに続き、季節は移ろう。";
let mut source = String::with_capacity(characters.saturating_mul(3));
let chapter_characters = CHAPTER.chars().count();
let paragraph = format!(
"東京の空は青く、{{言葉|ことば}}は[[em:静か]]に続く。第^12^話。{}\n\n",
FILLER.repeat(96)
);
let paragraph_characters = paragraph.chars().count();
let mut used_characters = 0;
let mut paragraphs = 0;
while used_characters + paragraph_characters <= characters {
if paragraphs % 64 == 0
&& used_characters + chapter_characters + paragraph_characters <= characters
{
source.push_str(CHAPTER);
used_characters += chapter_characters;
}
source.push_str(¶graph);
used_characters += paragraph_characters;
paragraphs += 1;
}
source.extend(std::iter::repeat_n('字', characters - used_characters));
assert_eq!(source.chars().count(), characters);
source
}
fn run_case(characters: usize) {
let source = book_source(characters);
let source_bytes = source.len();
let parse_started = Instant::now();
let document = parse_document(black_box(&source));
let parse_elapsed = parse_started.elapsed();
assert_eq!(document.span.start_byte, 0);
assert_eq!(document.span.end_byte as usize, source_bytes);
assert!(!document.children.is_empty(), "large source was truncated");
let serialize_started = Instant::now();
let canonical = serialize_mdi_document(black_box(&document));
let serialize_elapsed = serialize_started.elapsed();
assert!(
!canonical.is_empty(),
"canonical serialization was truncated"
);
drop(document);
let reparsed = parse_document(black_box(&canonical));
assert_eq!(reparsed.span.end_byte as usize, canonical.len());
assert!(
!reparsed.children.is_empty(),
"canonical document was truncated"
);
println!(
"PERF_RESULT {{\"characters\":{characters},\"source_bytes\":{source_bytes},\"canonical_bytes\":{},\"parse_ms\":{},\"serialize_ms\":{},\"parse_chars_per_second\":{:.2},\"serialize_chars_per_second\":{:.2}}}",
canonical.len(),
parse_elapsed.as_millis(),
serialize_elapsed.as_millis(),
characters as f64 / parse_elapsed.as_secs_f64(),
characters as f64 / serialize_elapsed.as_secs_f64(),
);
}
#[test]
#[ignore = "run in the Large document performance CI job"]
fn case_100k() {
run_case(HUNDRED_THOUSAND);
}
#[test]
#[ignore = "run in the Large document performance CI job"]
fn case_1m() {
run_case(MILLION);
}
#[test]
#[ignore = "run in the Large document performance CI job"]
fn case_10m() {
run_case(TEN_MILLION);
}
#[test]
#[ignore = "run in the Large document performance CI job"]
fn case_100m() {
run_case(HUNDRED_MILLION);
}