Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libplugin-pay: use map for channel hints #7636

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

JssDWt
Copy link
Contributor

@JssDWt JssDWt commented Sep 3, 2024

libplugin-pay: use map for channel hints

Description

This commit fixes a "FIXME: This is slow" in the pay plugin. For nodes with many channels this is a tremendous improvement in pay performance. PR #7611 improves payment performance from 15 seconds to 13.5 seconds on one of our nodes. This commit improves payment performance from 13.5 seconds to 5.7 seconds.

Changes Made

  • Feature: Brief description of the new feature or functionality added.
  • Bug Fix: Brief description of the bug fixed and how it was resolved.
  • Refactor: Any code improvements or refactoring done without changing the functionality.

Checklist

Ensure the following tasks are completed before submitting the PR:

  • Changelog has been added in relevant commit/s.
  • Tests have been added or updated to cover the changes.
  • Documentation has been updated as needed.
  • Any relevant comments or TODOs have been addressed or removed.

@JssDWt JssDWt force-pushed the jssdwt-improve-pay-performance branch from 2c0a1c5 to f23b2d9 Compare September 3, 2024 19:12
@JssDWt JssDWt marked this pull request as ready for review September 3, 2024 20:04
@JssDWt JssDWt force-pushed the jssdwt-improve-pay-performance branch from f23b2d9 to b333c66 Compare September 3, 2024 20:12
plugins/libplugin-pay.h Outdated Show resolved Hide resolved
if (!short_channel_id_eq(hints[j].scid.scid, r->short_channel_id))
struct channel_hint *hint;
struct channel_hint_map_iter iter;
for (hint = channel_hint_map_first(hints, &iter);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why loop over the hash map here? Couldn't we use lookup by hash?

Copy link
Contributor Author

@JssDWt JssDWt Sep 4, 2024

Choose a reason for hiding this comment

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

The channel_hint_map is indexed by scid and direction, while here we only have the scid. An alternative could be to make a channel hint map based on scid only, with a struct with 2 fields for the different directions. Then we wouldn't have to iterate here.

This part of the code is used once per path though, and not with every step of the dijkstra procedure. The things fixed in this PR were called approximately 35000 times per payment, while this one is called once per payment. So the performance overhead is a lot less.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually it seems like we should be able to get the hint by getting from the channel hints map with 0 or 1 direction. I'll dig which one to use here. It seems weird that the direction wasn't used before, you could have gotten the route hint in the wrong direction and assumed the routehint was excluded 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

Once per payment is not bad, I have no issues with leaving the loop here.

But the direction of the hint (the r) is already defined by the ordering of the nodes on both ends of the channel.
I think the previous code was lazy to check only the short channel id, maybe considering that we usually get information
about channels in one direction and rarely we get the other direction. IDK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Lagrang3 I added a commit that attempts to get the route hint from the map directly. Can you check that out? Especially the pubkeys used for the comparison there.

plugins/libplugin-pay.c Outdated Show resolved Hide resolved
This commit fixes a "FIXME: This is slow" in the pay plugin. For
nodes with many channels this is a tremendous improvement in pay
performance. PR ElementsProject#7611 improves payment performance from 15 seconds to
13.5 seconds on one of our nodes. This commit improves payment
performance from 13.5 seconds to 5.7 seconds.

Changelog-Fixed: Improved pathfinding speed for large nodes.
@JssDWt JssDWt force-pushed the jssdwt-improve-pay-performance branch from b333c66 to 94babc2 Compare September 4, 2024 08:52
@Lagrang3
Copy link
Collaborator

Lagrang3 commented Sep 4, 2024

BTW this 2x improvement in runtime is great! Do you know how big was this array of hints typically? I thought these hints were gathered on a per payment basis and hence there wasn't supposed to be many of them.

@JssDWt
Copy link
Contributor Author

JssDWt commented Sep 4, 2024

BTW this 2x improvement in runtime is great! Do you know how big was this array of hints typically? I thought these hints were gathered on a per payment basis and hence there wasn't supposed to be many of them.

Thing is your own private channels are part of the hints. Being a LSP, the node has many private channels. In this case close to 2000.

Comment on lines +2914 to +2915
scidd.dir = node_id_cmp(&routehint->pubkey,
p->pay_destination) > 0 ? 1 : 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think something like this should do the trick.

Suggested change
scidd.dir = node_id_cmp(&routehint->pubkey,
p->pay_destination) > 0 ? 1 : 0;
scidd.dir = node_id_idx(&r->pubkey, p->pay_destination);

Also notice that I replaced routehint with r.

@cdecker
Copy link
Member

cdecker commented Sep 4, 2024

This conflicts with #7494 which essentially replaces the entire channel_hint handling, and encapsulates it in a separate file (and adds the channel_hint_set struct which is very similar to channel_hint_map here). This will likely need to be rebased on top of #7494

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.

4 participants