Skip to content

input: reduce memory allocation for ScriptBuilder#7464

Merged
Roasbeef merged 5 commits intolightningnetwork:masterfrom
guggero:script-builder-capacity
Apr 11, 2023
Merged

input: reduce memory allocation for ScriptBuilder#7464
Roasbeef merged 5 commits intolightningnetwork:masterfrom
guggero:script-builder-capacity

Conversation

@guggero
Copy link
Copy Markdown
Collaborator

@guggero guggero commented Feb 27, 2023

Depends on btcsuite/btcd#1954.

I got this heap profile from a user and noticed the NewScriptBuilder showing up with massive allocations:

Screenshot from 2023-02-27 12-50-45

It turns out that function allocates 500 bytes of memory for each script, even if we only end up using about 20-140 bytes for most of our scripts.
I added a new functional option to specify the initial allocation and used that for all our scripts.

The difference is quite significant, it looks like we can save almost 50% of allocation space.

Before optimization:

BenchmarkScriptBuilderAlloc
BenchmarkScriptBuilderAlloc-24    	      14	 100126013 ns/op	14200361 B/op	  128001 allocs/op


After optimization:
BenchmarkScriptBuilderAlloc
BenchmarkScriptBuilderAlloc-24    	      13	  97141019 ns/op	 7208551 B/op	  162001 allocs/op

@guggero guggero force-pushed the script-builder-capacity branch from acf9d10 to 33f27ed Compare February 27, 2023 11:59
Copy link
Copy Markdown
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

Very nice!! Running benchmarks locally and confirming the results,

> benchstat old.prof new.prof
goos: darwin
goarch: arm64
pkg: github.com/lightningnetwork/lnd/input
                      │  old.prof   │              new.prof              │
                      │   sec/op    │   sec/op     vs base               │
ScriptBuilderAlloc-10   15.03m ± 4%   14.44m ± 0%  -3.93% (p=0.000 n=10)


                      │   old.prof    │               new.prof               │
                      │     B/op      │     B/op      vs base                │
ScriptBuilderAlloc-10   12.138Mi ± 0%   5.989Mi ± 0%  -50.66% (p=0.000 n=10)


                      │  old.prof   │               new.prof               │
                      │  allocs/op  │  allocs/op    vs base                │
ScriptBuilderAlloc-10   94.00k ± 0%   128.00k ± 0%  +36.17% (p=0.000 n=10)

This is LGTM once the mod is updated🎉

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.

Got curious so I ran a version without the require.Len, and the results got slightly better with a 52.34% reduction in bytes per operation.

goos: darwin
goarch: arm64
pkg: github.com/lightningnetwork/lnd/input
                      │  old.prof   │              new.prof              │
                      │   sec/op    │   sec/op     vs base               │
ScriptBuilderAlloc-10   8.944m ± 2%   8.882m ± 2%  -0.69% (p=0.023 n=10)

                      │   old.prof    │               new.prof               │
                      │     B/op      │     B/op      vs base                │
ScriptBuilderAlloc-10   11.749Mi ± 0%   5.600Mi ± 0%  -52.34% (p=0.000 n=10)

                      │  old.prof   │               new.prof               │
                      │  allocs/op  │  allocs/op    vs base                │
ScriptBuilderAlloc-10   77.00k ± 0%   111.00k ± 0%  +44.16% (p=0.000 n=10)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Did you just run it like this?

	_, err = WitnessScriptHash(dummyData)
	require.NoError(t, err)

I think the compiler just optimizes away the return value, since it's not used. Could that explain the further 52% reduction?

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.

I think require.Len needs to put the value on the stack since it's referenced outside the function. Validated with a dummy test, which showed no alloc,

script, err = CommitScriptAnchor(randomPub)
require.NoError(t, err)
script[0] = 1 // make a dummy usage of the returned value

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Okay, I refactored the test a little bit to not use require inside the benchmark. Not sure if this is any better.

@guggero guggero force-pushed the script-builder-capacity branch from 33f27ed to 3352b9e Compare February 28, 2023 18:56
Copy link
Copy Markdown
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

tACK🎉Thanks for the PR! (the linter needs to be fixed tho)

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.

I think require.Len needs to put the value on the stack since it's referenced outside the function. Validated with a dummy test, which showed no alloc,

script, err = CommitScriptAnchor(randomPub)
require.NoError(t, err)
script[0] = 1 // make a dummy usage of the returned value

@guggero guggero force-pushed the script-builder-capacity branch from 3352b9e to 791e02f Compare March 1, 2023 08:15
@guggero guggero added this to the v0.16.1 milestone Mar 13, 2023
@guggero guggero force-pushed the script-builder-capacity branch from 791e02f to f246161 Compare March 14, 2023 12:00
@guggero guggero changed the base branch from master to 0-16-1-staging March 14, 2023 12:00
@guggero
Copy link
Copy Markdown
Collaborator Author

guggero commented Mar 14, 2023

Changed the base branch to 0-16-1-staging so this can be merged.

@guggero guggero requested a review from ffranr March 14, 2023 12:01
Copy link
Copy Markdown
Collaborator

@ffranr ffranr left a comment

Choose a reason for hiding this comment

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

Look like worth while changes! 🥳

@guggero guggero force-pushed the script-builder-capacity branch 3 times, most recently from 92a7d60 to b2ce7ff Compare March 29, 2023 12:01
@saubyk saubyk requested a review from ffranr March 30, 2023 15:20
@lightninglabs-deploy
Copy link
Copy Markdown
Collaborator

@ffranr: review reminder

@Roasbeef Roasbeef changed the base branch from 0-16-1-staging to master April 11, 2023 00:00
Copy link
Copy Markdown
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

Nice optimization work! Only comment is if we can reuse some of the existing size estimate constants instead of plugging magic numbers into the prealloc arg.

LGTM 🍦

guggero added 5 commits April 11, 2023 10:33
The default allocation of 500 bytes for the script that is
used in NewScriptBuilder is way too much for most of our scripts.
With the new functional option we can tune the allocation to exactly
what we need.
@guggero guggero force-pushed the script-builder-capacity branch from b2ce7ff to 26254d0 Compare April 11, 2023 09:15
@guggero guggero requested a review from Roasbeef April 11, 2023 09:17
Copy link
Copy Markdown
Collaborator

@ffranr ffranr left a comment

Choose a reason for hiding this comment

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

Nice work 👍

Copy link
Copy Markdown
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM 🎨

@Roasbeef Roasbeef merged commit 158e93f into lightningnetwork:master Apr 11, 2023
@guggero guggero deleted the script-builder-capacity branch April 12, 2023 07:21
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.

5 participants