forked from
tangled.org/core
Monorepo for Tangled
7.9 kB
245 lines
1use std::hint::black_box;
2
3use bobbin_types::edges::Record;
4use criterion::{Criterion, criterion_group, criterion_main};
5use jacquard_common::DefaultStr;
6use jacquard_common::types::nsid::Nsid;
7use serde::Deserialize;
8use serde_json::value::RawValue;
9
10#[derive(Deserialize)]
11struct ValueFrame {
12 record: ValueRecordFrame,
13}
14
15#[derive(Deserialize)]
16struct ValueRecordFrame {
17 collection: Nsid<DefaultStr>,
18 #[serde(default)]
19 record: Option<serde_json::Value>,
20}
21
22#[derive(Deserialize)]
23struct BorrowedRawFrame<'a> {
24 #[serde(borrow)]
25 record: BorrowedRawRecordFrame<'a>,
26}
27
28#[derive(Deserialize)]
29struct BorrowedRawRecordFrame<'a> {
30 collection: Nsid<DefaultStr>,
31 #[serde(borrow, default)]
32 record: Option<&'a RawValue>,
33}
34
35#[derive(Deserialize)]
36struct OwnedRawFrame {
37 record: OwnedRawRecordFrame,
38}
39
40#[derive(Deserialize)]
41struct OwnedRawRecordFrame {
42 collection: Nsid<DefaultStr>,
43 #[serde(default)]
44 record: Option<Box<RawValue>>,
45}
46
47fn current_path(text: &str) -> Record {
48 let frame: ValueFrame = serde_json::from_str(text).expect("frame");
49 let value = frame.record.record.expect("upsert body");
50 let bytes = serde_json::to_vec(&value).expect("re-serialize Value");
51 Record::from_json_bytes(&frame.record.collection, &bytes).expect("decode record")
52}
53
54fn raw_value_borrowed(text: &str) -> Record {
55 let frame: BorrowedRawFrame<'_> = serde_json::from_str(text).expect("frame");
56 let raw = frame.record.record.expect("upsert body");
57 Record::from_json_bytes(&frame.record.collection, raw.get().as_bytes()).expect("decode record")
58}
59
60fn raw_value_owned(text: &str) -> Record {
61 let frame: OwnedRawFrame = serde_json::from_str(text).expect("frame");
62 let raw = frame.record.record.expect("upsert body");
63 Record::from_json_bytes(&frame.record.collection, raw.get().as_bytes()).expect("decode record")
64}
65
66fn floor_record_only(collection: &Nsid<DefaultStr>, record_bytes: &[u8]) -> Record {
67 Record::from_json_bytes(collection, record_bytes).expect("decode record")
68}
69
70fn star_text() -> &'static str {
71 r#"{
72 "id": 1,
73 "type": "record",
74 "record": {
75 "live": false,
76 "did": "did:plc:olaren",
77 "rev": "3lq2zk5wqsh2k",
78 "collection": "sh.tangled.feed.star",
79 "rkey": "abcabcabcabcz",
80 "action": "create",
81 "record": {
82 "$type": "sh.tangled.feed.star",
83 "createdAt": "2026-05-01T00:00:00Z",
84 "subject": "at://did:plc:abalone/sh.tangled.repo/3lq2zk5wq0000"
85 }
86 }
87 }"#
88}
89
90fn repo_text() -> &'static str {
91 r#"{
92 "id": 2,
93 "type": "record",
94 "record": {
95 "live": false,
96 "did": "did:plc:nel",
97 "rev": "3lq2zk5wqsh2l",
98 "collection": "sh.tangled.repo",
99 "rkey": "3lq2zk5wq0001",
100 "action": "create",
101 "record": {
102 "$type": "sh.tangled.repo",
103 "createdAt": "2026-05-01T00:00:00Z",
104 "knot": "knot.witchcraft.systems",
105 "name": "limpet",
106 "description": "demonstration repository for the bench corpus",
107 "owner": "did:plc:nel",
108 "repoDid": "did:plc:limpet",
109 "labels": [
110 "at://did:plc:periwinkle/sh.tangled.label.definition/3lq2zk5wq0010",
111 "at://did:plc:periwinkle/sh.tangled.label.definition/3lq2zk5wq0011"
112 ]
113 }
114 }
115 }"#
116}
117
118fn issue_text() -> &'static str {
119 r#"{
120 "id": 3,
121 "type": "record",
122 "record": {
123 "live": false,
124 "did": "did:plc:teq",
125 "rev": "3lq2zk5wqsh2m",
126 "collection": "sh.tangled.repo.issue",
127 "rkey": "3lq2zk5wq0100",
128 "action": "create",
129 "record": {
130 "$type": "sh.tangled.repo.issue",
131 "createdAt": "2026-05-01T00:00:00Z",
132 "title": "ingest: single-pass JSON decode follow-up corpus entry",
133 "body": "Long body to give the bench a realistic decode cost. Repeats: blahhhhh meow meow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
134 "repo": "at://did:plc:limpet",
135 "repoDid": "did:plc:limpet",
136 "mentions": [
137 "did:plc:nel",
138 "did:plc:olaren",
139 "did:plc:bailey"
140 ],
141 "references": [
142 "at://did:plc:limpet/sh.tangled.repo.issue/3lq2zk5wq0099",
143 "at://did:plc:limpet/sh.tangled.repo.pull/3lq2zk5wq0098"
144 ]
145 }
146 }
147 }"#
148}
149
150fn pull_comment_text() -> &'static str {
151 r#"{
152 "id": 4,
153 "type": "record",
154 "record": {
155 "live": false,
156 "did": "did:plc:lyna",
157 "rev": "3lq2zk5wqsh2n",
158 "collection": "sh.tangled.repo.pull.comment",
159 "rkey": "3lq2zk5wq0200",
160 "action": "create",
161 "record": {
162 "$type": "sh.tangled.repo.pull.comment",
163 "createdAt": "2026-05-01T00:00:00Z",
164 "body": "lgtm i thinks!!!! but please verify the cursor invariant under buffered(N) before landing. :3",
165 "pull": "at://did:plc:limpet/sh.tangled.repo.pull/3lq2zk5wq0098",
166 "owner": "did:plc:lyna"
167 }
168 }
169 }"#
170}
171
172fn follow_text() -> &'static str {
173 r#"{
174 "id": 5,
175 "type": "record",
176 "record": {
177 "live": false,
178 "did": "did:plc:bailey",
179 "rev": "3lq2zk5wqsh2o",
180 "collection": "sh.tangled.graph.follow",
181 "rkey": "3lq2zk5wq0300",
182 "action": "create",
183 "record": {
184 "$type": "sh.tangled.graph.follow",
185 "createdAt": "2026-05-01T00:00:00Z",
186 "subject": "did:plc:nel"
187 }
188 }
189 }"#
190}
191
192fn extract_record_slice(text: &str) -> (Nsid<DefaultStr>, Vec<u8>) {
193 let frame: ValueFrame = serde_json::from_str(text).expect("frame");
194 let value = frame.record.record.expect("upsert body");
195 let bytes = serde_json::to_vec(&value).expect("re-serialize Value");
196 (frame.record.collection, bytes)
197}
198
199fn bench_decode(c: &mut Criterion) {
200 let corpus: &[(&str, &str)] = &[
201 ("star", star_text()),
202 ("repo", repo_text()),
203 ("issue", issue_text()),
204 ("pull_comment", pull_comment_text()),
205 ("follow", follow_text()),
206 ];
207 for (name, text) in corpus {
208 let mut group = c.benchmark_group(format!("decode/{name}"));
209 let (collection, record_bytes) = extract_record_slice(text);
210
211 group.bench_function("current_path", |b| {
212 b.iter(|| {
213 let r = current_path(black_box(text));
214 black_box(r);
215 });
216 });
217
218 group.bench_function("raw_value_borrowed", |b| {
219 b.iter(|| {
220 let r = raw_value_borrowed(black_box(text));
221 black_box(r);
222 });
223 });
224
225 group.bench_function("raw_value_owned", |b| {
226 b.iter(|| {
227 let r = raw_value_owned(black_box(text));
228 black_box(r);
229 });
230 });
231
232 group.bench_function("floor_record_only", |b| {
233 let bytes = record_bytes.as_slice();
234 b.iter(|| {
235 let r = floor_record_only(black_box(&collection), black_box(bytes));
236 black_box(r);
237 });
238 });
239
240 group.finish();
241 }
242}
243
244criterion_group!(benches, bench_decode);
245criterion_main!(benches);