Skip to content

Commit 5dda843

Browse files
committed
Move intl_memoizer to capture provider
1 parent ea47b54 commit 5dda843

File tree

7 files changed

+267
-436
lines changed

7 files changed

+267
-436
lines changed

intl-memoizer/Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,23 @@ icu_locid = { workspace = true }
3030
icu_plurals = { workspace = true }
3131
icu_provider = { workspace = true }
3232
type-map = "0.5"
33+
hashbrown = "0.14"
3334

3435
[dev-dependencies]
3536
fluent-langneg.workspace = true
37+
criterion.workspace = true
38+
icu_locid = "1.4"
39+
icu_provider = "1.4"
40+
icu_datetime = {version = "1.4", features = ["serde"]}
41+
icu_calendar = "1.4"
42+
icu_decimal = "1.4"
43+
icu_provider_blob = "1.4"
3644

3745
[features]
3846
default = []
3947
sync = ["icu_provider/sync"]
48+
49+
[[bench]]
50+
name = "single"
51+
harness = false
52+

intl-memoizer/benches/single.rs

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
use criterion::criterion_group;
2+
use criterion::criterion_main;
3+
use criterion::Criterion;
4+
use criterion::{Bencher, BenchmarkId};
5+
use icu_calendar::DateTime;
6+
use icu_datetime::{options::length::Time, TimeFormatter};
7+
use icu_locid::LanguageIdentifier;
8+
use intl_memoizer::{IntlLangMemoizer, Memoizable};
9+
10+
struct TF(pub TimeFormatter);
11+
12+
use icu_provider_blob::BlobDataProvider;
13+
const ICU4X_DATA: &[u8] = include_bytes!(concat!(
14+
"/Users/zibi/projects/icu-perf/data/icu4x-1.4-datetime.postcard"
15+
));
16+
17+
18+
impl Memoizable for TF {
19+
type Args = (Time,);
20+
21+
type Provider = icu_provider_blob::BlobDataProvider;
22+
23+
/// If the construtor is fallible, than errors can be described here.
24+
type Error = ();
25+
26+
/// This function wires together the `Args` and `Error` type to construct
27+
/// the intl API. In our example, there is
28+
fn construct(
29+
lang: LanguageIdentifier,
30+
args: Self::Args,
31+
provider: Option<&Self::Provider>,
32+
) -> Result<Self, Self::Error> {
33+
Ok(Self(
34+
TimeFormatter::try_new_with_length_with_buffer_provider(
35+
provider.unwrap(), &lang.into(), args.0).unwrap(),
36+
))
37+
}
38+
}
39+
40+
const SETS: usize = 10;
41+
const REPS: usize = 10;
42+
43+
fn construct_lang_bench(c: &mut Criterion) {
44+
let lang: LanguageIdentifier = "en-US".parse().unwrap();
45+
let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
46+
47+
c.bench_with_input(
48+
BenchmarkId::new("construct_lang", &lang),
49+
&(lang, provider),
50+
|b, (lang, provider)| {
51+
b.iter(|| {
52+
let _ = IntlLangMemoizer::new(lang.clone(), Some(provider));
53+
});
54+
},
55+
);
56+
}
57+
58+
fn populate_lang(c: &mut Criterion) {
59+
let lang: LanguageIdentifier = "en".parse().unwrap();
60+
61+
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
62+
let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
63+
let construct_args = (Time::Short, );
64+
65+
c.bench_with_input(
66+
BenchmarkId::new("populate_lang", &lang),
67+
&(construct_args, provider),
68+
|b: &mut Bencher, (construct_args, provider)| {
69+
b.iter(|| {
70+
let memoizer = IntlLangMemoizer::new(lang.clone(), Some(provider));
71+
for _ in 0..SETS {
72+
for _ in 0..REPS {
73+
let _ = memoizer.with_try_get::<TF, _, _>(construct_args, |intl_example| {
74+
intl_example.0.format_to_string(&input)
75+
});
76+
}
77+
}
78+
});
79+
},
80+
);
81+
}
82+
83+
fn without_memoizer(c: &mut Criterion) {
84+
let lang: LanguageIdentifier = "en".parse().unwrap();
85+
let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
86+
let construct_args = (Time::Short, );
87+
88+
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
89+
90+
c.bench_with_input(
91+
BenchmarkId::new("without_memoizer", &lang),
92+
&(construct_args, provider),
93+
|b: &mut Bencher, (construct_args, provider)| {
94+
b.iter(|| {
95+
for _ in 0..SETS {
96+
for _ in 0..REPS {
97+
let formatter =
98+
TimeFormatter::try_new_with_length_with_buffer_provider(provider, &lang.clone().into(), construct_args.0)
99+
.unwrap();
100+
let _ = formatter.format(&input);
101+
}
102+
}
103+
});
104+
},
105+
);
106+
}
107+
108+
fn without_memoizer_hoisted(c: &mut Criterion) {
109+
let lang: LanguageIdentifier = "en".parse().unwrap();
110+
let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data");
111+
let construct_args = (Time::Short, );
112+
113+
let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap();
114+
115+
c.bench_with_input(
116+
BenchmarkId::new("without_memoizer_hoisted", &lang),
117+
&(construct_args, provider),
118+
|b: &mut Bencher, (construct_args, provider)| {
119+
b.iter(|| {
120+
for _ in 0..SETS {
121+
let formatter =
122+
TimeFormatter::try_new_with_length_with_buffer_provider(provider, &lang.clone().into(), construct_args.0)
123+
.unwrap();
124+
for _ in 0..REPS {
125+
let _ = formatter.format(&input);
126+
}
127+
}
128+
});
129+
},
130+
);
131+
}
132+
133+
criterion_group!(
134+
benches,
135+
construct_lang_bench,
136+
populate_lang,
137+
without_memoizer,
138+
without_memoizer_hoisted
139+
);
140+
criterion_main!(benches);

intl-memoizer/src/lang_memoizer.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// use std::collections::HashMap;
2+
use crate::memoizable::Memoizable;
3+
use hashbrown::HashMap;
4+
use icu_locid::LanguageIdentifier;
5+
use std::cell::RefCell;
6+
7+
pub struct IntlLangMemoizer<'dp, DP = ()> {
8+
lang: LanguageIdentifier,
9+
provider: Option<&'dp DP>,
10+
map: RefCell<type_map::TypeMap>,
11+
}
12+
13+
impl<'dp, DP> IntlLangMemoizer<'dp, DP> {
14+
pub fn new(lang: LanguageIdentifier, provider: Option<&'dp DP>) -> Self {
15+
Self {
16+
lang,
17+
provider,
18+
map: Default::default(),
19+
}
20+
}
21+
22+
pub fn with_try_get<I, R, U>(
23+
&self,
24+
construct_args: &I::Args,
25+
callback: U,
26+
) -> Result<R, I::Error>
27+
where
28+
Self: Sized,
29+
I: Memoizable<Provider = DP> + 'static,
30+
U: FnOnce(&I) -> R,
31+
{
32+
let mut map = self.map.borrow_mut();
33+
34+
let cache = map.entry().or_insert_with(HashMap::<I::Args, I>::new);
35+
36+
let (_, e) = cache
37+
.raw_entry_mut()
38+
.from_key(construct_args)
39+
.or_insert_with(|| {
40+
(
41+
construct_args.clone(),
42+
I::construct(self.lang.clone(), construct_args.clone(), self.provider)
43+
.expect("FOO"),
44+
)
45+
});
46+
Ok(callback(&e))
47+
}
48+
}

0 commit comments

Comments
 (0)