http2: implement a more efficient writeQueue that avoids unnecessary copies.

Our previous implementation of writeQueue relies on one
[]FrameWriteRequests, forcing us to copy the rest of the slice's content
whenever we remove an item from the front.

This change remedies this problem by implementing writeQueue using
two-stage queues, similar to Okasaki's purely functional queue.

With 25 frames per stream, we are observing the following performance
improvement:
goos: linux
goarch: amd64
pkg: golang.org/x/net/http2
cpu: AMD EPYC 7B13
              │  /tmp/old   │              /tmp/new               │
              │   sec/op    │   sec/op     vs base                │
WriteQueue-64   508.3n ± 3%   305.7n ± 3%  -39.86% (p=0.000 n=10)

              │  /tmp/old  │            /tmp/new            │
              │    B/op    │    B/op     vs base            │
WriteQueue-64   0.000 ± 0%   0.000 ± 0%  ~ (p=1.000 n=10) ¹
¹ all samples are equal

              │  /tmp/old  │            /tmp/new            │
              │ allocs/op  │ allocs/op   vs base            │
WriteQueue-64   0.000 ± 0%   0.000 ± 0%  ~ (p=1.000 n=10) ¹
¹ all samples are equal

As the number of frames increases, the performance difference becomes
more stark as the old implementation does a quadratic amount of copying
in total to be able to fully consume a queue.

Change-Id: Ide816ebdd89a41275b5829683c0f10d48321af50
Reviewed-on: https://go-review.googlesource.com/c/net/+/710635
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicholas Husin <husin@google.com>
3 files changed
tree: 00f946d74182952194b6159c46c689e1bd8e5b70
  1. bpf/
  2. context/
  3. dict/
  4. dns/
  5. html/
  6. http/
  7. http2/
  8. icmp/
  9. idna/
  10. internal/
  11. ipv4/
  12. ipv6/
  13. lif/
  14. nettest/
  15. netutil/
  16. proxy/
  17. publicsuffix/
  18. quic/
  19. route/
  20. trace/
  21. webdav/
  22. websocket/
  23. xsrftoken/
  24. .gitattributes
  25. .gitignore
  26. codereview.cfg
  27. CONTRIBUTING.md
  28. go.mod
  29. go.sum
  30. LICENSE
  31. PATENTS
  32. README.md
README.md

Go Networking

Go Reference

This repository holds supplementary Go networking packages.

Report Issues / Send Patches

This repository uses Gerrit for code changes. To learn how to submit changes to this repository, see https://go.dev/doc/contribute.

The git repository is https://go.googlesource.com/net.

The main issue tracker for the net repository is located at https://go.dev/issues. Prefix your issue with “x/net:” in the subject line, so it is easy to find.