Skip to content

feat(prove_membership_relative_to_smaller_mmr): add spawn_blocking#937

Closed
skaunov wants to merge 1 commit into
Neptune-Crypto:masterfrom
skaunov:relativemmr_spawnblocking
Closed

feat(prove_membership_relative_to_smaller_mmr): add spawn_blocking#937
skaunov wants to merge 1 commit into
Neptune-Crypto:masterfrom
skaunov:relativemmr_spawnblocking

Conversation

@skaunov

@skaunov skaunov commented Jun 8, 2026

Copy link
Copy Markdown
Member

less starving the caller thread plus parallelizing PeerLoopHandler::batch_response

@codspeed-hq

codspeed-hq Bot commented Jun 8, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks


Comparing skaunov:relativemmr_spawnblocking (7f01499) with master (f0fb02a)

Open in CodSpeed

@skaunov skaunov requested review from Sword-Smith and aszepieniec and removed request for Sword-Smith June 8, 2026 16:55
less starving the caller thread
while parallelizing `PeerLoopHandler::batch_response`
@skaunov skaunov force-pushed the relativemmr_spawnblocking branch from f11889b to 7f01499 Compare June 8, 2026 17:37
@skaunov skaunov changed the title feat: add spawn_blocking to prove_membership_relative_to_smaller_mmr feat(prove_membership_relative_to_smaller_mmr): add spawn_blocking Jun 9, 2026
Comment on lines +288 to 291
let node_indices =
tokio::task::spawn_blocking(move || auth_path_node_indices(num_leafs, leaf_index))
.await?;
let ap_elements = self.digests.get_many(&node_indices).await;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually make a difference? Will the peer_loop not just stay blocked, waiting for the spawned task to finish? Each peer loop already runs in their own, individual tasks (read: thread), so the call to auth_path_node_indices doesn't block other peer loops.

@skaunov skaunov Jun 10, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the context! I did not think about it from that angle: it just looked to me as a book example of spawn_blocking though I'm not sure if this is computational enough (though seems so to me, or I would not bother). X)

So about the tasks. Ain't a scheduler expects a task to yield anyway, and while it only brute blocking its own task (though this is just a function: it can be used in the other contexts), it still a bit starves its scheduler as it's not happy to do its job along computing this thing? Sorry for such a long question but it's sincere question.

P.s. I got into auth_path_node_indices once more, and now feel like I overestimated it computations. So I'm confused on this terminally. Thank you for bearing with me here!

@Sword-Smith

Copy link
Copy Markdown
Member

Not convinced of this. Please reopen if you see a good reason to.

@skaunov

skaunov commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

IIRC there are quite few level of indirection in the function to quickly grasp what amount of computing does it do. That's why I was asking your help to wrap my head around this. I mean would be glad to understand this better.

Until then let me just assume that as the thing is generally logarithmic it's a non-issue. (Though from the place where the changes are proposed it look like textbook candidate for this to not get in the way for example of work stealing.)

@Sword-Smith

Sword-Smith commented Jun 29, 2026

Copy link
Copy Markdown
Member

The function looks incredibly fast to me. leaf_index_to_mt_index_and_peak_index and leaf_index_to_node_index both run in constant time and all the code prior to the while loop is probably less than 100 instructions, so maybe 10ns. The body of the while-loop is also extremely fast, where each lines reduces to maximum 10 basic CPU instructions. So even if the Merkle tree height is 63 (it's maximum possible value), the whole function is most likely less than 2000 instructions, meaning it should run in less than 1µs.

You could benhcmark the function if you think I'm wrong.

pub fn auth_path_node_indices(num_leafs: u64, leaf_index: u64) -> Vec<u64> {
    assert!(
        leaf_index < num_leafs,
        "Leaf index out-of-bounds: {leaf_index}/{num_leafs}"
    );

    let (mut merkle_tree_index, _) = leaf_index_to_mt_index_and_peak_index(leaf_index, num_leafs);
    let mut node_index = leaf_index_to_node_index(leaf_index);
    let mut height = 0;
    let tree_height = u64::BITS - merkle_tree_index.leading_zeros() - 1;
    let mut ret = Vec::with_capacity(tree_height as usize);
    while merkle_tree_index > 1 {
        let is_left_sibling = merkle_tree_index & 1 == 0;
        let height_pow = 1u64 << (height + 1);
        let as_1_or_minus_1: u64 = (2 * (is_left_sibling as i64) - 1) as u64;
        let signed_height_pow = height_pow.wrapping_mul(as_1_or_minus_1);
        let sibling = node_index
            .wrapping_add(signed_height_pow)
            .wrapping_sub(as_1_or_minus_1);

        node_index += 1 << ((height + 1) * is_left_sibling as u32);

        ret.push(sibling);
        merkle_tree_index >>= 1;
        height += 1;
    }

    debug_assert_eq!(tree_height, ret.len() as u32, "Allocation must be optimal");

    ret
}

If you're looking for bottlenecks in neptune-core, it's all things related to proving (Triton VM), and whenever a whole block has to be loaded from disk.

@skaunov

skaunov commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

Thank you for swift explanation!!

I got here after spawning blocking another call, and as I'm using this function there as well, was thinking that may be it's similar. But got a bit lost in what got called during this one. (If I'm getting the things right, some membership proving functions are quite heavy.) Then after your review I started to get how logarithmic this one is, but still was confused. And now I'm sure, and can get the logic better (will take a couple of looks into this part)! So thank you again!

@Sword-Smith

Sword-Smith commented Jun 30, 2026

Copy link
Copy Markdown
Member

IIRC, the maintenance of removal records is also quite slow. So if you're looking to speed up the mutator set code, that would be a good place to look.

@skaunov

skaunov commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

Will note it too, thank you! Feel like closing #903 first though. 🏁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants