Skip to content

Commit

Permalink
perf: make BTreeMap V2 2-4x more officient (#118)
Browse files Browse the repository at this point in the history
A number of optimizations are made to make BTreeMap V2 more efficient.
The optimizations in this commit are focused on loading the BTree node
faster, specifically:

1. Rather than loading all the pages of a node into one large buffer on
the heap, a `NodeReader` is introduced to read the data from stable
memory directly, avoiding allocating large vectors on the heap.
2. Values are loaded lazily as needed.

V2 is still quite a bit slower than V1, but more performance
optimizations will be made in subsequent commits to narrow that gap.

Benchmark results:

```
Benchmarking btreemap_insert_blob_4_1024: Warming up for 1.0000 ms
2023-08-30 13:29:46.909777 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "280_652_463 (28%)",
    "node_save_v1": "378_779_478 (38%)",
}

btreemap_insert_blob_4_1024
                        time:   [990.56 M Instructions 990.56 M Instructions 990.56 M Instructions]
                        change: [+1.9882% +1.9882% +1.9882%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_4_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:29:48.438599 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "481_365_503 (29%)",
    "node_save_v2": "791_766_971 (49%)",
}

btreemap_insert_blob_4_1024_v2
                        time:   [1614.0 M Instructions 1614.0 M Instructions 1614.0 M Instructions]
                        change: [-68.528% -68.528% -68.528%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_8_1024: Warming up for 1.0000 ms
2023-08-30 13:29:50.215987 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "321_869_274 (28%)",
    "node_save_v1": "403_084_516 (35%)",
}

btreemap_insert_blob_8_1024
                        time:   [1138.0 M Instructions 1138.0 M Instructions 1138.0 M Instructions]
                        change: [+1.8644% +1.8644% +1.8644%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_8_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:29:51.688200 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "537_284_069 (29%)",
    "node_save_v2": "855_112_095 (47%)",
}

btreemap_insert_blob_8_1024_v2
                        time:   [1814.0 M Instructions 1814.0 M Instructions 1814.0 M Instructions]
                        change: [-67.519% -67.519% -67.519%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_16_1024: Warming up for 1.0000 ms
2023-08-30 13:29:53.364102 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "402_518_468 (32%)",
    "node_save_v1": "412_099_008 (33%)",
}

btreemap_insert_blob_16_1024
                        time:   [1234.1 M Instructions 1234.1 M Instructions 1234.1 M Instructions]
                        change: [+1.7602% +1.7602% +1.7602%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_16_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:29:54.959311 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "637_871_422 (32%)",
    "node_save_v2": "888_925_546 (45%)",
}

btreemap_insert_blob_16_1024_v2
                        time:   [1956.2 M Instructions 1956.2 M Instructions 1956.2 M Instructions]
                        change: [-65.588% -65.588% -65.588%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_32_1024: Warming up for 1.0000 ms
2023-08-30 13:29:56.710154 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "424_603_999 (33%)",
    "node_save_v1": "424_724_582 (33%)",
}

btreemap_insert_blob_32_1024
                        time:   [1275.2 M Instructions 1275.2 M Instructions 1275.2 M Instructions]
                        change: [+1.7279% +1.7279% +1.7279%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_32_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:29:58.173915 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "674_211_795 (33%)",
    "node_save_v2": "924_055_955 (45%)",
}

btreemap_insert_blob_32_1024_v2
                        time:   [2026.7 M Instructions 2026.7 M Instructions 2026.7 M Instructions]
                        change: [-65.556% -65.556% -65.556%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_64_1024: Warming up for 1.0000 ms
2023-08-30 13:29:59.850203 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "629_811_234 (41%)",
    "node_save_v1": "427_562_314 (28%)",
}

btreemap_insert_blob_64_1024
                        time:   [1515.3 M Instructions 1515.3 M Instructions 1515.3 M Instructions]
                        change: [+1.4626% +1.4626% +1.4626%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_64_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:01.464917 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "902_108_118 (38%)",
    "node_save_v2": "945_427_084 (40%)",
}

btreemap_insert_blob_64_1024_v2
                        time:   [2319.5 M Instructions 2319.5 M Instructions 2319.5 M Instructions]
                        change: [-64.179% -64.179% -64.179%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_128_1024: Warming up for 1.0000 ms
2023-08-30 13:30:03.336015 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "854_194_111 (47%)",
    "node_save_v1": "433_551_383 (24%)",
}

btreemap_insert_blob_128_1024
                        time:   [1782.9 M Instructions 1782.9 M Instructions 1782.9 M Instructions]
                        change: [+1.2385% +1.2385% +1.2385%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_128_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:04.979043 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_181_808_096 (43%)",
    "node_save_v2": "982_453_230 (36%)",
}

btreemap_insert_blob_128_1024_v2
                        time:   [2692.3 M Instructions 2692.3 M Instructions 2692.3 M Instructions]
                        change: [-61.894% -61.894% -61.894%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_256_1024: Warming up for 1.0000 ms
2023-08-30 13:30:06.986058 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "1_308_925_598 (56%)",
    "node_save_v1": "439_263_956 (19%)",
}

btreemap_insert_blob_256_1024
                        time:   [2311.2 M Instructions 2311.2 M Instructions 2311.2 M Instructions]
                        change: [+0.9550% +0.9550% +0.9550%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_insert_blob_256_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:08.887031 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_702_828_360 (50%)",
    "node_save_v2": "1_030_215_378 (30%)",
}

btreemap_insert_blob_256_1024_v2
                        time:   [3360.7 M Instructions 3360.7 M Instructions 3360.7 M Instructions]
                        change: [-56.725% -56.725% -56.725%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_512_1024: Warming up for 1.0000 ms
2023-08-30 13:30:10.913146 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "2_198_537_195 (65%)",
    "node_save_v1": "455_605_397 (13%)",
}

btreemap_insert_blob_512_1024
                        time:   [3362.4 M Instructions 3362.4 M Instructions 3362.4 M Instructions]
                        change: [+0.6560% +0.6560% +0.6560%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_insert_blob_512_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:12.802118 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "2_654_333_483 (58%)",
    "node_save_v2": "1_148_060_652 (25%)",
}

btreemap_insert_blob_512_1024_v2
                        time:   [4530.6 M Instructions 4530.6 M Instructions 4530.6 M Instructions]
                        change: [-53.664% -53.664% -53.664%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_u64_u64: Warming up for 1.0000 ms
2023-08-30 13:30:14.988104 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "306_179_398 (35%)",
    "node_save_v1": "306_699_642 (35%)",
}

btreemap_insert_u64_u64 time:   [858.23 M Instructions 858.23 M Instructions 858.23 M Instructions]
                        change: [+2.6280% +2.6280% +2.6280%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_u64_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:30:16.220958 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "385_750_590 (39%)",
    "node_save_v2": "340_931_881 (35%)",
}

btreemap_insert_u64_u64_v2
                        time:   [967.61 M Instructions 967.61 M Instructions 967.61 M Instructions]
                        change: [-22.690% -22.690% -22.690%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_u64_blob_8: Warming up for 1.0000 ms
2023-08-30 13:30:17.437455 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "308_458_700 (37%)",
    "node_save_v1": "293_871_277 (35%)",
}

btreemap_insert_u64_blob_8
                        time:   [831.41 M Instructions 831.41 M Instructions 831.41 M Instructions]
                        change: [+2.7028% +2.7028% +2.7028%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_u64_blob_8_v2: Warming up for 1.0000 ms
2023-08-30 13:30:18.704157 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "384_546_931 (41%)",
    "node_save_v2": "313_996_501 (34%)",
}

btreemap_insert_u64_blob_8_v2
                        time:   [923.47 M Instructions 923.47 M Instructions 923.47 M Instructions]
                        change: [-22.231% -22.231% -22.231%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_insert_blob_8_u64: Warming up for 1.0000 ms
2023-08-30 13:30:19.847856 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "310_026_924 (41%)",
    "node_save_v1": "201_763_446 (27%)",
}

btreemap_insert_blob_8_u64
                        time:   [740.28 M Instructions 740.28 M Instructions 740.28 M Instructions]
                        change: [+2.8877% +2.8877% +2.8877%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_insert_blob_8_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:30:21.137105 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "387_941_334 (45%)",
    "node_save_v2": "247_665_634 (28%)",
}

btreemap_insert_blob_8_u64_v2
                        time:   [860.71 M Instructions 860.71 M Instructions 860.71 M Instructions]
                        change: [-25.356% -25.356% -25.356%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_4_1024: Warming up for 1.0000 ms
2023-08-30 13:30:22.382634 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "293_795_450 (66%)",
}

btreemap_get_blob_4_1024
                        time:   [442.36 M Instructions 442.36 M Instructions 442.36 M Instructions]
                        change: [+1.6646% +1.6646% +1.6646%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_4_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:24.092106 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "516_995_139 (74%)",
}

btreemap_get_blob_4_1024_v2
                        time:   [692.81 M Instructions 692.81 M Instructions 692.81 M Instructions]
                        change: [-86.187% -86.187% -86.187%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_8_1024: Warming up for 1.0000 ms
2023-08-30 13:30:26.077776 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "344_728_885 (66%)",
}

btreemap_get_blob_8_1024
                        time:   [520.76 M Instructions 520.76 M Instructions 520.76 M Instructions]
                        change: [+1.6751% +1.6751% +1.6751%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_8_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:27.766904 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "547_592_745 (72%)",
}

btreemap_get_blob_8_1024_v2
                        time:   [751.56 M Instructions 751.56 M Instructions 751.56 M Instructions]
                        change: [-83.628% -83.628% -83.628%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_16_1024: Warming up for 1.0000 ms
2023-08-30 13:30:29.675098 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "425_809_809 (70%)",
}

btreemap_get_blob_16_1024
                        time:   [602.40 M Instructions 602.40 M Instructions 602.40 M Instructions]
                        change: [+1.4532% +1.4532% +1.4532%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_16_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:31.443236 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "646_405_838 (76%)",
}

btreemap_get_blob_16_1024_v2
                        time:   [845.21 M Instructions 845.21 M Instructions 845.21 M Instructions]
                        change: [-81.786% -81.786% -81.786%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_32_1024: Warming up for 1.0000 ms
2023-08-30 13:30:33.485992 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "444_926_271 (70%)",
}

btreemap_get_blob_32_1024
                        time:   [632.59 M Instructions 632.59 M Instructions 632.59 M Instructions]
                        change: [+1.3882% +1.3882% +1.3882%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_32_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:35.328321 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "683_036_393 (76%)",
}

btreemap_get_blob_32_1024_v2
                        time:   [893.12 M Instructions 893.12 M Instructions 893.12 M Instructions]
                        change: [-82.432% -82.432% -82.432%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_64_1024: Warming up for 1.0000 ms
2023-08-30 13:30:37.364 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "663_035_945 (77%)",
}

btreemap_get_blob_64_1024
                        time:   [856.36 M Instructions 856.36 M Instructions 856.36 M Instructions]
                        change: [+1.0251% +1.0251% +1.0251%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_64_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:39.182974 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "906_869_057 (80%)",
}

btreemap_get_blob_64_1024_v2
                        time:   [1127.3 M Instructions 1127.3 M Instructions 1127.3 M Instructions]
                        change: [-79.477% -79.477% -79.477%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_128_1024: Warming up for 1.0000 ms
2023-08-30 13:30:41.276889 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "875_716_723 (81%)",
}

btreemap_get_blob_128_1024
                        time:   [1078.9 M Instructions 1078.9 M Instructions 1078.9 M Instructions]
                        change: [+0.8112% +0.8112% +0.8112%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_get_blob_128_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:43.159713 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_199_414_614 (83%)",
}

btreemap_get_blob_128_1024_v2
                        time:   [1434.3 M Instructions 1434.3 M Instructions 1434.3 M Instructions]
                        change: [-76.011% -76.011% -76.011%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_u64_u64: Warming up for 1.0000 ms
2023-08-30 13:30:45.459040 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "323_182_267 (71%)",
}

btreemap_get_u64_u64    time:   [450.17 M Instructions 450.17 M Instructions 450.17 M Instructions]
                        change: [+2.0779% +2.0779% +2.0779%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_u64_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:30:46.922949 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "403_618_361 (75%)",
}

btreemap_get_u64_u64_v2 time:   [536.77 M Instructions 536.77 M Instructions 536.77 M Instructions]
                        change: [-41.792% -41.792% -41.792%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_u64_blob_8: Warming up for 1.0000 ms
2023-08-30 13:30:48.352277 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "324_661_032 (72%)",
}

btreemap_get_u64_blob_8 time:   [446.62 M Instructions 446.62 M Instructions 446.62 M Instructions]
                        change: [+2.0957% +2.0957% +2.0957%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_u64_blob_8_v2: Warming up for 1.0000 ms
2023-08-30 13:30:49.904282 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "405_206_697 (76%)",
}

btreemap_get_u64_blob_8_v2
                        time:   [531.93 M Instructions 531.93 M Instructions 531.93 M Instructions]
                        change: [-39.188% -39.188% -39.188%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_8_u64: Warming up for 1.0000 ms
2023-08-30 13:30:51.503835 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "327_829_305 (70%)",
}

btreemap_get_blob_8_u64 time:   [464.82 M Instructions 464.82 M Instructions 464.82 M Instructions]
                        change: [+1.8812% +1.8812% +1.8812%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_get_blob_8_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:30:52.976112 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "405_354_044 (74%)",
}

btreemap_get_blob_8_u64_v2
                        time:   [547.72 M Instructions 547.72 M Instructions 547.72 M Instructions]
                        change: [-44.544% -44.544% -44.544%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_256_1024: Warming up for 1.0000 ms
2023-08-30 13:30:54.527343 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "1_339_890_114 (85%)",
}

btreemap_get_blob_256_1024
                        time:   [1568.1 M Instructions 1568.1 M Instructions 1568.1 M Instructions]
                        change: [+0.5572% +0.5572% +0.5572%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_get_blob_256_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:30:56.610064 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_724_578_760 (86%)",
}

btreemap_get_blob_256_1024_v2
                        time:   [1986.7 M Instructions 1986.7 M Instructions 1986.7 M Instructions]
                        change: [-70.236% -70.236% -70.236%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_get_blob_512_1024: Warming up for 1.0000 ms
2023-08-30 13:30:59.349144 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "2_257_152_362 (89%)",
}

btreemap_get_blob_512_1024
                        time:   [2533.8 M Instructions 2533.8 M Instructions 2533.8 M Instructions]
                        change: [+0.3442% +0.3442% +0.3442%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_get_blob_512_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:01.885678 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "2_704_747_759 (89%)",
}

btreemap_get_blob_512_1024_v2
                        time:   [3015.4 M Instructions 3015.4 M Instructions 3015.4 M Instructions]
                        change: [-63.826% -63.826% -63.826%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_4_1024: Warming up for 1.0000 ms
2023-08-30 13:31:04.819011 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "307_574_353 (28%)",
    "node_save_v1": "429_262_724 (39%)",
}

btreemap_remove_blob_4_1024
                        time:   [1078.5 M Instructions 1078.5 M Instructions 1078.5 M Instructions]
                        change: [+2.1824% +2.1824% +2.1824%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_4_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:06.686165 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "525_286_266 (29%)",
    "node_save_v2": "919_507_893 (51%)",
}

btreemap_remove_blob_4_1024_v2
                        time:   [1801.4 M Instructions 1801.4 M Instructions 1801.4 M Instructions]
                        change: [+70.677% +70.677% +70.677%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_8_1024: Warming up for 1.0000 ms
2023-08-30 13:31:08.892916 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "367_298_948 (26%)",
    "node_save_v1": "571_957_965 (41%)",
}

btreemap_remove_blob_8_1024
                        time:   [1381.6 M Instructions 1381.6 M Instructions 1381.6 M Instructions]
                        change: [+2.1607% +2.1607% +2.1607%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_8_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:10.856298 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "592_297_067 (25%)",
    "node_save_v2": "1_246_294_503 (54%)",
}

btreemap_remove_blob_8_1024_v2
                        time:   [2295.8 M Instructions 2295.8 M Instructions 2295.8 M Instructions]
                        change: [+69.760% +69.760% +69.760%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_16_1024: Warming up for 1.0000 ms
2023-08-30 13:31:13.179670 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "465_498_356 (28%)",
    "node_save_v1": "665_431_027 (40%)",
}

btreemap_remove_blob_16_1024
                        time:   [1635.0 M Instructions 1635.0 M Instructions 1635.0 M Instructions]
                        change: [+2.0421% +2.0421% +2.0421%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_16_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:15.202687 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "731_192_668 (26%)",
    "node_save_v2": "1_479_786_407 (54%)",
}

btreemap_remove_blob_16_1024_v2
                        time:   [2730.8 M Instructions 2730.8 M Instructions 2730.8 M Instructions]
                        change: [-61.379% -61.379% -61.379%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_32_1024: Warming up for 1.0000 ms
2023-08-30 13:31:17.763538 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "483_509_883 (28%)",
    "node_save_v1": "692_337_702 (40%)",
}

btreemap_remove_blob_32_1024
                        time:   [1709.2 M Instructions 1709.2 M Instructions 1709.2 M Instructions]
                        change: [+2.0117% +2.0117% +2.0117%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_32_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:19.793330 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "771_502_103 (26%)",
    "node_save_v2": "1_542_745_873 (53%)",
}

btreemap_remove_blob_32_1024_v2
                        time:   [2863.0 M Instructions 2863.0 M Instructions 2863.0 M Instructions]
                        change: [-61.242% -61.242% -61.242%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_64_1024: Warming up for 1.0000 ms
2023-08-30 13:31:22.346099 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "713_539_284 (35%)",
    "node_save_v1": "711_906_437 (35%)",
}

btreemap_remove_blob_64_1024
                        time:   [2002.9 M Instructions 2002.9 M Instructions 2002.9 M Instructions]
                        change: [+1.7442% +1.7442% +1.7442%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_64_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:24.525138 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_005_955_971 (31%)",
    "node_save_v2": "1_604_661_935 (50%)",
}

btreemap_remove_blob_64_1024_v2
                        time:   [3207.4 M Instructions 3207.4 M Instructions 3207.4 M Instructions]
                        change: [-58.543% -58.543% -58.543%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_128_1024: Warming up for 1.0000 ms
2023-08-30 13:31:27.171892 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "961_751_320 (41%)",
    "node_save_v1": "728_296_269 (31%)",
}

btreemap_remove_blob_128_1024
                        time:   [2326.9 M Instructions 2326.9 M Instructions 2326.9 M Instructions]
                        change: [+1.5188% +1.5188% +1.5188%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_128_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:29.473263 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_317_606_284 (35%)",
    "node_save_v2": "1_684_252_759 (46%)",
}

btreemap_remove_blob_128_1024_v2
                        time:   [3661.0 M Instructions 3661.0 M Instructions 3661.0 M Instructions]
                        change: [-55.819% -55.819% -55.819%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_256_1024: Warming up for 1.0000 ms
2023-08-30 13:31:32.261676 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "1_463_074_911 (49%)",
    "node_save_v1": "733_401_574 (24%)",
}

btreemap_remove_blob_256_1024
                        time:   [2936.6 M Instructions 2936.6 M Instructions 2936.6 M Instructions]
                        change: [+1.1822% +1.1822% +1.1822%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_256_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:34.625539 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "1_912_032_462 (43%)",
    "node_save_v2": "1_765_320_493 (39%)",
}

btreemap_remove_blob_256_1024_v2
                        time:   [4445.9 M Instructions 4445.9 M Instructions 4445.9 M Instructions]
                        change: [-53.658% -53.658% -53.658%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_512_1024: Warming up for 1.0000 ms
2023-08-30 13:31:37.692671 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "2_483_999_494 (58%)",
    "node_save_v1": "774_958_020 (18%)",
}

btreemap_remove_blob_512_1024
                        time:   [4235.4 M Instructions 4235.4 M Instructions 4235.4 M Instructions]
                        change: [+0.8365% +0.8365% +0.8365%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Benchmarking btreemap_remove_blob_512_1024_v2: Warming up for 1.0000 ms
2023-08-30 13:31:40.372300 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "2_997_562_773 (49%)",
    "node_save_v2": "2_000_668_239 (33%)",
}

btreemap_remove_blob_512_1024_v2
                        time:   [6007.8 M Instructions 6007.8 M Instructions 6007.8 M Instructions]
                        change: [-48.537% -48.537% -48.537%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_u64_u64: Warming up for 1.0000 ms
2023-08-30 13:31:44.243827 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "348_586_038 (28%)",
    "node_save_v1": "531_727_461 (43%)",
}

btreemap_remove_u64_u64 time:   [1214.9 M Instructions 1214.9 M Instructions 1214.9 M Instructions]
                        change: [+2.9883% +2.9883% +2.9883%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_u64_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:31:46.034729 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "431_636_337 (32%)",
    "node_save_v2": "558_282_435 (42%)",
}

btreemap_remove_u64_u64_v2
                        time:   [1323.5 M Instructions 1323.5 M Instructions 1323.5 M Instructions]
                        change: [-15.942% -15.942% -15.942%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_u64_blob_8: Warming up for 1.0000 ms
2023-08-30 13:31:47.706368 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "348_727_728 (29%)",
    "node_save_v1": "503_799_202 (42%)",
}

btreemap_remove_u64_blob_8
                        time:   [1174.6 M Instructions 1174.6 M Instructions 1174.6 M Instructions]
                        change: [+3.0731% +3.0731% +3.0731%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_u64_blob_8_v2: Warming up for 1.0000 ms
2023-08-30 13:31:49.496095 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "429_769_109 (34%)",
    "node_save_v2": "512_312_460 (40%)",
}

btreemap_remove_u64_blob_8_v2
                        time:   [1263.0 M Instructions 1263.0 M Instructions 1263.0 M Instructions]
                        change: [-15.780% -15.780% -15.780%] (p = 0.00 < 0.05)
                        Performance has improved.

Benchmarking btreemap_remove_blob_8_u64: Warming up for 1.0000 ms
2023-08-30 13:31:51.208054 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v1": "353_086_064 (35%)",
    "node_save_v1": "315_283_721 (32%)",
}

btreemap_remove_blob_8_u64
                        time:   [981.11 M Instructions 981.11 M Instructions 981.11 M Instructions]
                        change: [+3.1771% +3.1771% +3.1771%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking btreemap_remove_blob_8_u64_v2: Warming up for 1.0000 ms
2023-08-30 13:31:52.832257 UTC: [Canister rwlgt-iiaaa-aaaaa-aaaaa-cai] {
    "node_load_v2": "428_189_803 (38%)",
    "node_save_v2": "380_733_306 (34%)",
}

btreemap_remove_blob_8_u64_v2
                        time:   [1118.2 M Instructions 1118.2 M Instructions 1118.2 M Instructions]
                        change: [-21.650% -21.650% -21.650%] (p = 0.00 < 0.05)
                        Performance has improved.
```
  • Loading branch information
ielashi authored Sep 5, 2023
1 parent 6d00eca commit 1f0b468
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 132 deletions.
4 changes: 2 additions & 2 deletions benchmark-canisters/src/btreemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ pub fn btreemap_remove_blob_4_1024() -> u64 {

#[query]
pub fn btreemap_remove_blob_4_1024_v2() -> u64 {
remove_blob_helper::<4, 1024>()
remove_blob_helper_v2::<4, 1024>()
}

#[query]
Expand All @@ -217,7 +217,7 @@ pub fn btreemap_remove_blob_8_1024() -> u64 {

#[query]
pub fn btreemap_remove_blob_8_1024_v2() -> u64 {
remove_blob_helper::<8, 1024>()
remove_blob_helper_v2::<8, 1024>()
}

#[query]
Expand Down
25 changes: 17 additions & 8 deletions src/btreemap/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use crate::{
use std::borrow::{Borrow, Cow};
use std::cell::{Ref, RefCell};

mod reader;
#[cfg(test)]
mod tests;
mod v1;

// V2 nodes are currently only used in tests.
#[allow(dead_code)]
mod v2;

use reader::NodeReader;

// The minimum degree to use in the btree.
// This constant is taken from Rust's std implementation of BTreeMap.
const B: usize = 6;
Expand Down Expand Up @@ -60,8 +60,7 @@ pub struct Node<K: Storable + Ord + Clone> {

// The address of the overflow page.
// In V2, a node can span multiple pages if it exceeds a certain size.
#[allow(dead_code)]
overflow: Option<Address>,
overflows: Vec<Address>,
}

impl<K: Storable + Ord + Clone> Node<K> {
Expand Down Expand Up @@ -167,10 +166,16 @@ impl<K: Storable + Ord + Clone> Node<K> {

if let Value::ByRef(offset) = values[idx] {
// Value isn't loaded yet.
let value_address = self.address + offset;
let value_len = read_u32(memory, value_address) as usize;
let reader = NodeReader {
address: self.address,
overflows: &self.overflows,
page_size: self.page_size(),
memory,
};

let value_len = read_u32(&reader, Address::from(offset.get())) as usize;
let mut value = vec![0; value_len];
memory.read((value_address + U32_SIZE).get(), &mut value);
reader.read((offset + U32_SIZE).get(), &mut value);

// Cache the value internally.
values[idx] = Value::ByVal(value);
Expand All @@ -187,6 +192,10 @@ impl<K: Storable + Ord + Clone> Node<K> {
})
}

fn page_size(&self) -> PageSize {
self.version.page_size()
}

/// Returns a reference to the key at the specified index.
pub fn key(&self, idx: usize) -> &K {
&self.keys[idx]
Expand Down
170 changes: 170 additions & 0 deletions src/btreemap/node/reader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use super::*;
use crate::btreemap::node::v2::PAGE_OVERFLOW_DATA_OFFSET;
use std::cmp::min;

/// A `NodeReader` abstracts the `Node` as a single contiguous memory, even though internally
/// it can be composed of multiple pages.
pub struct NodeReader<'a, M: Memory> {
pub address: Address,
pub overflows: &'a [Address],
pub page_size: PageSize,
pub memory: &'a M,
}

// Note: The `Memory` interface is implemented so that helper methods such `read_u32`,
// `read_struct`, etc. can be used with a `NodeReader` directly.
impl<'a, M: Memory> Memory for NodeReader<'a, M> {
fn read(&self, offset: u64, dst: &mut [u8]) {
// If the read is only in the initial page, then read it directly in one go.
// This is a performance enhancement to avoid the cost of creating a `NodeIterator`.
if (offset + dst.len() as u64) < self.page_size.get() as u64 {
self.memory.read(self.address.get() + offset, dst);
return;
}

// The read is split across several pages. Create a `NodeIterator` to to read from
// each of the individual pages.
let iter = NodeIterator::new(
VirtualSegment {
address: Address::from(offset),
length: Bytes::from(dst.len() as u64),
},
Bytes::from(self.page_size.get()),
);

let mut bytes_read = 0;
for RealSegment {
page_idx,
offset,
length,
} in iter
{
if page_idx == 0 {
self.memory.read(
(self.address + offset).get(),
&mut dst[bytes_read as usize..(bytes_read + length.get()) as usize],
);
} else {
self.memory.read(
(self.overflows[page_idx - 1] + offset).get(),
&mut dst[bytes_read as usize..(bytes_read + length.get()) as usize],
);
}

bytes_read += length.get();
}
}

fn write(&self, _: u64, _: &[u8]) {
unreachable!("NodeReader does not support write")
}

fn size(&self) -> u64 {
unreachable!("NodeReader does not support size")
}

fn grow(&self, _: u64) -> i64 {
unreachable!("NodeReader does not support grow")
}
}

#[derive(Debug)]
struct VirtualSegment {
address: Address,
length: Bytes,
}

struct RealSegment {
page_idx: usize,
offset: Bytes,
length: Bytes,
}

// An iterator that maps a segment of a node into segments of its underlying memory.
//
// A segment in a node can map to multiple segments of memory. Here's an example:
//
// Node
// --------------------------------------------------------
// (A) ---------- SEGMENT ---------- (B)
// --------------------------------------------------------
// ↑ ↑ ↑ ↑
// Page 0 Page 1 Page 2 Page 3
//
// The [`Node`] is internally divided into fixed-size pages. In the node's virtual address space,
// all these pages are consecutive, but in the underlying memory this may not be the case.
//
// A virtual segment would be split at the page boundaries. The example virtual segment
// above would be split into the following "real" segments:
//
// (A, end of page 0)
// (start of page 1, end of page 1)
// (start of page 2, B)
//
// Each of the segments above can then be translated into the real address space by looking up
// the pages' addresses in the underlying memory.
struct NodeIterator {
virtual_segment: VirtualSegment,
page_size: Bytes,

// The amount of data that can be stored in an overflow page.
overflow_page_capacity: Bytes,
}

impl NodeIterator {
#[inline]
fn new(virtual_segment: VirtualSegment, page_size: Bytes) -> Self {
Self {
virtual_segment,
page_size,
overflow_page_capacity: page_size - PAGE_OVERFLOW_DATA_OFFSET,
}
}
}

impl Iterator for NodeIterator {
type Item = RealSegment;

fn next(&mut self) -> Option<Self::Item> {
// The segment is empty. End iteration.
if self.virtual_segment.length == Bytes::from(0u64) {
return None;
}

let offset = Bytes::from(self.virtual_segment.address.get());

// Compute the page where the segment begins.
let page_idx = if offset < self.page_size {
0 // The segment begins in the initial page.
} else {
// The segment begins in an overflow page.
((offset - self.page_size) / self.overflow_page_capacity).get() + 1
};

// Compute the length of the next real segment.
// The length of the real segment is either up to the end of the page, or the end of the
// virtual segment, whichever is smaller.
let length = {
let page_end = self.page_size + self.overflow_page_capacity * page_idx;
min(page_end - offset, self.virtual_segment.length)
};

// Compute the offset within the page.
let offset = if offset < self.page_size {
offset
} else {
// The offset is in the overflow pages.
PAGE_OVERFLOW_DATA_OFFSET + (offset - self.page_size) % self.overflow_page_capacity
};

// Update the virtual segment to exclude the portion we're about to return.
self.virtual_segment.length -= length;
self.virtual_segment.address += length;

Some(RealSegment {
page_idx: page_idx as usize,
offset,
length,
})
}
}
4 changes: 2 additions & 2 deletions src/btreemap/node/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<K: Storable + Ord + Clone> Node<K> {
encoded_values: RefCell::default(),
children: vec![],
version: Version::V1(page_size),
overflow: None,
overflows: Vec::with_capacity(0),
}
}

Expand Down Expand Up @@ -116,7 +116,7 @@ impl<K: Storable + Ord + Clone> Node<K> {
max_key_size,
max_value_size,
}),
overflow: None,
overflows: Vec::with_capacity(0),
}
}

Expand Down
Loading

0 comments on commit 1f0b468

Please sign in to comment.