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

lnwire: fix heap escapes to reduce gc pressure #4884

Merged
merged 11 commits into from
Aug 11, 2021

Conversation

yyforyongyu
Copy link
Member

@yyforyongyu yyforyongyu commented Dec 24, 2020

This PR is meant to fix #3004.

The overall optimization is done in three steps,

  • change WriteMessage to use write buffer.
  • change Encode and WriteElement to use write buffer.
  • replace interface types with concrete types inside Encode.

The result,

name                                    old time/op    new time/op    delta
WriteMessage/Init-4                       3.62µs ±25%    2.29µs ±11%   -36.70%  (p=0.000 n=10+10)
WriteMessage/Error-4                      1.03µs ±10%    0.37µs ± 9%   -63.94%  (p=0.000 n=10+10)
WriteMessage/Ping-4                        977ns ±17%     352ns ± 7%   -63.98%  (p=0.000 n=10+10)
WriteMessage/Pong-4                        834ns ± 1%     336ns ± 3%   -59.72%  (p=0.000 n=8+10)
WriteMessage/MsgOpenChannel-4             3.54µs ± 0%    1.65µs ± 3%   -53.30%  (p=0.000 n=7+10)
WriteMessage/MsgAcceptChannel-4           3.03µs ± 4%    1.65µs ± 2%   -45.48%  (p=0.000 n=10+9)
WriteMessage/MsgFundingCreated-4          1.34µs ± 0%    0.36µs ± 1%   -73.36%  (p=0.000 n=6+10)
WriteMessage/MsgFundingSigned-4           1.26µs ± 3%    0.34µs ± 1%   -73.00%  (p=0.000 n=9+10)
WriteMessage/FundingLocked-4              1.21µs ± 1%    0.45µs ± 1%   -62.51%  (p=0.000 n=8+9)
WriteMessage/Shutdown-4                   1.01µs ± 1%    0.34µs ± 3%   -66.18%  (p=0.000 n=9+10)
WriteMessage/ClosingSigned-4              1.17µs ± 2%    0.37µs ± 3%   -68.86%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4              2.21µs ± 1%    0.38µs ± 1%   -82.71%  (p=0.000 n=8+8)
WriteMessage/UpdateFulfillHTLC-4          1.14µs ± 2%    0.33µs ± 0%   -70.66%  (p=0.000 n=9+9)
WriteMessage/UpdateFailHTLC-4             1.01µs ± 1%    0.35µs ± 2%   -65.60%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  11.8µs ± 2%     1.4µs ± 1%   -88.00%  (p=0.000 n=9+9)
WriteMessage/RevokeAndAck-4               1.26µs ± 1%    0.47µs ± 2%   -63.02%  (p=0.000 n=9+9)
WriteMessage/UpdateFee-4                   960ns ± 1%     329ns ± 1%   -65.69%  (p=0.000 n=8+10)
WriteMessage/UpdateFailMalformedHTLC-4    1.19µs ± 1%    0.35µs ± 2%   -70.95%  (p=0.000 n=9+10)
WriteMessage/ChannelReestablish-4         1.34µs ± 1%    0.48µs ± 1%   -63.74%  (p=0.000 n=8+9)
WriteMessage/ChannelAnnouncement-4        3.01µs ± 1%    1.23µs ± 2%   -59.27%  (p=0.000 n=10+9)
WriteMessage/NodeAnnouncement-4           3.33µs ± 3%    2.99µs ± 1%   -10.37%  (p=0.000 n=9+9)
WriteMessage/ChannelUpdate-4              1.42µs ± 1%    0.43µs ± 9%   -69.71%  (p=0.000 n=9+9)
WriteMessage/AnnounceSignatures-4         1.45µs ± 7%    0.40µs ±12%   -72.19%  (p=0.000 n=9+10)
WriteMessage/QueryShortChanIDs-4           161µs ± 7%      75µs ± 2%   -53.30%  (p=0.000 n=9+10)
WriteMessage/ReplyShortChanIDsEnd-4        917ns ± 1%     326ns ± 1%   -64.41%  (p=0.000 n=9+9)
WriteMessage/QueryChannelRange-4           975ns ± 1%     337ns ± 1%   -65.49%  (p=0.000 n=8+9)
WriteMessage/ReplyChannelRange-4           145µs ± 1%      74µs ± 1%   -48.87%  (p=0.000 n=9+10)
WriteMessage/GossipTimestampRange-4       1.01µs ±10%    0.34µs ± 1%   -66.38%  (p=0.000 n=10+9)
WriteMessage/QueryShortChanIDs#01-4        712µs ±23%     408µs ± 3%   -42.65%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        681µs ± 3%     406µs ± 2%   -40.40%  (p=0.000 n=9+9)

name                                    old alloc/op   new alloc/op   delta
WriteMessage/Init-4                       1.33kB ± 0%    0.02kB ± 0%   -98.80%  (p=0.000 n=10+10)
WriteMessage/Error-4                      1.36kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                       1.30kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                       1.29kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4             5.84kB ± 0%    1.75kB ± 0%   -70.00%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4           4.57kB ± 0%    1.75kB ± 0%   -61.65%  (p=0.000 n=9+10)
WriteMessage/MsgFundingCreated-4          1.82kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4           1.95kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4              1.94kB ± 0%    0.08kB ± 0%   -95.87%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                   1.40kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4              1.98kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4              7.14kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4          1.84kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4             1.40kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  29.2kB ± 0%     0.0kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4               1.96kB ± 0%    0.08kB ± 0%   -95.92%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                  1.39kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4    1.85kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4         1.98kB ± 0%    0.08kB ± 0%   -95.97%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4        3.80kB ± 0%    0.01kB ± 0%   -99.79%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4           3.16kB ± 0%    0.09kB ± 0%   -97.22%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4              1.95kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4         2.11kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4          64.2kB ± 0%     0.1kB ± 1%   -99.86%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4       1.34kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4          1.36kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4          64.2kB ± 0%     0.1kB ± 0%   -99.86%  (p=0.000 n=10+8)
WriteMessage/GossipTimestampRange-4       1.36kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        876kB ± 0%     841kB ± 0%    -3.95%  (p=0.000 n=7+10)
WriteMessage/ReplyChannelRange#01-4        876kB ± 0%     841kB ± 0%    -3.95%  (p=0.000 n=9+10)

name                                    old allocs/op  new allocs/op  delta
WriteMessage/Init-4                         10.0 ± 0%       4.0 ± 0%   -60.00%  (p=0.000 n=10+10)
WriteMessage/Error-4                        8.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                         8.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                         6.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4               55.0 ± 0%      19.0 ± 0%   -65.45%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4             48.0 ± 0%      19.0 ± 0%   -60.42%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            13.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             11.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                12.0 ± 0%       2.0 ± 0%   -83.33%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     10.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                13.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                18.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            12.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               11.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                     217 ± 0%         0       -100.00%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 13.0 ± 0%       2.0 ± 0%   -84.62%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    10.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      15.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           17.0 ± 0%       2.0 ± 0%   -88.24%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          31.0 ± 0%       2.0 ± 0%   -93.55%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             39.0 ± 0%       4.0 ± 0%   -89.74%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                27.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           17.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           4.02k ± 0%     0.00k ± 0%   -99.93%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4         8.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4            11.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4           4.02k ± 0%     0.00k ± 0%   -99.93%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4         11.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        4.04k ± 0%     0.03k ± 0%   -99.18%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        4.04k ± 0%     0.03k ± 0%   -99.18%  (p=0.000 n=10+10)

Top heap allocs,

(pprof) top
Showing nodes accounting for 79.53GB, 98.26% of 80.94GB total
Dropped 61 nodes (cum <= 0.40GB)
Showing top 10 nodes out of 39
      flat  flat%   sum%        cum   cum%
   37.77GB 46.66% 46.66%    45.84GB 56.64%  compress/flate.NewWriter
   15.61GB 19.28% 65.94%    17.82GB 22.02%  github.com/lightningnetwork/lnd/lnwire.packShutdownScript
    8.87GB 10.96% 76.91%    14.73GB 18.20%  github.com/btcsuite/btcd/btcec.(*PublicKey).SerializeCompressed
    7.84GB  9.69% 86.60%     7.84GB  9.69%  compress/flate.(*compressor).initDeflate (inline)
    5.86GB  7.24% 93.83%     5.86GB  7.24%  math/big.(*Int).Bytes (inline)
    1.57GB  1.94% 95.78%     1.57GB  1.94%  bytes.makeSlice
    0.88GB  1.08% 96.86%     2.45GB  3.03%  bytes.(*Buffer).grow
    0.66GB  0.81% 97.67%     1.98GB  2.45%  github.com/lightningnetwork/lnd/lnwire.(*ExtraOpaqueData).PackRecords
    0.46GB  0.57% 98.24%     0.46GB  0.57%  github.com/lightningnetwork/lnd/tlv.NewStream
    0.02GB 0.021% 98.26%    47.87GB 59.14%  github.com/lightningnetwork/lnd/lnwire.encodeShortChanIDs

Build the benchmark

This first step is to build the benchmark for our optimization. Run the following commands to build the profiles. Notice that we need to run the bench test multiple times (I've chosen 10) to gather meaningful statistics for benchstat to analyze.

cd lnwire

gco 0c409c59

go test -run=^$ -bench=Write -count=10 -benchmem -memprofile=write-mem-base.prof -cpuprofile=write-cpu-base.prof -o lnwire-base.test | tee write-bench-base.prof

Now we can check the heap allocs using,

go tool pprof --sample_index=alloc_space lnwire-base.test write-mem-base.prof

And checking the heap escapes using go build -gcflags "-m -m".

First optimiztion - Using write buffer in WriteMessage

Run the following commands to gather stats.

gco e2a51cf2

go test -run=^$ -bench=Write -count=10 -benchmem -memprofile=write-mem-1.prof -cpuprofile=write-cpu-1.prof -o lnwire-1.test | tee write-bench-1.prof

See the improvement,

benchstat write-bench-base.prof write-bench-1.prof
name                                    old time/op    new time/op    delta
WriteMessage/Init-4                       3.62µs ±25%    2.36µs ± 5%  -34.81%  (p=0.000 n=10+8)
WriteMessage/Error-4                      1.03µs ±10%    0.53µs ±16%  -48.73%  (p=0.000 n=10+9)
WriteMessage/Ping-4                        977ns ±17%     709ns ±46%  -27.37%  (p=0.001 n=10+10)
WriteMessage/Pong-4                        834ns ± 1%     483ns ± 5%  -42.13%  (p=0.000 n=8+8)
WriteMessage/MsgOpenChannel-4             3.54µs ± 0%    3.05µs ±16%  -13.78%  (p=0.000 n=7+8)
WriteMessage/MsgAcceptChannel-4           3.03µs ± 4%    2.41µs ±13%  -20.72%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4          1.34µs ± 0%    0.74µs ±12%  -44.88%  (p=0.000 n=6+9)
WriteMessage/MsgFundingSigned-4           1.26µs ± 3%    0.72µs ±24%  -42.60%  (p=0.000 n=9+10)
WriteMessage/FundingLocked-4              1.21µs ± 1%    0.82µs ±19%  -32.25%  (p=0.000 n=8+9)
WriteMessage/Shutdown-4                   1.01µs ± 1%    0.62µs ±10%  -38.19%  (p=0.000 n=9+10)
WriteMessage/ClosingSigned-4              1.17µs ± 2%    0.69µs ± 7%  -41.31%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4              2.21µs ± 1%    0.75µs ± 1%  -66.32%  (p=0.000 n=8+8)
WriteMessage/UpdateFulfillHTLC-4          1.14µs ± 2%    0.63µs ± 5%  -44.89%  (p=0.000 n=9+10)
WriteMessage/UpdateFailHTLC-4             1.01µs ± 1%    0.64µs ± 9%  -36.30%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  11.8µs ± 2%     8.9µs ± 9%  -24.86%  (p=0.000 n=9+10)
WriteMessage/RevokeAndAck-4               1.26µs ± 1%    0.80µs ± 9%  -36.21%  (p=0.000 n=9+10)
WriteMessage/UpdateFee-4                   960ns ± 1%     626ns ±17%  -34.80%  (p=0.000 n=8+10)
WriteMessage/UpdateFailMalformedHTLC-4    1.19µs ± 1%    0.73µs ± 7%  -38.80%  (p=0.000 n=9+8)
WriteMessage/ChannelReestablish-4         1.34µs ± 1%    0.92µs ± 8%  -31.42%  (p=0.000 n=8+8)
WriteMessage/ChannelAnnouncement-4        3.01µs ± 1%    2.28µs ± 7%  -24.15%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4           3.33µs ± 3%    2.53µs ± 0%  -24.01%  (p=0.000 n=9+8)
WriteMessage/ChannelUpdate-4              1.42µs ± 1%    0.95µs ± 6%  -32.92%  (p=0.000 n=9+10)
WriteMessage/AnnounceSignatures-4         1.45µs ± 7%    0.93µs ±11%  -35.66%  (p=0.000 n=9+8)
WriteMessage/QueryShortChanIDs-4           161µs ± 7%     155µs ±12%     ~     (p=0.400 n=9+10)
WriteMessage/ReplyShortChanIDsEnd-4        917ns ± 1%     630ns ±21%  -31.24%  (p=0.000 n=9+10)
WriteMessage/QueryChannelRange-4           975ns ± 1%     655ns ±11%  -32.82%  (p=0.000 n=8+9)
WriteMessage/ReplyChannelRange-4           145µs ± 1%     146µs ± 9%     ~     (p=1.000 n=9+9)
WriteMessage/GossipTimestampRange-4       1.01µs ±10%    0.58µs ± 4%  -42.41%  (p=0.000 n=10+8)
WriteMessage/QueryShortChanIDs#01-4        712µs ±23%     762µs ± 4%     ~     (p=0.122 n=10+8)
WriteMessage/ReplyChannelRange#01-4        681µs ± 3%     600µs ±10%  -11.81%  (p=0.000 n=9+10)

name                                    old alloc/op   new alloc/op   delta
WriteMessage/Init-4                       1.33kB ± 0%    0.06kB ± 0%  -95.18%  (p=0.000 n=10+10)
WriteMessage/Error-4                      1.36kB ± 0%    0.09kB ± 0%  -93.36%  (p=0.000 n=10+10)
WriteMessage/Ping-4                       1.30kB ± 0%    0.03kB ± 0%  -97.69%  (p=0.000 n=10+10)
WriteMessage/Pong-4                       1.29kB ± 0%    0.03kB ± 0%  -97.99%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4             5.84kB ± 0%    2.26kB ± 0%  -61.37%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4           4.57kB ± 0%    2.19kB ± 0%  -52.01%  (p=0.000 n=9+10)
WriteMessage/MsgFundingCreated-4          1.82kB ± 0%    0.28kB ± 0%  -84.51%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4           1.95kB ± 0%    0.24kB ± 0%  -87.72%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4              1.94kB ± 0%    0.24kB ± 0%  -87.62%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                   1.40kB ± 0%    0.14kB ± 0%  -90.17%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4              1.98kB ± 0%    0.26kB ± 0%  -87.04%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4              7.14kB ± 0%    0.21kB ± 0%  -97.09%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4          1.84kB ± 0%    0.15kB ± 0%  -91.74%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4             1.40kB ± 0%    0.14kB ± 0%  -90.29%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  29.2kB ± 0%    13.1kB ± 0%  -55.22%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4               1.96kB ± 0%    0.26kB ± 0%  -86.54%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                  1.39kB ± 0%    0.12kB ± 0%  -91.35%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4    1.85kB ± 0%    0.17kB ± 0%  -90.91%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4         1.98kB ± 0%    0.30kB ± 0%  -85.08%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4        3.80kB ± 0%    1.00kB ± 0%  -73.68%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4           3.16kB ± 0%    0.79kB ± 0%  -75.06%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4              1.95kB ± 0%    0.27kB ± 0%  -86.07%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4         2.11kB ± 0%    0.39kB ± 0%  -81.29%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4          64.2kB ± 0%    26.8kB ± 0%  -58.21%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4       1.34kB ± 0%    0.07kB ± 0%  -94.55%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4          1.36kB ± 0%    0.09kB ± 0%  -93.51%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4          64.2kB ± 0%    26.8kB ± 0%  -58.20%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4       1.36kB ± 0%    0.09kB ± 0%  -93.51%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        876kB ± 0%     849kB ± 0%   -3.05%  (p=0.000 n=7+10)
WriteMessage/ReplyChannelRange#01-4        876kB ± 0%     849kB ± 0%   -3.05%  (p=0.000 n=9+10)

name                                    old allocs/op  new allocs/op  delta
WriteMessage/Init-4                         10.0 ± 0%       6.0 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/Error-4                        8.00 ± 0%      4.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                         8.00 ± 0%      4.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                         6.00 ± 0%      2.00 ± 0%  -66.67%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4               55.0 ± 0%      48.0 ± 0%  -12.73%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4             48.0 ± 0%      42.0 ± 0%  -12.50%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            13.0 ± 0%       8.0 ± 0%  -38.46%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             11.0 ± 0%       6.0 ± 0%  -45.45%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                12.0 ± 0%       7.0 ± 0%  -41.67%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     10.0 ± 0%       6.0 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                13.0 ± 0%       8.0 ± 0%  -38.46%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                18.0 ± 0%      12.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            12.0 ± 0%       7.0 ± 0%  -41.67%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               11.0 ± 0%       7.0 ± 0%  -36.36%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                     217 ± 0%       208 ± 0%   -4.15%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 13.0 ± 0%       8.0 ± 0%  -38.46%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    10.0 ± 0%       6.0 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      15.0 ± 0%      10.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           17.0 ± 0%      12.0 ± 0%  -29.41%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          31.0 ± 0%      25.0 ± 0%  -19.35%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             39.0 ± 0%      33.0 ± 0%  -15.38%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                27.0 ± 0%      22.0 ± 0%  -18.52%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           17.0 ± 0%      12.0 ± 0%  -29.41%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           4.02k ± 0%     4.01k ± 0%   -0.27%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4         8.00 ± 0%      4.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4            11.0 ± 0%       7.0 ± 0%  -36.36%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4           4.02k ± 0%     4.01k ± 0%   -0.27%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4         11.0 ± 0%       7.0 ± 0%  -36.36%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        4.04k ± 0%     4.03k ± 0%   -0.12%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        4.04k ± 0%     4.03k ± 0%   -0.12%  (p=0.000 n=10+10)

Second optimiztion - Using write buffer in Encode

Run the following commands to gather stats.

gco 7c0e6d4b

go test -run=^$ -bench=Write -count=10 -benchmem -memprofile=write-mem-2.prof -cpuprofile=write-cpu-2.prof -o lnwire-2.test | tee write-bench-2.prof

See incremental gain,

benchstat write-bench-1.prof write-bench-2.prof
name                                    old time/op    new time/op    delta
WriteMessage/Init-4                       2.36µs ± 5%    2.65µs ±31%     ~     (p=0.068 n=8+10)
WriteMessage/Error-4                       526ns ±16%     564ns ±11%   +7.21%  (p=0.043 n=9+10)
WriteMessage/Ping-4                        709ns ±46%     479ns ± 9%  -32.45%  (p=0.000 n=10+10)
WriteMessage/Pong-4                        483ns ± 5%     535ns ±25%     ~     (p=0.074 n=8+9)
WriteMessage/MsgOpenChannel-4             3.05µs ±16%    2.31µs ±26%  -24.41%  (p=0.000 n=8+9)
WriteMessage/MsgAcceptChannel-4           2.41µs ±13%    1.96µs ± 1%  -18.43%  (p=0.000 n=10+9)
WriteMessage/MsgFundingCreated-4           737ns ±12%     843ns ±33%     ~     (p=1.000 n=9+10)
WriteMessage/MsgFundingSigned-4            722ns ±24%     615ns ±11%  -14.75%  (p=0.002 n=10+8)
WriteMessage/FundingLocked-4               817ns ±19%     682ns ±15%  -16.52%  (p=0.000 n=9+10)
WriteMessage/Shutdown-4                    622ns ±10%     548ns ±10%  -12.01%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4               689ns ± 7%     624ns ±16%   -9.41%  (p=0.015 n=10+10)
WriteMessage/UpdateAddHTLC-4               746ns ± 1%     708ns ± 8%   -5.09%  (p=0.006 n=8+9)
WriteMessage/UpdateFulfillHTLC-4           629ns ± 5%     591ns ± 3%   -6.04%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4              641ns ± 9%     562ns ± 7%  -12.32%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  8.89µs ± 9%    5.02µs ± 2%  -43.51%  (p=0.000 n=10+9)
WriteMessage/RevokeAndAck-4                802ns ± 9%     710ns ± 9%  -11.47%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                   626ns ±17%     528ns ± 5%  -15.66%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4     728ns ± 7%     621ns ± 2%  -14.76%  (p=0.000 n=8+8)
WriteMessage/ChannelReestablish-4          917ns ± 8%     736ns ± 9%  -19.73%  (p=0.000 n=8+10)
WriteMessage/ChannelAnnouncement-4        2.28µs ± 7%    1.77µs ± 1%  -22.47%  (p=0.000 n=10+9)
WriteMessage/NodeAnnouncement-4           2.53µs ± 0%    2.35µs ± 9%   -7.01%  (p=0.033 n=8+10)
WriteMessage/ChannelUpdate-4               950ns ± 6%     738ns ± 1%  -22.32%  (p=0.000 n=10+9)
WriteMessage/AnnounceSignatures-4          930ns ±11%     659ns ±14%  -29.15%  (p=0.000 n=8+10)
WriteMessage/QueryShortChanIDs-4           155µs ±12%     105µs ±13%  -32.56%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4        630ns ±21%     702ns ±47%     ~     (p=0.529 n=10+10)
WriteMessage/QueryChannelRange-4           655ns ±11%     845ns ±40%     ~     (p=0.133 n=9+10)
WriteMessage/ReplyChannelRange-4           146µs ± 9%     135µs ±40%     ~     (p=0.243 n=9+10)
WriteMessage/GossipTimestampRange-4        584ns ± 4%     553ns ± 6%   -5.22%  (p=0.001 n=8+10)
WriteMessage/QueryShortChanIDs#01-4        762µs ± 4%     466µs ± 3%  -38.92%  (p=0.000 n=8+8)
WriteMessage/ReplyChannelRange#01-4        600µs ±10%     632µs ±26%     ~     (p=0.720 n=10+9)

name                                    old alloc/op   new alloc/op   delta
WriteMessage/Init-4                        64.0B ± 0%     64.0B ± 0%     ~     (all equal)
WriteMessage/Error-4                       90.0B ± 0%     56.0B ± 0%  -37.78%  (p=0.000 n=10+10)
WriteMessage/Ping-4                        30.0B ± 0%     26.0B ± 0%  -13.33%  (p=0.000 n=10+10)
WriteMessage/Pong-4                        26.0B ± 0%     24.0B ± 0%   -7.69%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4             2.26kB ± 0%    1.90kB ± 0%  -15.60%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4           2.19kB ± 0%    1.86kB ± 0%  -14.96%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            282B ± 0%      184B ± 0%  -34.75%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             240B ± 0%      144B ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                240B ± 0%      160B ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     138B ± 0%      104B ± 0%  -24.64%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                256B ± 0%      152B ± 0%  -40.62%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                208B ± 0%      152B ± 0%  -26.92%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            152B ± 0%      112B ± 0%  -26.32%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               136B ± 0%       88B ± 0%  -35.29%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  13.1kB ± 0%     6.6kB ± 0%  -49.74%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 264B ± 0%      184B ± 0%  -30.30%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    120B ± 0%       84B ± 0%  -30.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      168B ± 0%      120B ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           296B ± 0%      200B ± 0%  -32.43%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4        1.00kB ± 0%    0.54kB ± 0%  -45.90%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             788B ± 0%      600B ± 0%  -23.86%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                272B ± 0%      160B ± 0%  -41.18%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           394B ± 0%      224B ± 0%  -43.15%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4          26.8kB ± 0%    16.1kB ± 0%  -39.81%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4        73.0B ± 0%     72.0B ± 0%   -1.37%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4           88.0B ± 0%     80.0B ± 0%   -9.09%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4          26.8kB ± 0%    16.1kB ± 0%  -39.83%  (p=0.000 n=10+9)
WriteMessage/GossipTimestampRange-4        88.0B ± 0%     80.0B ± 0%   -9.09%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        849kB ± 0%     857kB ± 0%   +0.97%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        849kB ± 0%     857kB ± 0%   +0.97%  (p=0.000 n=10+10)

name                                    old allocs/op  new allocs/op  delta
WriteMessage/Init-4                         6.00 ± 0%      6.00 ± 0%     ~     (all equal)
WriteMessage/Error-4                        4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                         4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                         2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4               48.0 ± 0%      32.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4             42.0 ± 0%      29.0 ± 0%  -30.95%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            8.00 ± 0%      5.00 ± 0%  -37.50%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             6.00 ± 0%      4.00 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                7.00 ± 0%      5.00 ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     6.00 ± 0%      4.00 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                8.00 ± 0%      5.00 ± 0%  -37.50%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                12.0 ± 0%       8.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            7.00 ± 0%      5.00 ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               7.00 ± 0%      4.00 ± 0%  -42.86%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                     208 ± 0%       105 ± 0%  -49.52%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 8.00 ± 0%      6.00 ± 0%  -25.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    6.00 ± 0%      4.00 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      10.0 ± 0%       7.0 ± 0%  -30.00%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           12.0 ± 0%       8.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          25.0 ± 0%      14.0 ± 0%  -44.00%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             33.0 ± 0%      15.0 ± 0%  -54.55%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                22.0 ± 0%      10.0 ± 0%  -54.55%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           12.0 ± 0%       6.0 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           4.01k ± 0%     1.01k ± 0%  -74.90%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4         4.00 ± 0%      3.00 ± 0%  -25.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4            7.00 ± 0%      5.00 ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4           4.01k ± 0%     1.01k ± 0%  -74.92%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4         7.00 ± 0%      5.00 ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        4.03k ± 0%     1.04k ± 0%  -74.27%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        4.03k ± 0%     1.04k ± 0%  -74.29%  (p=0.000 n=10+10)

You can also view overall gain using,

benchstat write-bench-base.prof write-bench-2.prof

Third optimiztion - Using concrete types in Encode

Run the following commands to gather stats.

gco c4ad0e33

go test -run=^$ -bench=Write -count=10 -benchmem -memprofile=write-mem-final.prof -cpuprofile=write-cpu-final.prof -o lnwire-final.test | tee write-bench-final.prof
go tool pprof --sample_index=alloc_space lnwire-final.test write-mem-final.prof

Check the incremental gain using,

benchstat write-bench-2.prof write-bench-final.prof
name                                    old time/op    new time/op    delta
WriteMessage/Init-4                       2.65µs ±31%    2.29µs ±11%   -13.57%  (p=0.007 n=10+10)
WriteMessage/Error-4                       564ns ±11%     370ns ± 9%   -34.39%  (p=0.000 n=10+10)
WriteMessage/Ping-4                        479ns ± 9%     352ns ± 7%   -26.57%  (p=0.000 n=10+10)
WriteMessage/Pong-4                        535ns ±25%     336ns ± 3%   -37.17%  (p=0.000 n=9+10)
WriteMessage/MsgOpenChannel-4             2.31µs ±26%    1.65µs ± 3%   -28.36%  (p=0.000 n=9+10)
WriteMessage/MsgAcceptChannel-4           1.96µs ± 1%    1.65µs ± 2%   -15.68%  (p=0.000 n=9+9)
WriteMessage/MsgFundingCreated-4           843ns ±33%     356ns ± 1%   -57.73%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4            615ns ±11%     339ns ± 1%   -44.82%  (p=0.000 n=8+10)
WriteMessage/FundingLocked-4               682ns ±15%     452ns ± 1%   -33.72%  (p=0.000 n=10+9)
WriteMessage/Shutdown-4                    548ns ±10%     341ns ± 3%   -37.80%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4               624ns ±16%     366ns ± 3%   -41.42%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4               708ns ± 8%     383ns ± 1%   -45.90%  (p=0.000 n=9+8)
WriteMessage/UpdateFulfillHTLC-4           591ns ± 3%     335ns ± 0%   -43.34%  (p=0.000 n=10+9)
WriteMessage/UpdateFailHTLC-4              562ns ± 7%     346ns ± 2%   -38.41%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  5.02µs ± 2%    1.42µs ± 1%   -71.74%  (p=0.000 n=9+9)
WriteMessage/RevokeAndAck-4                710ns ± 9%     465ns ± 2%   -34.52%  (p=0.000 n=10+9)
WriteMessage/UpdateFee-4                   528ns ± 5%     329ns ± 1%   -37.60%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4     621ns ± 2%     346ns ± 2%   -44.32%  (p=0.000 n=8+10)
WriteMessage/ChannelReestablish-4          736ns ± 9%     485ns ± 1%   -34.13%  (p=0.000 n=10+9)
WriteMessage/ChannelAnnouncement-4        1.77µs ± 1%    1.23µs ± 2%   -30.74%  (p=0.000 n=9+9)
WriteMessage/NodeAnnouncement-4           2.35µs ± 9%    2.99µs ± 1%   +26.83%  (p=0.000 n=10+9)
WriteMessage/ChannelUpdate-4               738ns ± 1%     429ns ± 9%   -41.87%  (p=0.000 n=9+9)
WriteMessage/AnnounceSignatures-4          659ns ±14%     402ns ±12%   -38.98%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           105µs ±13%      75µs ± 2%   -28.28%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4        702ns ±47%     326ns ± 1%   -53.51%  (p=0.000 n=10+9)
WriteMessage/QueryChannelRange-4           845ns ±40%     337ns ± 1%   -60.18%  (p=0.000 n=10+9)
WriteMessage/ReplyChannelRange-4           135µs ±40%      74µs ± 1%   -44.88%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4        553ns ± 6%     341ns ± 1%   -38.41%  (p=0.000 n=10+9)
WriteMessage/QueryShortChanIDs#01-4        466µs ± 3%     408µs ± 3%   -12.34%  (p=0.000 n=8+10)
WriteMessage/ReplyChannelRange#01-4        632µs ±26%     406µs ± 2%   -35.81%  (p=0.000 n=9+9)

name                                    old alloc/op   new alloc/op   delta
WriteMessage/Init-4                        64.0B ± 0%     16.0B ± 0%   -75.00%  (p=0.000 n=10+10)
WriteMessage/Error-4                       56.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                        26.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                        24.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4             1.90kB ± 0%    1.75kB ± 0%    -7.98%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4           1.86kB ± 0%    1.75kB ± 0%    -6.01%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            184B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             144B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                160B ± 0%       80B ± 0%   -50.00%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     104B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                152B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                152B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            112B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4              88.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                  6.57kB ± 0%    0.00kB       -100.00%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 184B ± 0%       80B ± 0%   -56.52%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                   84.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      120B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           200B ± 0%       80B ± 0%   -60.00%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          541B ± 0%        8B ± 0%   -98.52%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             600B ± 0%       88B ± 0%   -85.33%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                160B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           224B ± 0%        0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4          16.1kB ± 0%     0.1kB ± 1%   -99.45%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4        72.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4           80.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4          16.1kB ± 0%     0.1kB ± 0%   -99.45%  (p=0.000 n=9+8)
WriteMessage/GossipTimestampRange-4        80.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        857kB ± 0%     841kB ± 0%    -1.88%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        857kB ± 0%     841kB ± 0%    -1.88%  (p=0.000 n=10+10)

name                                    old allocs/op  new allocs/op  delta
WriteMessage/Init-4                         6.00 ± 0%      4.00 ± 0%   -33.33%  (p=0.000 n=10+10)
WriteMessage/Error-4                        2.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                         2.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                         1.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4               32.0 ± 0%      19.0 ± 0%   -40.62%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4             29.0 ± 0%      19.0 ± 0%   -34.48%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            5.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             4.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                5.00 ± 0%      2.00 ± 0%   -60.00%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     4.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                5.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                8.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            5.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               4.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                     105 ± 0%         0       -100.00%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 6.00 ± 0%      2.00 ± 0%   -66.67%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    4.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      7.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           8.00 ± 0%      2.00 ± 0%   -75.00%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          14.0 ± 0%       2.0 ± 0%   -85.71%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             15.0 ± 0%       4.0 ± 0%   -73.33%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                10.0 ± 0%       0.0       -100.00%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           6.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           1.01k ± 0%     0.00k ± 0%   -99.70%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4         3.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4            5.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4           1.01k ± 0%     0.00k ± 0%   -99.70%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4         5.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        1.04k ± 0%     0.03k ± 0%   -96.82%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        1.04k ± 0%     0.03k ± 0%   -96.82%  (p=0.000 n=10+10)

Check the overall gain using benchstat write-bench-base.prof write-bench-final.prof.

Most of the messages now use zero heap allocations, except when,

  • calling serializedPubkey := e.SerializeCompressed(), as in MsgOpenChannel,MsgAcceptChannel,FundingLocked,RevokeAndAck and ChannelReestablish.
  • using zlib, found in QueryShortChanIDs and ReplyChannelRange.

Next Step

Optimization can be an endless task. This PR focuses on optimizing the write methods used in lnwire. The following steps would be,

  • remove WriteElement method and its related usage in other packages.
  • optimize the Write methods in channeldb to make use of the buffer.
  • optimize the Read methods in lnwire.
  • optimize the Read methods in channeldb.

@yyforyongyu yyforyongyu changed the title 3004 buffer pool lnwire: fix heap escapes to reduce gc pressure Dec 24, 2020
@Roasbeef Roasbeef added this to the 0.13.0 milestone Jan 14, 2021
@Roasbeef Roasbeef added optimization wire protocol Encoding of messages for the communication between nodes labels Jan 20, 2021
@Crypt-iQ
Copy link
Collaborator

Nice work! Drive-thru comment: commits should compile, and perhaps the diff could be broken up into smaller PRs to make review easier.

@yyforyongyu yyforyongyu marked this pull request as draft January 27, 2021 23:53
@yyforyongyu
Copy link
Member Author

Nice work! Drive-thru comment: commits should compile, and perhaps the diff could be broken up into smaller PRs to make review easier.

Will do! Just want to make sure I'm heading to the right direction before more changes are made.

@Roasbeef Roasbeef added the P2 should be fixed if one has time label Jan 28, 2021
@Roasbeef Roasbeef requested review from cfromknecht and removed request for carlaKC January 28, 2021 01:33
@Crypt-iQ
Copy link
Collaborator

Crypt-iQ commented Jan 29, 2021

I think the WriteMessage change from io.Writer to *bytes.Buffer can be a separate commit from WriteElements change from io.Writer to *bytes.Buffer. One gain from WriteMessage is the removal of var bw bytes.Buffer. Splitting up the commit there can help see incrementally the gains realized. WDYT?

@Roasbeef
Copy link
Member

Roasbeef commented Mar 5, 2021

cc @cfromknecht

@yyforyongyu
Copy link
Member Author

I think the WriteMessage change from io.Writer to *bytes.Buffer can be a separate commit from WriteElements change from io.Writer to *bytes.Buffer. One gain from WriteMessage is the removal of var bw bytes.Buffer. Splitting up the commit there can help see incrementally the gains realized. WDYT?

I've changed the overall optimization into three steps and broke the commits. Let me know what you think.

@yyforyongyu yyforyongyu requested review from Roasbeef and removed request for cfromknecht June 22, 2021 13:10
@yyforyongyu yyforyongyu marked this pull request as ready for review June 22, 2021 13:10
@yyforyongyu
Copy link
Member Author

make lint gave me this weird error, does anybody know what happened?

lnwire/writer.go:50:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteBytes(buf *bytes.Buffer, b []byte) error {
                ^
lnwire/writer.go:56:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint8(buf *bytes.Buffer, n uint8) error {
                ^
lnwire/writer.go:63:18: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint16(buf *bytes.Buffer, n uint16) error {

@Crypt-iQ
Copy link
Collaborator

make lint gave me this weird error, does anybody know what happened?

lnwire/writer.go:50:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteBytes(buf *bytes.Buffer, b []byte) error {
                ^
lnwire/writer.go:56:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint8(buf *bytes.Buffer, n uint8) error {
                ^
lnwire/writer.go:63:18: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint16(buf *bytes.Buffer, n uint16) error {

No idea, that is very weird.

@carlaKC
Copy link
Collaborator

carlaKC commented Jun 23, 2021

make lint gave me this weird error, does anybody know what happened?

lnwire/writer.go:50:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteBytes(buf *bytes.Buffer, b []byte) error {
                ^
lnwire/writer.go:56:17: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint8(buf *bytes.Buffer, n uint8) error {
                ^
lnwire/writer.go:63:18: `buf` can be `github.com/miekg/dns.Writer` (interfacer)
func WriteUint16(buf *bytes.Buffer, n uint16) error {

If you only use the methods of bytes.Buffer that are implemented by io.Writer then the linter wants you to just set the parameter to the interface since that's all you need.

another example, this would fail for the linter because you could just use the Stringer interface here:

func something(hash lntypes.Hash)string{
    return hash.String()
}

Since we intentionally want to replace the interface here, you can just add //nolint: interfacer and perhaps a comment indicating why we don't use the interface.

@yyforyongyu
Copy link
Member Author

Since we intentionally want to replace the interface here, you can just add //nolint: interfacer and perhaps a comment indicating why we don't use the interface.

Cool, good to know, thanks! To me it's weird that the linter is asking me to use the package github.com/miekg/dns.Writer, which I don't think it's in the standard library.

@carlaKC
Copy link
Collaborator

carlaKC commented Jun 23, 2021

Cool, good to know, thanks! To me it's weird that the linter is asking me to use the package github.com/miekg/dns.Writer, which I don't think it's in the standard library.

Ah yeah, probably just happens to match the set of methods we're using here. Pretty random.

Copy link
Collaborator

@Crypt-iQ Crypt-iQ left a comment

Choose a reason for hiding this comment

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

Reviewed up to 78afd37165d6abdf4ee723635355d4082e794143:
I think so far the PR goes in a good direction. I think the TODOs could be removed. Left some comments.

lnwire/message_test.go Outdated Show resolved Hide resolved
lnwire/message_test.go Outdated Show resolved Hide resolved
lnwire/message_test.go Outdated Show resolved Hide resolved
lnwire/message_test.go Outdated Show resolved Hide resolved
lnwire/message_test.go Outdated Show resolved Hide resolved
lnwire/query_short_chan_ids.go Show resolved Hide resolved
lnwire/writer.go Outdated Show resolved Hide resolved
// First, we'll encode all the addresses into an intermediate
// buffer. We need to do this in order to compute the total
// length of the addresses.
buffer := make([]byte, 0, MaxMsgBody)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can the length not be calculated for []net.Addr so a slice doesn't have to be made?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think you need to have the length for TLV records?

Copy link
Member

Choose a reason for hiding this comment

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

If I understand his suggestion, we'd essentially need to run through the set of addresses twice: once to tally up how much data is needed, and a second time to write the bytes in-line.

Doesn't this double buffering defeat the purpose of using bytes.Buffer here (passed in) vs making a brand new one?

Copy link
Member Author

Choose a reason for hiding this comment

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

The short answer is because it won't escape to heap, running go build -gcflags "-m -m" under lnd/lnwire,

./writer.go:393:16: make([]byte, 0, MaxMsgBody) does not escape
./writer.go:394:28: &bytes.Buffer{...} does not escape

So there're no heap allocations.

If I understand his suggestion, we'd essentially need to run through the set of addresses twice: once to tally up how much data is needed, and a second time to write the bytes in-line.

Yeah I think we have to write the address data somewhere before we could know the length of the data. And because we need to encode length before the actual data, [bytes for length][bytes for data], we need to use a temp buffer to hold it before we write it to our passed in buffer. Otherwise we could just write to the passed in buffer then calculate how much new data was written to retrieve the length info, ie, [bytes for data][bytes for length].

Only if we could first write two empty bytes, then write the data, and "insert" back the length. But I don't think that's feasible with bytes.Buffer, as suggested here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We'd just have to iterate over the addresses and tally up the lengths based on the type encountered -- so I don't think it'd require a temporary buffer?

Another Q: If make([]byte, 0, MaxMsgBody) doesn't escape to the heap, then it's on the stack. Is it a problem if multiple goroutines are calling this function then given that the stack has limited space?

Copy link
Member Author

Choose a reason for hiding this comment

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

We'd just have to iterate over the addresses and tally up the lengths based on the type encountered -- so I don't think it'd require a temporary buffer?

Yeah we could iterate twice. The first time we calculate the length and the second time we put the length and actual data into the buffer. So it depends on whether you want to trade space with time. Since it lives on the stack, I don't think we need to.

Another Q: If make([]byte, 0, MaxMsgBody) doesn't escape to the heap, then it's on the stack. Is it a problem if multiple goroutines are calling this function then given that the stack has limited space?

Yeah either it's heap or stack I think we both have this oom problem.

lnwire/writer_test.go Show resolved Hide resolved
lnwire/writer_test.go Show resolved Hide resolved
Copy link
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.

Impressive results! I also like how the large change of updating all the seriliaztion in the codebase was broken up into a few smaller commits to make the setr of changes slightly more digestible.

The diff reads well to me, and I've started to run this on one of my larger testnet nodes that has lndmon enabled so I can track metrics such as the heap size, total allocated/freed, etc. Will report back with my findings.

lnwire/message.go Show resolved Hide resolved
// generates a test message for each of the lnwire.Message, calls the
// WriteMessage method and benchmark it.
func BenchmarkWriteMessage(b *testing.B) {
// Create testing messages. We will use a constant seed to make sure
Copy link
Member

Choose a reason for hiding this comment

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

If you add b.ReportAllocs here, then it'll also show information related to the number of allocations/bytes per op.

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it. I used -benchmem instead, so go test -run=^$ -bench=Write -benchmem will give,

BenchmarkWriteMessage/Init-4    545257    2330 ns/op    176 B/op    9 allocs/op


bufPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(buffer)
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, does this end copying the buffer each time New is called, or create a new one in place?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's arbitrary. From the godoc,

Get selects an arbitrary item from the Pool, removes it from the Pool, and returns it to the caller. Get may choose to ignore the pool and treat it as empty. Callers should not assume any relation between values passed to Put and the values returned by Get.

I tested locally. If I run the test exactly once (b.N = 1), it will create two buffers and keeps iterating between the two.

// makeAllMessages is used to create testing messages for each lnwire message
// type.
//
// TODO(yy): the following testing messages are created somewhat arbitrary. We
Copy link
Member

Choose a reason for hiding this comment

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

What do you mean by standardize? Like set the set of fields and TLV values that we typically see in practice?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah exactly. Atm I'm just filling random bytes into each field, while it's a good start, we may someday get to the point where we want to optimize a single byte (hopefully!).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could remove TODO comment

return msg
}

func newMsgAcceptChannel(t testing.TB, r *rand.Rand) *lnwire.AcceptChannel {
Copy link
Member

Choose a reason for hiding this comment

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

Not a blocker, but we could possibly re-use the code we have to generate sample messages of each types for the testing/quick tests we use for serialization.

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it. I think I did copy that code and broke them into smaller functions. This could be a TODO in the future to let them share the same code.

@@ -115,7 +116,7 @@ var _ Message = (*AcceptChannel)(nil)
// protocol version.
//
// This is part of the lnwire.Message interface.
func (a *AcceptChannel) Encode(w io.Writer, pver uint32) error {
func (a *AcceptChannel) Encode(w *bytes.Buffer, pver uint32) error {
Copy link
Member

Choose a reason for hiding this comment

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

So the rationale here is that we end up saving a heap escape? I guess in the end, we don't ever really write directly to the wire (where the io.Writer could be useful), since we need to encrypt the message payload first using our noise construction.

Copy link
Member Author

Choose a reason for hiding this comment

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

The Encode calls WriteElements, which saves several heap escapes when using a concrete type. I think this is where the gain comes from, and the incremental gain from this commit compared to the previous one,

name                                    old allocs/op  new allocs/op  delta
WriteMessage/Init-4                         6.00 ± 0%      6.00 ± 0%     ~     (all equal)
WriteMessage/Error-4                        4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Ping-4                         4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/Pong-4                         2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/MsgOpenChannel-4               48.0 ± 0%      32.0 ± 0%  -33.33%  (p=0.000 n=10+10)
WriteMessage/MsgAcceptChannel-4             42.0 ± 0%      29.0 ± 0%  -30.95%  (p=0.000 n=10+10)
WriteMessage/MsgFundingCreated-4            6.00 ± 0%      3.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/MsgFundingSigned-4             4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/FundingLocked-4                7.00 ± 0%      5.00 ± 0%  -28.57%  (p=0.000 n=10+10)
WriteMessage/Shutdown-4                     4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/ClosingSigned-4                6.00 ± 0%      3.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/UpdateAddHTLC-4                10.0 ± 0%       6.0 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFulfillHTLC-4            5.00 ± 0%      3.00 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailHTLC-4               5.00 ± 0%      2.00 ± 0%  -60.00%  (p=0.000 n=10+10)
WriteMessage/CommitSig-4                     208 ± 0%       105 ± 0%  -49.52%  (p=0.000 n=10+10)
WriteMessage/RevokeAndAck-4                 8.00 ± 0%      6.00 ± 0%  -25.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFee-4                    4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/UpdateFailMalformedHTLC-4      8.00 ± 0%      5.00 ± 0%  -37.50%  (p=0.000 n=10+10)
WriteMessage/ChannelReestablish-4           10.0 ± 0%       6.0 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/ChannelAnnouncement-4          25.0 ± 0%      14.0 ± 0%  -44.00%  (p=0.000 n=10+10)
WriteMessage/NodeAnnouncement-4             33.0 ± 0%      15.0 ± 0%  -54.55%  (p=0.000 n=10+10)
WriteMessage/ChannelUpdate-4                22.0 ± 0%      10.0 ± 0%  -54.55%  (p=0.000 n=10+10)
WriteMessage/AnnounceSignatures-4           12.0 ± 0%       6.0 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs-4           4.01k ± 0%     1.00k ± 0%  -74.92%  (p=0.000 n=10+10)
WriteMessage/ReplyShortChanIDsEnd-4         2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WriteMessage/QueryChannelRange-4            5.00 ± 0%      3.00 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange-4           4.01k ± 0%     1.00k ± 0%  -74.94%  (p=0.000 n=10+10)
WriteMessage/GossipTimestampRange-4         5.00 ± 0%      3.00 ± 0%  -40.00%  (p=0.000 n=10+10)
WriteMessage/QueryShortChanIDs#01-4        4.03k ± 0%     1.04k ± 0%  -74.29%  (p=0.000 n=10+10)
WriteMessage/ReplyChannelRange#01-4        4.03k ± 0%     1.04k ± 0%  -74.31%  (p=0.000 n=10+10)

I guess in the end, we don't ever really write directly to the wire (where the io.Writer could be useful)

A bit confused here🧐 If the io.Writer works, so does *bytes.Buffer right?

lnwire/features.go Show resolved Hide resolved
@@ -76,6 +76,9 @@ func (a addressType) AddrLen() uint16 {

// WriteElement is a one-stop shop to write the big endian representation of
// any element which is to be serialized for the wire protocol.
//
// TODO(yy): rm this method once we finish dereferencing it from other
// packages.
Copy link
Member

Choose a reason for hiding this comment

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

One thing that would be useful here (still getting through the commits) to make sure we're not breaking anything in the process here would be to retain this method (rename it likely), then use quick.CheckEqual to ensure that the encoding produced here doesn't deviate with any input. Eventually (post Go 1.7) we'll be able to also use the fuzzing in the standard library to implement differential fuzzing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I think atm only package chanbackup is using it, will check!

// First, we'll encode all the addresses into an intermediate
// buffer. We need to do this in order to compute the total
// length of the addresses.
buffer := make([]byte, 0, MaxMsgBody)
Copy link
Member

Choose a reason for hiding this comment

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

If I understand his suggestion, we'd essentially need to run through the set of addresses twice: once to tally up how much data is needed, and a second time to write the bytes in-line.

Doesn't this double buffering defeat the purpose of using bytes.Buffer here (passed in) vs making a brand new one?

a.FirstCommitmentPoint,
tlvRecords,
)
if err := WriteBytes(w, a.PendingChannelID[:]); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Extra I in the commit message?

Copy link
Member

Choose a reason for hiding this comment

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

Ahh it's meant to be like "part 1" gotcha.

Copy link
Member Author

Choose a reason for hiding this comment

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

😂

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually it's missing a dash...will put it back

@yyforyongyu
Copy link
Member Author

The diff reads well to me, and I've started to run this on one of my larger testnet nodes that has lndmon enabled so I can track metrics such as the heap size, total allocated/freed, etc. Will report back with my findings.

Just curious about how the heap allocs prior to this PR look like? Do we happen to have that kind of data?

Copy link
Collaborator

@Crypt-iQ Crypt-iQ left a comment

Choose a reason for hiding this comment

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

Reviewed up to 0274194f961ffb0d5c4a68300da5ddebfd723685, some nits, comments and questions

r := bytes.NewBuffer(buf.Bytes())

// Read the message from the buffer.

Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: remove newline

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed!

// makeAllMessages is used to create testing messages for each lnwire message
// type.
//
// TODO(yy): the following testing messages are created somewhat arbitrary. We
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could remove TODO comment


return lnwire.NewInitMessage(
rawFeatureVector(),
rawFeatureVector(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

May take ExtraData

Copy link
Member Author

Choose a reason for hiding this comment

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

Added.

require.NoError(t, err)

_, err = r.Read(msg.PendingChannelID[:])
require.NoError(t, err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

err message here and above?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added.

t.Helper()

return &lnwire.Ping{
NumPongBytes: uint16(r.Int31()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Change to 16-bits wide?

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed.

lnwire/writer_test.go Show resolved Hide resolved
lnwire/writer_test.go Show resolved Hide resolved
lnwire/writer_test.go Show resolved Hide resolved
lnwire/closing_signed.go Show resolved Hide resolved
lnwire/funding_created.go Show resolved Hide resolved
@Crypt-iQ
Copy link
Collaborator

Crypt-iQ commented Jul 7, 2021

The diff reads well to me, and I've started to run this on one of my larger testnet nodes that has lndmon enabled so I can track metrics such as the heap size, total allocated/freed, etc. Will report back with my findings.

Just curious about how the heap allocs prior to this PR look like? Do we happen to have that kind of data?

I don't have raw data, but I remember it not being so great when using pprof on a running node

@Roasbeef
Copy link
Member

Just curious about how the heap allocs prior to this PR look like? Do we happen to have that kind of data?

I mainly have some historical data from my own person lndmon instance...

Copy link
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 👒

Just needs an entry in the set of release notes!

MaxMessagePayload and MaxSliceLength are duplicate variables. This
commit deletes MaxMessagePayload and keeps MaxSliceLength.
This commit changes the method WriteMessage to use bytes.Buffer to save
heap allocations. A unit test is added to check the method is
implemented as expected.
This commit changes the WriteElement and WriteElements methods to take a
write buffer instead of io.Writer. The corresponding Encode methods are
changed to use the write buffer.
This commit breaks the method WriteElement and adds specific writers for
each of the data types.
This commit takes 10 types of messages and refactors their Encode method
to use specific writers. The following commits will refactor the rest.
This commit takes another 10 message types and refactors their Encode
method to use specific writers. The following commit will refactor the
rest.
This commit refactors the remaining usage of WriteElements. By
replacing the interface types with concrete types for the params used in
the methods, most of the encoding of the messages now takes zero heap
allocations.
@Roasbeef Roasbeef merged commit b0e9442 into lightningnetwork:master Aug 11, 2021
@yyforyongyu yyforyongyu deleted the 3004-buffer-pool branch August 11, 2021 03:30
@Crypt-iQ
Copy link
Collaborator

post-merge update: I ran the fuzz tests for lnwire and this pull does not break anything

morehouse added a commit to morehouse/lnd that referenced this pull request May 12, 2023
After lightningnetwork#4884, many of the cases in WriteElement are now dead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
optimization P2 should be fixed if one has time wire protocol Encoding of messages for the communication between nodes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

lnwire+channeldb+pool: extend the reader/write buffer pools to cover channeldb+lnwire
4 participants