|
| 1 | +package router |
| 2 | + |
| 3 | +import ( |
| 4 | + "net/http" |
| 5 | + "net/http/httptest" |
| 6 | + "testing" |
| 7 | +) |
| 8 | + |
| 9 | +type route struct { |
| 10 | + method string |
| 11 | + path string |
| 12 | +} |
| 13 | + |
| 14 | +var staticRoutes = []route{ |
| 15 | + {"GET", "/"}, |
| 16 | + {"GET", "/cmd.html"}, |
| 17 | + {"GET", "/code.html"}, |
| 18 | + {"GET", "/contrib.html"}, |
| 19 | + {"GET", "/contribute.html"}, |
| 20 | + {"GET", "/debugging_with_gdb.html"}, |
| 21 | + {"GET", "/docs.html"}, |
| 22 | + {"GET", "/effective_go.html"}, |
| 23 | + {"GET", "/files.log"}, |
| 24 | + {"GET", "/gccgo_contribute.html"}, |
| 25 | + {"GET", "/gccgo_install.html"}, |
| 26 | + {"GET", "/go-logo-black.png"}, |
| 27 | + {"GET", "/go-logo-blue.png"}, |
| 28 | + {"GET", "/go-logo-white.png"}, |
| 29 | + {"GET", "/go1.1.html"}, |
| 30 | + {"GET", "/go1.2.html"}, |
| 31 | + {"GET", "/go1.html"}, |
| 32 | + {"GET", "/go1compat.html"}, |
| 33 | + {"GET", "/go_faq.html"}, |
| 34 | + {"GET", "/go_mem.html"}, |
| 35 | + {"GET", "/go_spec.html"}, |
| 36 | + {"GET", "/help.html"}, |
| 37 | + {"GET", "/ie.css"}, |
| 38 | + {"GET", "/install-source.html"}, |
| 39 | + {"GET", "/install.html"}, |
| 40 | + {"GET", "/logo-153x55.png"}, |
| 41 | + {"GET", "/Makefile"}, |
| 42 | + {"GET", "/root.html"}, |
| 43 | + {"GET", "/share.png"}, |
| 44 | + {"GET", "/sieve.gif"}, |
| 45 | + {"GET", "/tos.html"}, |
| 46 | + {"GET", "/articles/"}, |
| 47 | + {"GET", "/articles/go_command.html"}, |
| 48 | + {"GET", "/articles/index.html"}, |
| 49 | + {"GET", "/articles/wiki/"}, |
| 50 | + {"GET", "/articles/wiki/edit.html"}, |
| 51 | + {"GET", "/articles/wiki/final-noclosure.go"}, |
| 52 | + {"GET", "/articles/wiki/final-noerror.go"}, |
| 53 | + {"GET", "/articles/wiki/final-parsetemplate.go"}, |
| 54 | + {"GET", "/articles/wiki/final-template.go"}, |
| 55 | + {"GET", "/articles/wiki/final.go"}, |
| 56 | + {"GET", "/articles/wiki/get.go"}, |
| 57 | + {"GET", "/articles/wiki/http-sample.go"}, |
| 58 | + {"GET", "/articles/wiki/index.html"}, |
| 59 | + {"GET", "/articles/wiki/Makefile"}, |
| 60 | + {"GET", "/articles/wiki/notemplate.go"}, |
| 61 | + {"GET", "/articles/wiki/part1-noerror.go"}, |
| 62 | + {"GET", "/articles/wiki/part1.go"}, |
| 63 | + {"GET", "/articles/wiki/part2.go"}, |
| 64 | + {"GET", "/articles/wiki/part3-errorhandling.go"}, |
| 65 | + {"GET", "/articles/wiki/part3.go"}, |
| 66 | + {"GET", "/articles/wiki/test.bash"}, |
| 67 | + {"GET", "/articles/wiki/test_edit.good"}, |
| 68 | + {"GET", "/articles/wiki/test_Test.txt.good"}, |
| 69 | + {"GET", "/articles/wiki/test_view.good"}, |
| 70 | + {"GET", "/articles/wiki/view.html"}, |
| 71 | + {"GET", "/codewalk/"}, |
| 72 | + {"GET", "/codewalk/codewalk.css"}, |
| 73 | + {"GET", "/codewalk/codewalk.js"}, |
| 74 | + {"GET", "/codewalk/codewalk.xml"}, |
| 75 | + {"GET", "/codewalk/functions.xml"}, |
| 76 | + {"GET", "/codewalk/markov.go"}, |
| 77 | + {"GET", "/codewalk/markov.xml"}, |
| 78 | + {"GET", "/codewalk/pig.go"}, |
| 79 | + {"GET", "/codewalk/popout.png"}, |
| 80 | + {"GET", "/codewalk/run"}, |
| 81 | + {"GET", "/codewalk/sharemem.xml"}, |
| 82 | + {"GET", "/codewalk/urlpoll.go"}, |
| 83 | + {"GET", "/devel/"}, |
| 84 | + {"GET", "/devel/release.html"}, |
| 85 | + {"GET", "/devel/weekly.html"}, |
| 86 | + {"GET", "/gopher/"}, |
| 87 | + {"GET", "/gopher/appenginegopher.jpg"}, |
| 88 | + {"GET", "/gopher/appenginegophercolor.jpg"}, |
| 89 | + {"GET", "/gopher/appenginelogo.gif"}, |
| 90 | + {"GET", "/gopher/bumper.png"}, |
| 91 | + {"GET", "/gopher/bumper192x108.png"}, |
| 92 | + {"GET", "/gopher/bumper320x180.png"}, |
| 93 | + {"GET", "/gopher/bumper480x270.png"}, |
| 94 | + {"GET", "/gopher/bumper640x360.png"}, |
| 95 | + {"GET", "/gopher/doc.png"}, |
| 96 | + {"GET", "/gopher/frontpage.png"}, |
| 97 | + {"GET", "/gopher/gopherbw.png"}, |
| 98 | + {"GET", "/gopher/gophercolor.png"}, |
| 99 | + {"GET", "/gopher/gophercolor16x16.png"}, |
| 100 | + {"GET", "/gopher/help.png"}, |
| 101 | + {"GET", "/gopher/pkg.png"}, |
| 102 | + {"GET", "/gopher/project.png"}, |
| 103 | + {"GET", "/gopher/ref.png"}, |
| 104 | + {"GET", "/gopher/run.png"}, |
| 105 | + {"GET", "/gopher/talks.png"}, |
| 106 | + {"GET", "/gopher/pencil/"}, |
| 107 | + {"GET", "/gopher/pencil/gopherhat.jpg"}, |
| 108 | + {"GET", "/gopher/pencil/gopherhelmet.jpg"}, |
| 109 | + {"GET", "/gopher/pencil/gophermega.jpg"}, |
| 110 | + {"GET", "/gopher/pencil/gopherrunning.jpg"}, |
| 111 | + {"GET", "/gopher/pencil/gopherswim.jpg"}, |
| 112 | + {"GET", "/gopher/pencil/gopherswrench.jpg"}, |
| 113 | + {"GET", "/play/"}, |
| 114 | + {"GET", "/play/fib.go"}, |
| 115 | + {"GET", "/play/hello.go"}, |
| 116 | + {"GET", "/play/life.go"}, |
| 117 | + {"GET", "/play/peano.go"}, |
| 118 | + {"GET", "/play/pi.go"}, |
| 119 | + {"GET", "/play/sieve.go"}, |
| 120 | + {"GET", "/play/solitaire.go"}, |
| 121 | + {"GET", "/play/tree.go"}, |
| 122 | + {"GET", "/progs/"}, |
| 123 | + {"GET", "/progs/cgo1.go"}, |
| 124 | + {"GET", "/progs/cgo2.go"}, |
| 125 | + {"GET", "/progs/cgo3.go"}, |
| 126 | + {"GET", "/progs/cgo4.go"}, |
| 127 | + {"GET", "/progs/defer.go"}, |
| 128 | + {"GET", "/progs/defer.out"}, |
| 129 | + {"GET", "/progs/defer2.go"}, |
| 130 | + {"GET", "/progs/defer2.out"}, |
| 131 | + {"GET", "/progs/eff_bytesize.go"}, |
| 132 | + {"GET", "/progs/eff_bytesize.out"}, |
| 133 | + {"GET", "/progs/eff_qr.go"}, |
| 134 | + {"GET", "/progs/eff_sequence.go"}, |
| 135 | + {"GET", "/progs/eff_sequence.out"}, |
| 136 | + {"GET", "/progs/eff_unused1.go"}, |
| 137 | + {"GET", "/progs/eff_unused2.go"}, |
| 138 | + {"GET", "/progs/error.go"}, |
| 139 | + {"GET", "/progs/error2.go"}, |
| 140 | + {"GET", "/progs/error3.go"}, |
| 141 | + {"GET", "/progs/error4.go"}, |
| 142 | + {"GET", "/progs/go1.go"}, |
| 143 | + {"GET", "/progs/gobs1.go"}, |
| 144 | + {"GET", "/progs/gobs2.go"}, |
| 145 | + {"GET", "/progs/image_draw.go"}, |
| 146 | + {"GET", "/progs/image_package1.go"}, |
| 147 | + {"GET", "/progs/image_package1.out"}, |
| 148 | + {"GET", "/progs/image_package2.go"}, |
| 149 | + {"GET", "/progs/image_package2.out"}, |
| 150 | + {"GET", "/progs/image_package3.go"}, |
| 151 | + {"GET", "/progs/image_package3.out"}, |
| 152 | + {"GET", "/progs/image_package4.go"}, |
| 153 | + {"GET", "/progs/image_package4.out"}, |
| 154 | + {"GET", "/progs/image_package5.go"}, |
| 155 | + {"GET", "/progs/image_package5.out"}, |
| 156 | + {"GET", "/progs/image_package6.go"}, |
| 157 | + {"GET", "/progs/image_package6.out"}, |
| 158 | + {"GET", "/progs/interface.go"}, |
| 159 | + {"GET", "/progs/interface2.go"}, |
| 160 | + {"GET", "/progs/interface2.out"}, |
| 161 | + {"GET", "/progs/json1.go"}, |
| 162 | + {"GET", "/progs/json2.go"}, |
| 163 | + {"GET", "/progs/json2.out"}, |
| 164 | + {"GET", "/progs/json3.go"}, |
| 165 | + {"GET", "/progs/json4.go"}, |
| 166 | + {"GET", "/progs/json5.go"}, |
| 167 | + {"GET", "/progs/run"}, |
| 168 | + {"GET", "/progs/slices.go"}, |
| 169 | + {"GET", "/progs/timeout1.go"}, |
| 170 | + {"GET", "/progs/timeout2.go"}, |
| 171 | + {"GET", "/progs/update.bash"}, |
| 172 | +} |
| 173 | + |
| 174 | +func init() { |
| 175 | + |
| 176 | + staticRouter = loadRouter(staticRoutes) |
| 177 | +} |
| 178 | + |
| 179 | +var ( |
| 180 | + staticRouter http.Handler |
| 181 | +) |
| 182 | + |
| 183 | +func routerHandle(_ *Control) {} |
| 184 | + |
| 185 | +func loadRouter(routes []route) http.Handler { |
| 186 | + r := New() |
| 187 | + for _, route := range routes { |
| 188 | + r.Handle(route.method, route.path, routerHandle) |
| 189 | + } |
| 190 | + return r |
| 191 | +} |
| 192 | + |
| 193 | +func benchRequest(b *testing.B, router http.Handler, r *http.Request) { |
| 194 | + w := httptest.NewRecorder() |
| 195 | + u := r.URL |
| 196 | + rq := u.RawQuery |
| 197 | + r.RequestURI = u.RequestURI() |
| 198 | + |
| 199 | + b.ReportAllocs() |
| 200 | + b.ResetTimer() |
| 201 | + |
| 202 | + for i := 0; i < b.N; i++ { |
| 203 | + u.RawQuery = rq |
| 204 | + router.ServeHTTP(w, r) |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +func benchRoutes(b *testing.B, router http.Handler, routes []route) { |
| 209 | + w := httptest.NewRecorder() |
| 210 | + r, _ := http.NewRequest("GET", "/", nil) |
| 211 | + u := r.URL |
| 212 | + rq := u.RawQuery |
| 213 | + |
| 214 | + b.ReportAllocs() |
| 215 | + b.ResetTimer() |
| 216 | + |
| 217 | + for i := 0; i < b.N; i++ { |
| 218 | + for _, route := range routes { |
| 219 | + r.Method = route.method |
| 220 | + r.RequestURI = route.path |
| 221 | + u.Path = route.path |
| 222 | + u.RawQuery = rq |
| 223 | + router.ServeHTTP(w, r) |
| 224 | + } |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | +func BenchmarkRouter_StaticAll(b *testing.B) { |
| 229 | + benchRoutes(b, staticRouter, staticRoutes) |
| 230 | +} |
| 231 | + |
| 232 | +func BenchmarkRouter_Param(b *testing.B) { |
| 233 | + router := New() |
| 234 | + router.Handle("GET", "/user/:name", routerHandle) |
| 235 | + |
| 236 | + r, _ := http.NewRequest("GET", "/user/jhon", nil) |
| 237 | + benchRequest(b, router, r) |
| 238 | +} |
| 239 | + |
| 240 | +const fiveColon = "/:a/:b/:c/:d/:e" |
| 241 | +const fiveRoute = "/a/b/c/d/e" |
| 242 | + |
| 243 | +func BenchmarkRouter_Param5(b *testing.B) { |
| 244 | + router := New() |
| 245 | + router.Handle("GET", fiveColon, routerHandle) |
| 246 | + |
| 247 | + r, _ := http.NewRequest("GET", fiveRoute, nil) |
| 248 | + benchRequest(b, router, r) |
| 249 | +} |
| 250 | + |
| 251 | +const twentyColon = "/:a/:b/:c/:d/:e/:f/:g/:h/:i/:j/:k/:l/:m/:n/:o/:p/:q/:r/:s/:t" |
| 252 | +const twentyRoute = "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t" |
| 253 | + |
| 254 | +func BenchmarkRouter_Param20(b *testing.B) { |
| 255 | + router := New() |
| 256 | + router.Handle("GET", twentyColon, routerHandle) |
| 257 | + |
| 258 | + r, _ := http.NewRequest("GET", twentyRoute, nil) |
| 259 | + benchRequest(b, router, r) |
| 260 | +} |
| 261 | + |
| 262 | +func BenchmarkRouter_ParamWrite(b *testing.B) { |
| 263 | + router := New() |
| 264 | + router.Handle("GET", "/user/:name", routerHandle) |
| 265 | + |
| 266 | + r, _ := http.NewRequest("GET", "/user/jhon", nil) |
| 267 | + benchRequest(b, router, r) |
| 268 | +} |
0 commit comments