From f250d04c9403c18f841ce53c22c401408c9be5ab Mon Sep 17 00:00:00 2001 From: Yu-Lang Chu Date: Tue, 11 May 2021 00:46:50 +0200 Subject: [PATCH 1/4] add ServeMux benchmark --- misc/router-benchmark/routerbenchmark_test.go | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 misc/router-benchmark/routerbenchmark_test.go diff --git a/misc/router-benchmark/routerbenchmark_test.go b/misc/router-benchmark/routerbenchmark_test.go new file mode 100644 index 00000000..3511964b --- /dev/null +++ b/misc/router-benchmark/routerbenchmark_test.go @@ -0,0 +1,103 @@ +package router_benchmark + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func BenchmarkServeMux(b *testing.B) { + rr := httptest.NewRecorder() + mux := http.NewServeMux() + mux.HandleFunc("/v1/boards/", getBoards) + + req, err := http.NewRequest("GET", "/v1/boards/SYSOP/articles", nil) + if err != nil { + b.Fatal(err) + } + + for i := 0; i < b.N; i++ { + mux.ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + b.Errorf("handler returned wrong status code: got %v want %v", + rr.Code, http.StatusOK) + } + } +} + +// getBoards is the handler for `/v1/boards` with GET method +func getBoards(w http.ResponseWriter, r *http.Request) { + boardID, item, filename, _ := parseBoardPath(r.URL.Path) + if boardID == "" { + //delivery.getBoardList(w, r) + w.WriteHeader(http.StatusNotFound) + return + } + // get single board + if item == "information" { + w.WriteHeader(http.StatusNotFound) + return + } else if item == "settings" { + //delivery.getBoardSettings(w, r, boardID) + w.WriteHeader(http.StatusNotFound) + return + } else if item == "articles" { + if filename == "" { + getBoardArticles(w, r, boardID) + } else { + w.WriteHeader(http.StatusNotFound) + } + return + } else if item == "treasures" { + w.WriteHeader(http.StatusNotFound) + return + } + + // 404 + w.WriteHeader(http.StatusNotFound) +} + +// parseBoardPath covert url path from /v1/boards/SYSOP/article to +// {SYSOP, article) or /v1/boards to {,} +func parseBoardPath(path string) (boardID string, item string, filename string, err error) { + pathSegment := strings.Split(path, "/") + + if len(pathSegment) >= 6 { + // /{{version}}/boards/{{class_id}}/{{item}}/{{filename}} + boardID = pathSegment[3] + item = pathSegment[4] + filename = pathSegment[5] + return + } else if len(pathSegment) == 5 { + // /{{version}}/boards/{{class_id}}/{{item}} + boardID = pathSegment[3] + item = pathSegment[4] + return + } else if len(pathSegment) == 4 { + // /{{version}}/boards/{{class_id}} + boardID = pathSegment[3] + return + } else if len(pathSegment) == 3 { + // /{{version}}/boards + // Should not be reach... + return + } + return +} + +// getBoardArticles handles request with `/v1/boards/SYSOP/articles` and will return +// article list to client +func getBoardArticles(w http.ResponseWriter, r *http.Request, boardID string) { + _ = boardID + w.WriteHeader(200) +} + +// +//// getBoards is the handler for `/v1/boards` with GET method +//func getBoardArticles_Router(w http.ResponseWriter, r *http.Request) { +// params := httprouter.ParamsFromContext(r.Context()) +// boardID := params["boardID"] +// _ = boardID +// w.WriteHeader(200) +//} From 8a6215544c8b05eaa575a7d2cf0cc5a114c6e542 Mon Sep 17 00:00:00 2001 From: Yu-Lang Chu Date: Tue, 11 May 2021 01:05:31 +0200 Subject: [PATCH 2/4] add gorilla and httprouter benchmark --- misc/router-benchmark/go.mod | 8 ++++ misc/router-benchmark/go.sum | 4 ++ misc/router-benchmark/routerbenchmark_test.go | 46 ++++++++++++++----- 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 misc/router-benchmark/go.mod create mode 100644 misc/router-benchmark/go.sum diff --git a/misc/router-benchmark/go.mod b/misc/router-benchmark/go.mod new file mode 100644 index 00000000..a1eac278 --- /dev/null +++ b/misc/router-benchmark/go.mod @@ -0,0 +1,8 @@ +module github.com/Ptt-official-app/Ptt-backend/misc/router-benchmark + +go 1.16 + +require ( + github.com/gorilla/mux v1.8.0 + github.com/julienschmidt/httprouter v1.3.0 +) diff --git a/misc/router-benchmark/go.sum b/misc/router-benchmark/go.sum new file mode 100644 index 00000000..04888091 --- /dev/null +++ b/misc/router-benchmark/go.sum @@ -0,0 +1,4 @@ +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= diff --git a/misc/router-benchmark/routerbenchmark_test.go b/misc/router-benchmark/routerbenchmark_test.go index 3511964b..a036f047 100644 --- a/misc/router-benchmark/routerbenchmark_test.go +++ b/misc/router-benchmark/routerbenchmark_test.go @@ -1,6 +1,8 @@ package router_benchmark import ( + "github.com/gorilla/mux" + "github.com/julienschmidt/httprouter" "net/http" "net/http/httptest" "strings" @@ -9,16 +11,31 @@ import ( func BenchmarkServeMux(b *testing.B) { rr := httptest.NewRecorder() - mux := http.NewServeMux() - mux.HandleFunc("/v1/boards/", getBoards) + r := http.NewServeMux() + r.HandleFunc("/v1/boards/", getBoards) + runTest(b, r, rr) +} +func BenchmarkGorillaMux(b *testing.B) { + rr := httptest.NewRecorder() + r := mux.NewRouter().StrictSlash(true) + r.HandleFunc("/v1/boards/{boardID}/articles", getBoardArticles_gorillamux) + runTest(b, r, rr) +} +func BenchmarkHttpRouter(b *testing.B) { + rr := httptest.NewRecorder() + r := httprouter.New() + r.HandlerFunc(http.MethodGet, "/v1/boards/:boardID/articles", getBoardArticles_httprouter) + runTest(b, r, rr) +} +func runTest(b *testing.B, r http.Handler, rr *httptest.ResponseRecorder) { req, err := http.NewRequest("GET", "/v1/boards/SYSOP/articles", nil) if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { - mux.ServeHTTP(rr, req) + r.ServeHTTP(rr, req) if rr.Code != http.StatusOK { b.Errorf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK) @@ -93,11 +110,18 @@ func getBoardArticles(w http.ResponseWriter, r *http.Request, boardID string) { w.WriteHeader(200) } -// -//// getBoards is the handler for `/v1/boards` with GET method -//func getBoardArticles_Router(w http.ResponseWriter, r *http.Request) { -// params := httprouter.ParamsFromContext(r.Context()) -// boardID := params["boardID"] -// _ = boardID -// w.WriteHeader(200) -//} +// getBoards is the handler for `/v1/boards` with GET method +func getBoardArticles_httprouter(w http.ResponseWriter, r *http.Request) { + params := httprouter.ParamsFromContext(r.Context()) + boardID := params.ByName("boardID") + _ = boardID + w.WriteHeader(200) +} + +// getBoards is the handler for `/v1/boards` with GET method +func getBoardArticles_gorillamux(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + boardID := params["boardID"] + _ = boardID + w.WriteHeader(200) +} From 8eee078777a291858bebc1b7f953b8265f7c2455 Mon Sep 17 00:00:00 2001 From: Yu-Lang Chu Date: Tue, 11 May 2021 01:14:44 +0200 Subject: [PATCH 3/4] add README.md --- misc/router-benchmark/README.md | 13 +++++++++++++ misc/router-benchmark/routerbenchmark_test.go | 13 ++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 misc/router-benchmark/README.md diff --git a/misc/router-benchmark/README.md b/misc/router-benchmark/README.md new file mode 100644 index 00000000..3a90b138 --- /dev/null +++ b/misc/router-benchmark/README.md @@ -0,0 +1,13 @@ +## Router benchmark + +Ptt-backend/misc/router-benchmark\ +`go test -bench=. -benchmem` +```go +goos: linux +goarch: amd64 +pkg: github.com/Ptt-official-app/Ptt-backend/misc/router-benchmark +cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz +Benchmark_ServeMux-7 3167156 374.2 ns/op 80 B/op 1 allocs/op +Benchmark_gorillamux-7 760047 1560 ns/op 1312 B/op 10 allocs/op +Benchmark_httprouter-7 3195236 371.7 ns/op 504 B/op 5 allocs/op +``` diff --git a/misc/router-benchmark/routerbenchmark_test.go b/misc/router-benchmark/routerbenchmark_test.go index a036f047..db8baef6 100644 --- a/misc/router-benchmark/routerbenchmark_test.go +++ b/misc/router-benchmark/routerbenchmark_test.go @@ -9,19 +9,19 @@ import ( "testing" ) -func BenchmarkServeMux(b *testing.B) { +func Benchmark_ServeMux(b *testing.B) { rr := httptest.NewRecorder() r := http.NewServeMux() r.HandleFunc("/v1/boards/", getBoards) runTest(b, r, rr) } -func BenchmarkGorillaMux(b *testing.B) { +func Benchmark_gorillamux(b *testing.B) { rr := httptest.NewRecorder() r := mux.NewRouter().StrictSlash(true) r.HandleFunc("/v1/boards/{boardID}/articles", getBoardArticles_gorillamux) runTest(b, r, rr) } -func BenchmarkHttpRouter(b *testing.B) { +func Benchmark_httprouter(b *testing.B) { rr := httptest.NewRecorder() r := httprouter.New() r.HandlerFunc(http.MethodGet, "/v1/boards/:boardID/articles", getBoardArticles_httprouter) @@ -81,23 +81,18 @@ func parseBoardPath(path string) (boardID string, item string, filename string, pathSegment := strings.Split(path, "/") if len(pathSegment) >= 6 { - // /{{version}}/boards/{{class_id}}/{{item}}/{{filename}} boardID = pathSegment[3] item = pathSegment[4] filename = pathSegment[5] return } else if len(pathSegment) == 5 { - // /{{version}}/boards/{{class_id}}/{{item}} boardID = pathSegment[3] item = pathSegment[4] return } else if len(pathSegment) == 4 { - // /{{version}}/boards/{{class_id}} boardID = pathSegment[3] return } else if len(pathSegment) == 3 { - // /{{version}}/boards - // Should not be reach... return } return @@ -105,7 +100,7 @@ func parseBoardPath(path string) (boardID string, item string, filename string, // getBoardArticles handles request with `/v1/boards/SYSOP/articles` and will return // article list to client -func getBoardArticles(w http.ResponseWriter, r *http.Request, boardID string) { +func getBoardArticles(w http.ResponseWriter, _ *http.Request, boardID string) { _ = boardID w.WriteHeader(200) } From f515cada60cbc5b4dc767b289f550522303f9918 Mon Sep 17 00:00:00 2001 From: Yu-Lang Chu Date: Thu, 13 May 2021 10:34:45 +0200 Subject: [PATCH 4/4] add lines of code --- misc/router-benchmark/README.md | 28 +++++++ misc/router-benchmark/routeGorillamux.go | 14 ++++ misc/router-benchmark/routeHttprouter.go | 14 ++++ misc/router-benchmark/routeServeMux.go | 68 ++++++++++++++++ misc/router-benchmark/routerbenchmark_test.go | 79 ------------------- 5 files changed, 124 insertions(+), 79 deletions(-) create mode 100644 misc/router-benchmark/routeGorillamux.go create mode 100644 misc/router-benchmark/routeHttprouter.go create mode 100644 misc/router-benchmark/routeServeMux.go diff --git a/misc/router-benchmark/README.md b/misc/router-benchmark/README.md index 3a90b138..375aebbb 100644 --- a/misc/router-benchmark/README.md +++ b/misc/router-benchmark/README.md @@ -11,3 +11,31 @@ Benchmark_ServeMux-7 3167156 374.2 ns/op 80 Benchmark_gorillamux-7 760047 1560 ns/op 1312 B/op 10 allocs/op Benchmark_httprouter-7 3195236 371.7 ns/op 504 B/op 5 allocs/op ``` + +## Lines of code +`cloc routeServeMux.go` +```shell +------------------------------------------------------------------------------- +Language files blank comment code +------------------------------------------------------------------------------- +Go 1 6 9 53 +------------------------------------------------------------------------------- +``` + +`cloc routeGorillamux.go` +```shell +------------------------------------------------------------------------------- +Language files blank comment code +------------------------------------------------------------------------------- +Go 1 2 1 11 +------------------------------------------------------------------------------- +``` + +`cloc routeHttprouter.go` +```shell +------------------------------------------------------------------------------- +Language files blank comment code +------------------------------------------------------------------------------- +Go 1 2 1 11 +------------------------------------------------------------------------------- +``` \ No newline at end of file diff --git a/misc/router-benchmark/routeGorillamux.go b/misc/router-benchmark/routeGorillamux.go new file mode 100644 index 00000000..d2f61d52 --- /dev/null +++ b/misc/router-benchmark/routeGorillamux.go @@ -0,0 +1,14 @@ +package router_benchmark + +import ( + "github.com/gorilla/mux" + "net/http" +) + +// getBoards is the handler for `/v1/boards` with GET method +func getBoardArticles_gorillamux(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + boardID := params["boardID"] + _ = boardID + w.WriteHeader(200) +} diff --git a/misc/router-benchmark/routeHttprouter.go b/misc/router-benchmark/routeHttprouter.go new file mode 100644 index 00000000..428851c0 --- /dev/null +++ b/misc/router-benchmark/routeHttprouter.go @@ -0,0 +1,14 @@ +package router_benchmark + +import ( + "github.com/julienschmidt/httprouter" + "net/http" +) + +// getBoards is the handler for `/v1/boards` with GET method +func getBoardArticles_httprouter(w http.ResponseWriter, r *http.Request) { + params := httprouter.ParamsFromContext(r.Context()) + boardID := params.ByName("boardID") + _ = boardID + w.WriteHeader(200) +} diff --git a/misc/router-benchmark/routeServeMux.go b/misc/router-benchmark/routeServeMux.go new file mode 100644 index 00000000..b83d12a0 --- /dev/null +++ b/misc/router-benchmark/routeServeMux.go @@ -0,0 +1,68 @@ +package router_benchmark + +import ( + "net/http" + "strings" +) + +// getBoards is the handler for `/v1/boards` with GET method +func getBoards(w http.ResponseWriter, r *http.Request) { + boardID, item, filename, _ := parseBoardPath(r.URL.Path) + if boardID == "" { + //delivery.getBoardList(w, r) + w.WriteHeader(http.StatusNotFound) + return + } + // get single board + if item == "information" { + w.WriteHeader(http.StatusNotFound) + return + } else if item == "settings" { + //delivery.getBoardSettings(w, r, boardID) + w.WriteHeader(http.StatusNotFound) + return + } else if item == "articles" { + if filename == "" { + getBoardArticles(w, r, boardID) + } else { + w.WriteHeader(http.StatusNotFound) + } + return + } else if item == "treasures" { + w.WriteHeader(http.StatusNotFound) + return + } + + // 404 + w.WriteHeader(http.StatusNotFound) +} + +// parseBoardPath covert url path from /v1/boards/SYSOP/article to +// {SYSOP, article) or /v1/boards to {,} +func parseBoardPath(path string) (boardID string, item string, filename string, err error) { + pathSegment := strings.Split(path, "/") + + if len(pathSegment) >= 6 { + boardID = pathSegment[3] + item = pathSegment[4] + filename = pathSegment[5] + return + } else if len(pathSegment) == 5 { + boardID = pathSegment[3] + item = pathSegment[4] + return + } else if len(pathSegment) == 4 { + boardID = pathSegment[3] + return + } else if len(pathSegment) == 3 { + return + } + return +} + +// getBoardArticles handles request with `/v1/boards/SYSOP/articles` and will return +// article list to client +func getBoardArticles(w http.ResponseWriter, _ *http.Request, boardID string) { + _ = boardID + w.WriteHeader(200) +} diff --git a/misc/router-benchmark/routerbenchmark_test.go b/misc/router-benchmark/routerbenchmark_test.go index db8baef6..a51c4975 100644 --- a/misc/router-benchmark/routerbenchmark_test.go +++ b/misc/router-benchmark/routerbenchmark_test.go @@ -5,7 +5,6 @@ import ( "github.com/julienschmidt/httprouter" "net/http" "net/http/httptest" - "strings" "testing" ) @@ -42,81 +41,3 @@ func runTest(b *testing.B, r http.Handler, rr *httptest.ResponseRecorder) { } } } - -// getBoards is the handler for `/v1/boards` with GET method -func getBoards(w http.ResponseWriter, r *http.Request) { - boardID, item, filename, _ := parseBoardPath(r.URL.Path) - if boardID == "" { - //delivery.getBoardList(w, r) - w.WriteHeader(http.StatusNotFound) - return - } - // get single board - if item == "information" { - w.WriteHeader(http.StatusNotFound) - return - } else if item == "settings" { - //delivery.getBoardSettings(w, r, boardID) - w.WriteHeader(http.StatusNotFound) - return - } else if item == "articles" { - if filename == "" { - getBoardArticles(w, r, boardID) - } else { - w.WriteHeader(http.StatusNotFound) - } - return - } else if item == "treasures" { - w.WriteHeader(http.StatusNotFound) - return - } - - // 404 - w.WriteHeader(http.StatusNotFound) -} - -// parseBoardPath covert url path from /v1/boards/SYSOP/article to -// {SYSOP, article) or /v1/boards to {,} -func parseBoardPath(path string) (boardID string, item string, filename string, err error) { - pathSegment := strings.Split(path, "/") - - if len(pathSegment) >= 6 { - boardID = pathSegment[3] - item = pathSegment[4] - filename = pathSegment[5] - return - } else if len(pathSegment) == 5 { - boardID = pathSegment[3] - item = pathSegment[4] - return - } else if len(pathSegment) == 4 { - boardID = pathSegment[3] - return - } else if len(pathSegment) == 3 { - return - } - return -} - -// getBoardArticles handles request with `/v1/boards/SYSOP/articles` and will return -// article list to client -func getBoardArticles(w http.ResponseWriter, _ *http.Request, boardID string) { - _ = boardID - w.WriteHeader(200) -} - -// getBoards is the handler for `/v1/boards` with GET method -func getBoardArticles_httprouter(w http.ResponseWriter, r *http.Request) { - params := httprouter.ParamsFromContext(r.Context()) - boardID := params.ByName("boardID") - _ = boardID - w.WriteHeader(200) -} - -// getBoards is the handler for `/v1/boards` with GET method -func getBoardArticles_gorillamux(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - boardID := params["boardID"] - _ = boardID - w.WriteHeader(200) -}