Seems the simplest web server printing just "Hello World" is not comparable
to nginx, apache, etc. I can get about 3000 request/second for Go with max
procs set to number of CPUs, but easily get nginx serving a larger static
file about 5000 request/second.
I profiled the program. Here is the result. I added the source code at the
end also. Can someone please explain why the syscall.Syscall and
runtime.futex are taking so much cycles? Can it be improved?
(pprof) top
Total: 6053 samples
2243 37.1% 37.1% 2249 37.2% syscall.Syscall
2153 35.6% 72.6% 2153 35.6% runtime.futex
443 7.3% 79.9% 446 7.4% syscall.Syscall6
92 1.5% 81.5% 92 1.5% bytes.IndexByte
86 1.4% 82.9% 159 2.6% scanblock
81 1.3% 84.2% 81 1.3% syscall.RawSyscall6
68 1.1% 85.3% 68 1.1% runtime.usleep
37 0.6% 86.0% 67 1.1% sweep
35 0.6% 86.5% 35 0.6% runtime.memmove
33 0.5% 87.1% 74 1.2% runtime.MCache_Alloc
(pprof) top --cum
Total: 6053 samples
0 0.0% 0.0% 5350 88.4% schedunlock
3 0.0% 0.0% 2957 48.9% net/http.(*conn).serve
2243 37.1% 37.1% 2249 37.2% syscall.Syscall
2153 35.6% 72.7% 2153 35.6% runtime.futex
0 0.0% 72.7% 1715 28.3% runtime.futexwakeup
0 0.0% 72.7% 1706 28.2% runtime.notewakeup
1 0.0% 72.7% 1638 27.1% net/http.(*response).finishRequest
1 0.0% 72.7% 1628 26.9% bufio.(*Writer).Flush
1 0.0% 72.7% 1628 26.9% net.(*TCPConn).Write
2 0.0% 72.8% 1628 26.9% net.(*netFD).Write
The source code server.go:
package main
import (
"flag"
"log"
"net/http"
"os"
"runtime"
"runtime/pprof"
"time"
)
func HelloServer(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("hello, world!\n"))
}
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
go func() {
time.Sleep(100 * time.Second)
pprof.StopCPUProfile()
}()
}
http.HandleFunc("/", HelloServer)
srv := &http.Server{
Addr: ":8080",
Handler: http.DefaultServeMux,
ReadTimeout: time.Duration(5) * time.Second,
}
srv.ListenAndServe()
}
--