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

x/net: Performance degradation on Windows 64 bit when using "tcp4"/"tcp6" as network instead of "tcp" in net.Listen() #40243

Closed
ikandaswamy opened this issue Jul 16, 2020 · 5 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Milestone

Comments

@ikandaswamy
Copy link

What version of Go are you using (go version)?

$ go version
1.13.7

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

Windows 64 bit

go env Output
$ go env

What did you do?

Pre issue we created a single listener for http and use that to Listen with protocol = tcp

listener    net.Listener
func (this *HttpEndpoint) Listen() error {
	ln, err := net.Listen("tcp", this.httpAddr)
	if err == nil {
		this.listener = ln
		srv := &http.Server{
			Handler:           this.mux,
			ReadHeaderTimeout: 5 * time.Second,
		}
		go srv.Serve(ln)
		logging.Infop("HttpEndpoint: Listen", logging.Pair{"Address", ln.Addr()})
	}
	return err
}

Then we changed the code to use tcp4 and/or tcp6 explicitly in the Listen function. The code for this is given below.

  1. If server sends us ipv6=true, then we should
    (1) start listening to ipv6 - fail service if listen fails
    (2) try to listen to ipv4 - don't fail service even if listen fails.
  2. If server sends us ipv6=false, then we should
    (1) start listening to ipv4 - fail service if listen fails
    (2) try to listen to ipv6 - don't fail service even if listen fails.

Create 2 listeners - one for http and one for https.
Code to create the listeners -

listener      []net.Listener

func getNetwProtocol() []string {
	if server.IsIPv6() {
		return []string{"tcp6", "tcp4"}
	}
	return []string{"tcp4", "tcp6"}
}

func (this *HttpEndpoint) Listen() error {

	srv := &http.Server{
		Handler:           this.mux,
		ReadHeaderTimeout: 5 * time.Second,
	}

	for i, netW := range getNetwProtocol() {
		ln, err := net.Listen(netW, this.httpAddr)

		if err != nil {
			if i == 0 {
				return fmt.Errorf("Failed to start service: %v", err.Error())
			} else {
				logging.Infof("Failed to start service: %v", err.Error())
			}
		} else {
			this.listener = append(this.listener, ln)
			go srv.Serve(ln)
			logging.Infop("HttpEndpoint: Listen", logging.Pair{"Address", ln.Addr()})
		}
	}

	return nil
}

What did you expect to see?

No change in performance tests (this is true for the Linux - Centos7 machine and Mac)
Previous throughput - 131K

What did you see instead?

Slowdown only on the Windows performance tests. The throughput on Linux and Mac more or less stayed the same.
On windows we saw a 50% degradation.

I changed the code to test just using tcp and tcp4/tcp6 with the rest of the code being the same. Thats when I see the degradation in performance.

Question - Why is there an performance issue with using tcp4/tcp6 instead of tcp in net.Listen() on Windows ? Is this an expected issue ?

@toothrot toothrot changed the title Performance degradation on Windows 64 bit when using "tcp4"/"tcp6" as network instead of "tcp" in net.Listen() x/net: Performance degradation on Windows 64 bit when using "tcp4"/"tcp6" as network instead of "tcp" in net.Listen() Jul 21, 2020
@gopherbot gopherbot added this to the Unreleased milestone Jul 21, 2020
@toothrot toothrot added OS-Windows NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Jul 21, 2020
@toothrot toothrot modified the milestones: Unreleased, Backlog Jul 21, 2020
@toothrot
Copy link
Contributor

/cc @bradfitz @ianlancetaylor

@networkimprov
Copy link

cc @alexbrainman

@bradfitz
Copy link
Contributor

Do you have a self-contained minimal repro?

Does this also happen with Go 1.14 or Go 1.15?

@ikandaswamy
Copy link
Author

ikandaswamy commented Nov 17, 2020

I tried building with 1.15.4 but I run into a build issue - mingw32/bin/ld.exe: Error: export ordinal too large: 80134 - #40795

But I see the same numbers with go 1.14.

@qmuntal
Copy link
Contributor

qmuntal commented May 16, 2023

Question - Why is there an performance issue with using tcp4/tcp6 instead of tcp in net.Listen() on Windows ? Is this an expected issue ?

tcp was being marked as pollable, while tcp4 and tcp6 were not, causing more cgo calls on the later. This has been fix in go1.21 by CL 463839.

Please reopen if you still see the issue on go1.21.

@qmuntal qmuntal closed this as completed May 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Projects
None yet
Development

No branches or pull requests

6 participants