Skip to content

Commit 30125e9

Browse files
zbranieckialerque
authored andcommitted
perf(intl-memoizer): Benchmark memoizer
1 parent adef769 commit 30125e9

File tree

2 files changed

+183
-125
lines changed

2 files changed

+183
-125
lines changed

intl-memoizer/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ icu_datetime = {version = "1.4", features = ["serde"]}
3737
icu_calendar = "1.4"
3838
icu_decimal = "1.4"
3939
icu_provider_blob = "1.4"
40+
icu_collator = "1.4"
41+
fixed_decimal = "0.5"
42+
icu_list = { version = "1.4", features = ["serde"]}
4043

4144
[features]
4245
default = []

intl-memoizer/benches/single.rs

Lines changed: 180 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -3,151 +3,206 @@ use criterion::criterion_main;
33
use criterion::Criterion;
44
use criterion::{Bencher, BenchmarkId};
55
use icu_calendar::DateTime;
6-
use icu_datetime::{options::length::Time, TimeFormatter};
6+
use icu_datetime::{
7+
options::length::{Date, Time},
8+
// DateTimeFormatterOptions,
9+
DateFormatter,
10+
// DateTimeFormatter,
11+
TimeFormatter,
12+
};
13+
// use icu_collator::{Collator, CollatorOptions};
14+
// use icu_decimal::{FixedDecimalFormatter, options::FixedDecimalFormatterOptions};
15+
// use fixed_decimal::FixedDecimal;
16+
use icu_list::{ListFormatter, ListLength};
717
use icu_locid::LanguageIdentifier;
18+
use icu_plurals::{PluralRuleType, PluralRules};
819
use intl_memoizer::{IntlLangMemoizer, Memoizable};
9-
10-
struct TF(pub TimeFormatter);
20+
use std::hint::black_box;
1121

1222
use icu_provider_blob::BlobDataProvider;
1323
const ICU4X_DATA: &[u8] = include_bytes!(concat!(
14-
"/Users/zibi/projects/icu-perf/data/icu4x-1.4-datetime.postcard"
24+
"/Users/zibi/projects/icu-perf/data/icu4x-1.4.postcard"
1525
));
1626

17-
impl Memoizable for TF {
18-
type Args = (Time,);
19-
20-
type Provider = icu_provider_blob::BlobDataProvider;
21-
22-
/// If the construtor is fallible, than errors can be described here.
23-
type Error = ();
24-
25-
/// This function wires together the `Args` and `Error` type to construct
26-
/// the intl API. In our example, there is
27-
fn construct(
28-
lang: LanguageIdentifier,
29-
args: Self::Args,
30-
provider: Option<&Self::Provider>,
31-
) -> Result<Self, Self::Error> {
32-
Ok(Self(
33-
TimeFormatter::try_new_with_length_with_buffer_provider(
34-
provider.unwrap(),
35-
&lang.into(),
36-
args.0,
37-
)
38-
.unwrap(),
39-
))
40-
}
27+
trait Testable {
28+
type Input;
29+
30+
fn execute(&self, input: Self::Input);
4131
}
4232

43-
const SETS: usize = 10;
44-
const REPS: usize = 10;
33+
macro_rules! define_testable_type {
34+
($name:ident, $type:ident, $args:tt, $constructor:ident, $method:ident, $input:ty) => {
35+
define_testable_type!($name, $type, $args, $constructor);
36+
37+
impl Testable for $name {
38+
type Input = $input;
39+
40+
fn execute(&self, input: Self::Input) {
41+
let _ = self.0.$method(input);
42+
}
43+
}
44+
};
45+
46+
($name:ident, $type:ident, $args:tt, $constructor:ident, $method:ident, ref $input:ty) => {
47+
define_testable_type!($name, $type, $args, $constructor);
48+
49+
impl Testable for $name {
50+
type Input = $input;
51+
52+
fn execute(&self, input: Self::Input) {
53+
let _ = self.0.$method(&input);
54+
}
55+
}
56+
};
57+
58+
($name:ident, $type:ident, $args:tt, $constructor:ident) => {
59+
struct $name($type);
60+
61+
impl Memoizable for $name {
62+
type Args = $args;
63+
type Provider = icu_provider_blob::BlobDataProvider;
64+
type Error = ();
65+
66+
fn construct(
67+
lang: LanguageIdentifier,
68+
args: Self::Args,
69+
provider: Option<&Self::Provider>,
70+
) -> Result<Self, Self::Error> {
71+
Ok(Self(
72+
$type::$constructor(provider.unwrap(), &lang.into(), args.0).unwrap(),
73+
))
74+
}
75+
}
76+
};
77+
}
4578

46-
fn construct_lang_bench(c: &mut Criterion) {
47-
let lang: LanguageIdentifier = "en-US".parse().unwrap();
48-
let provider =
49-
BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
79+
define_testable_type!(TF, TimeFormatter, (Time, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime<icu_calendar::Gregorian>);
80+
define_testable_type!(DF, DateFormatter, (Date, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime<icu_calendar::AnyCalendar>);
81+
// define_testable_type!(DTF, DateTimeFormatter, (DateTimeFormatterOptions, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime<icu_calendar::AnyCalendar>);
82+
define_testable_type!(
83+
PR,
84+
PluralRules,
85+
(PluralRuleType,),
86+
try_new_with_buffer_provider,
87+
category_for,
88+
usize
89+
);
90+
// define_testable_type!(
91+
// C,
92+
// Collator,
93+
// (CollatorOptions,),
94+
// try_new_with_buffer_provider,
95+
// compare,
96+
// &str,
97+
// &str,
98+
// );
99+
// define_testable_type!(
100+
// D,
101+
// FixedDecimalFormatter,
102+
// (FixedDecimalFormatterOptions,),
103+
// try_new_with_buffer_provider,
104+
// format_to_string,
105+
// ref FixedDecimal
106+
// );
107+
define_testable_type!(
108+
LF,
109+
ListFormatter,
110+
(ListLength,),
111+
try_new_and_with_length_with_buffer_provider,
112+
format_to_string,
113+
std::vec::IntoIter<String>
114+
);
50115

51-
c.bench_with_input(
52-
BenchmarkId::new("construct_lang", &lang),
53-
&(lang, provider),
54-
|b, (lang, provider)| {
55-
b.iter(|| {
56-
let _ = IntlLangMemoizer::new(lang.clone(), Some(provider));
57-
});
58-
},
59-
);
116+
macro_rules! without_memoizer_hoisted {
117+
($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => {
118+
$b.iter(|| {
119+
let intl = $type::construct($lang.clone(), black_box($args), Some($provider)).unwrap();
120+
for _ in 0..$count {
121+
let _ = intl.execute($input);
122+
}
123+
})
124+
};
60125
}
61126

62-
fn populate_lang(c: &mut Criterion) {
63-
let lang: LanguageIdentifier = "en".parse().unwrap();
64-
65-
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
66-
let provider =
67-
BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
68-
let construct_args = (Time::Short,);
69-
70-
c.bench_with_input(
71-
BenchmarkId::new("populate_lang", &lang),
72-
&(construct_args, provider),
73-
|b: &mut Bencher, (construct_args, provider)| {
74-
b.iter(|| {
75-
let memoizer = IntlLangMemoizer::new(lang.clone(), Some(provider));
76-
for _ in 0..SETS {
77-
for _ in 0..REPS {
78-
let _ = memoizer.with_try_get::<TF, _, _>(construct_args, |intl_example| {
79-
intl_example.0.format_to_string(&input)
80-
});
81-
}
82-
}
83-
});
84-
},
85-
);
127+
macro_rules! without_memoizer {
128+
($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => {
129+
$b.iter(|| {
130+
for _ in 0..$count {
131+
let intl =
132+
$type::construct($lang.clone(), black_box($args), Some($provider)).unwrap();
133+
let _ = intl.execute($input);
134+
}
135+
})
136+
};
86137
}
87138

88-
fn without_memoizer(c: &mut Criterion) {
89-
let lang: LanguageIdentifier = "en".parse().unwrap();
90-
let provider =
91-
BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
92-
let construct_args = (Time::Short,);
93-
94-
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
95-
96-
c.bench_with_input(
97-
BenchmarkId::new("without_memoizer", &lang),
98-
&(construct_args, provider),
99-
|b: &mut Bencher, (construct_args, provider)| {
100-
b.iter(|| {
101-
for _ in 0..SETS {
102-
for _ in 0..REPS {
103-
let formatter = TimeFormatter::try_new_with_length_with_buffer_provider(
104-
provider,
105-
&lang.clone().into(),
106-
construct_args.0,
107-
)
108-
.unwrap();
109-
let _ = formatter.format(&input);
110-
}
111-
}
112-
});
113-
},
114-
);
139+
macro_rules! with_memoizer {
140+
($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => {
141+
$b.iter(|| {
142+
let memoizer =
143+
IntlLangMemoizer::new(black_box($lang.clone()), Some(black_box($provider)));
144+
for _ in 0..$count {
145+
let _ =
146+
memoizer.with_try_get(black_box(&$args), |intl: &$type| intl.execute($input));
147+
}
148+
})
149+
};
115150
}
116151

117-
fn without_memoizer_hoisted(c: &mut Criterion) {
118-
let lang: LanguageIdentifier = "en".parse().unwrap();
152+
fn bench_variants(c: &mut Criterion) {
153+
let lang: LanguageIdentifier = "und".parse().unwrap();
154+
119155
let provider =
120156
BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
121-
let construct_args = (Time::Short,);
122-
123-
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
124-
125-
c.bench_with_input(
126-
BenchmarkId::new("without_memoizer_hoisted", &lang),
127-
&(construct_args, provider),
128-
|b: &mut Bencher, (construct_args, provider)| {
129-
b.iter(|| {
130-
for _ in 0..SETS {
131-
let formatter = TimeFormatter::try_new_with_length_with_buffer_provider(
132-
provider,
133-
&lang.clone().into(),
134-
construct_args.0,
135-
)
136-
.unwrap();
137-
for _ in 0..REPS {
138-
let _ = formatter.format(&input);
157+
158+
let tf_input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
159+
let tf_args = (Time::Short,);
160+
161+
let pr_input = 5;
162+
let pr_args = (PluralRuleType::Cardinal,);
163+
164+
for component in ["time", "plurals"] {
165+
let mut group = c.benchmark_group(component);
166+
let counts: &[usize] = &[0, 1, 10, 100, 1000, 10000];
167+
168+
for count in counts {
169+
group.bench_with_input(
170+
BenchmarkId::new("without_memoizer_hoisted", count),
171+
&(count, &provider),
172+
|b: &mut Bencher, &(count, provider)| match component {
173+
"time" => {
174+
without_memoizer_hoisted!(TF, b, lang, provider, tf_args, *count, tf_input)
175+
}
176+
"plurals" => {
177+
without_memoizer_hoisted!(PR, b, lang, provider, pr_args, *count, pr_input)
139178
}
140-
}
141-
});
142-
},
143-
);
179+
_ => unreachable!(),
180+
},
181+
);
182+
group.bench_with_input(
183+
BenchmarkId::new("without_memoizer", count),
184+
&(count, &provider),
185+
|b: &mut Bencher, &(count, provider)| match component {
186+
"time" => without_memoizer!(TF, b, lang, provider, tf_args, *count, tf_input),
187+
"plurals" => {
188+
without_memoizer!(PR, b, lang, provider, pr_args, *count, pr_input)
189+
}
190+
_ => unreachable!(),
191+
},
192+
);
193+
group.bench_with_input(
194+
BenchmarkId::new("with_memoizer", count),
195+
&(count, &provider),
196+
|b: &mut Bencher, &(count, provider)| match component {
197+
"time" => with_memoizer!(TF, b, lang, provider, tf_args, *count, tf_input),
198+
"plurals" => with_memoizer!(PR, b, lang, provider, pr_args, *count, pr_input),
199+
_ => unreachable!(),
200+
},
201+
);
202+
}
203+
group.finish();
204+
}
144205
}
145206

146-
criterion_group!(
147-
benches,
148-
construct_lang_bench,
149-
populate_lang,
150-
without_memoizer,
151-
without_memoizer_hoisted
152-
);
207+
criterion_group!(benches, bench_variants,);
153208
criterion_main!(benches);

0 commit comments

Comments
 (0)