hamt.rs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. use async_std::task;
  2. use criterion::{
  3. async_executor::AsyncStdExecutor, black_box, criterion_group, criterion_main, BatchSize,
  4. Criterion, Throughput,
  5. };
  6. use proptest::{arbitrary::any, collection::vec, test_runner::TestRunner};
  7. use std::cmp;
  8. use wnfs_common::{
  9. utils::{Arc, Sampleable},
  10. BlockStore, Link, MemoryBlockStore, Storable, StoreIpld,
  11. };
  12. use wnfs_hamt::{
  13. diff, merge,
  14. strategies::{generate_kvs, node_from_kvs, node_from_operations, operations},
  15. Hamt, Node,
  16. };
  17. fn node_set(c: &mut Criterion) {
  18. let mut runner = TestRunner::deterministic();
  19. let store = MemoryBlockStore::default();
  20. let operations = operations(any::<[u8; 32]>(), any::<u64>(), 1_000_000).sample(&mut runner);
  21. let node =
  22. &async_std::task::block_on(async { node_from_operations(&operations, &store).await })
  23. .expect("Couldn't setup HAMT node from operations");
  24. let store = Arc::new(store);
  25. c.bench_function("node set", |b| {
  26. b.to_async(AsyncStdExecutor).iter_batched(
  27. || {
  28. let store = Arc::clone(&store);
  29. let kv = (any::<[u8; 32]>(), any::<u64>()).sample(&mut runner);
  30. (store, kv)
  31. },
  32. |(store, (key, value))| async move {
  33. Arc::clone(node)
  34. .set(key, value, store.as_ref())
  35. .await
  36. .unwrap();
  37. black_box(());
  38. },
  39. BatchSize::SmallInput,
  40. );
  41. });
  42. }
  43. fn node_set_consecutive(c: &mut Criterion) {
  44. let mut runner = TestRunner::deterministic();
  45. c.bench_function("node set 1000 consecutive", |b| {
  46. b.to_async(AsyncStdExecutor).iter_batched(
  47. || {
  48. let store = MemoryBlockStore::default();
  49. let operations =
  50. operations(any::<[u8; 32]>(), any::<u64>(), 1000).sample(&mut runner);
  51. let node = async_std::task::block_on(async {
  52. node_from_operations(&operations, &store).await
  53. })
  54. .expect("Couldn't setup HAMT node from operations");
  55. let kvs = vec((any::<[u8; 32]>(), any::<u64>()), 1000).sample(&mut runner);
  56. (node, store, kvs)
  57. },
  58. |(mut node, store, kvs)| async move {
  59. for (key, value) in kvs {
  60. node.set(key, value, &store).await.unwrap();
  61. black_box(());
  62. }
  63. },
  64. BatchSize::SmallInput,
  65. );
  66. });
  67. }
  68. fn node_load_get(c: &mut Criterion) {
  69. let store = MemoryBlockStore::default();
  70. let cid = async_std::task::block_on(async {
  71. let mut node = Arc::new(<Node<_, _>>::default());
  72. for i in 0..50 {
  73. node.set(i.to_string(), i, &store).await.unwrap();
  74. }
  75. Hamt::with_root(node).store(&store).await.unwrap()
  76. });
  77. c.bench_function("node load and get", |b| {
  78. b.to_async(AsyncStdExecutor).iter(|| async {
  79. let hamt = Hamt::<String, i32>::load(&cid, &store).await.unwrap();
  80. for i in 0..50 {
  81. assert!(hamt
  82. .root
  83. .get(&i.to_string(), &store)
  84. .await
  85. .unwrap()
  86. .is_some());
  87. }
  88. })
  89. });
  90. }
  91. fn node_load_remove(c: &mut Criterion) {
  92. let store = MemoryBlockStore::default();
  93. let cid = async_std::task::block_on(async {
  94. let mut node = Arc::new(<Node<_, _>>::default());
  95. for i in 0..50 {
  96. node.set(i.to_string(), i, &store).await.unwrap();
  97. }
  98. Hamt::with_root(node).store(&store).await.unwrap()
  99. });
  100. c.bench_function("node load and remove", |b| {
  101. b.to_async(AsyncStdExecutor).iter(|| async {
  102. let mut hamt = black_box(Hamt::<String, i32>::load(&cid, &store).await.unwrap());
  103. for i in 0..50 {
  104. let value = hamt.root.remove(&i.to_string(), &store).await.unwrap();
  105. assert!(value.is_some());
  106. }
  107. })
  108. });
  109. }
  110. fn hamt_load_decode(c: &mut Criterion) {
  111. let store = MemoryBlockStore::default();
  112. let (cid, bytes) = async_std::task::block_on(async {
  113. let mut node = Arc::new(<Node<_, _>>::default());
  114. for i in 0..50 {
  115. node.set(i.to_string(), i, &store).await.unwrap();
  116. }
  117. let (encoded_hamt, codec) = Hamt::with_root(node)
  118. .to_serializable(&store)
  119. .await
  120. .unwrap()
  121. .encode_ipld()
  122. .unwrap();
  123. let cid = store.put_block(encoded_hamt.clone(), codec).await.unwrap();
  124. (cid, encoded_hamt)
  125. });
  126. let mut group = c.benchmark_group("hamt load and decode");
  127. group.throughput(Throughput::Bytes(bytes.len() as u64));
  128. group.bench_function("0", |b| {
  129. b.to_async(AsyncStdExecutor).iter(|| async {
  130. black_box(Hamt::<String, i32>::load(&cid, &store).await.unwrap());
  131. })
  132. });
  133. group.finish();
  134. }
  135. fn hamt_set_encode(c: &mut Criterion) {
  136. c.bench_function("hamt set and encode", |b| {
  137. b.to_async(AsyncStdExecutor).iter_batched(
  138. || {
  139. (
  140. MemoryBlockStore::default(),
  141. Arc::new(<Node<_, _>>::default()),
  142. )
  143. },
  144. |(store, mut node)| async move {
  145. for i in 0..50 {
  146. node.set(i.to_string(), i, &store).await.unwrap();
  147. }
  148. let hamt = Hamt::with_root(node);
  149. black_box(
  150. hamt.to_serializable(&store)
  151. .await
  152. .unwrap()
  153. .encode_ipld()
  154. .unwrap(),
  155. );
  156. },
  157. BatchSize::SmallInput,
  158. )
  159. });
  160. }
  161. fn hamt_diff(c: &mut Criterion) {
  162. let mut runner = TestRunner::deterministic();
  163. c.bench_function("hamt diff", |b| {
  164. b.to_async(AsyncStdExecutor).iter_batched(
  165. || {
  166. let store = MemoryBlockStore::default();
  167. let kvs1 = generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100).sample(&mut runner);
  168. let kvs2 = generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100).sample(&mut runner);
  169. let (node1, node2) = task::block_on(async {
  170. (
  171. node_from_kvs(kvs1, &store).await.unwrap(),
  172. node_from_kvs(kvs2, &store).await.unwrap(),
  173. )
  174. });
  175. (store, (node1, node2))
  176. },
  177. |(store, (node1, node2))| async move {
  178. black_box(
  179. diff(Link::from(node1), Link::from(node2), &store)
  180. .await
  181. .unwrap(),
  182. );
  183. },
  184. BatchSize::SmallInput,
  185. );
  186. });
  187. }
  188. fn hamt_merge(c: &mut Criterion) {
  189. let mut runner = TestRunner::deterministic();
  190. c.bench_function("hamt merge", |b| {
  191. b.to_async(AsyncStdExecutor).iter_batched(
  192. || {
  193. let store = MemoryBlockStore::default();
  194. let kvs1 = generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100).sample(&mut runner);
  195. let kvs2 = generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100).sample(&mut runner);
  196. let (node1, node2) = task::block_on(async {
  197. (
  198. node_from_kvs(kvs1, &store).await.unwrap(),
  199. node_from_kvs(kvs2, &store).await.unwrap(),
  200. )
  201. });
  202. (store, (node1, node2))
  203. },
  204. |(store, (node1, node2))| async move {
  205. black_box(
  206. merge(
  207. Link::from(node1),
  208. Link::from(node2),
  209. |a, b| Ok(cmp::min(*a, *b)),
  210. &store,
  211. )
  212. .await
  213. .unwrap(),
  214. );
  215. },
  216. BatchSize::SmallInput,
  217. );
  218. });
  219. }
  220. criterion_group!(
  221. benches,
  222. node_set,
  223. node_set_consecutive,
  224. node_load_get,
  225. node_load_remove,
  226. hamt_load_decode,
  227. hamt_set_encode,
  228. hamt_diff,
  229. hamt_merge
  230. );
  231. criterion_main!(benches);