Created
September 24, 2015 17:31
-
-
Save axdg/44974b4c8aedd9fe583a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
github.com/axdg/echo | |
BenchmarkEcho_Param 20000000 114 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Param5 10000000 217 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Param20 2000000 634 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParamWrite 5000000 244 ns/op 16 B/op 1 allocs/op | |
BenchmarkEcho_GithubStatic 10000000 151 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GithubParam 5000000 258 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GithubAll 30000 54910 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusStatic 20000000 107 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusParam 10000000 148 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlus2Params 10000000 218 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusAll 500000 2739 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseStatic 20000000 110 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseParam 10000000 130 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Parse2Params 10000000 159 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseAll 300000 4904 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_StaticAll 50000 38429 ns/op 0 B/op 0 allocs/op | |
github.com/labstack/echo | |
BenchmarkEcho_Param 20000000 107 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Param5 10000000 209 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Param20 2000000 613 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParamWrite 5000000 263 ns/op 16 B/op 1 allocs/op | |
BenchmarkEcho_GithubStatic 10000000 139 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GithubParam 5000000 254 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GithubAll 30000 55460 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusStatic 20000000 100 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusParam 10000000 143 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlus2Params 10000000 206 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_GPlusAll 500000 2723 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseStatic 20000000 106 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseParam 10000000 127 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_Parse2Params 10000000 161 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_ParseAll 300000 5874 ns/op 0 B/op 0 allocs/op | |
BenchmarkEcho_StaticAll 30000 43592 ns/op 0 B/op 0 allocs/op |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package findmethod | |
// Mock Echo router for testing | |
type Router struct { | |
connectTree *node | |
deleteTree *node | |
getTree *node | |
headTree *node | |
optionsTree *node | |
patchTree *node | |
postTree *node | |
putTree *node | |
traceTree *node | |
} | |
// Mock Echo node for testing | |
type node struct { | |
label byte | |
} | |
// HTTP Method constants | |
const ( | |
// CONNECT HTTP method | |
CONNECT = "CONNECT" | |
// DELETE HTTP method | |
DELETE = "DELETE" | |
// GET HTTP method | |
GET = "GET" | |
// HEAD HTTP method | |
HEAD = "HEAD" | |
// OPTIONS HTTP method | |
OPTIONS = "OPTIONS" | |
// PATCH HTTP method | |
PATCH = "PATCH" | |
// POST HTTP method | |
POST = "POST" | |
// PUT HTTP method | |
PUT = "PUT" | |
// TRACE HTTP method | |
TRACE = "TRACE" | |
) | |
// New router returns a new router | |
func NewRouter() *Router { | |
return &Router{ | |
connectTree: new(node), | |
deleteTree: new(node), | |
getTree: new(node), | |
headTree: new(node), | |
optionsTree: new(node), | |
patchTree: new(node), | |
postTree: new(node), | |
putTree: new(node), | |
traceTree: new(node), | |
} | |
} | |
// findTreeWithSwitch | |
func (r *Router) findTreeWithSwitch(method string) (n *node) { | |
switch method { | |
case GET: | |
return r.getTree | |
case DELETE: | |
return r.deleteTree | |
case POST: | |
return r.postTree | |
case PUT: | |
return r.putTree | |
case OPTIONS: | |
return r.optionsTree | |
case PATCH: | |
return r.patchTree | |
case HEAD: | |
return r.headTree | |
case CONNECT: | |
return r.connectTree | |
case TRACE: | |
return r.traceTree | |
} | |
return nil | |
} | |
// findTreeWithSwitchOpt | |
func (r *Router) findTreeWithSwitchOpt(method string) (n *node) { | |
if method == GET { | |
return r.getTree | |
} else if method == POST { | |
return r.postTree | |
} else if method == DELETE { | |
return r.deleteTree | |
} else if method == PUT { | |
return r.putTree | |
} | |
switch method { | |
case OPTIONS: | |
return r.optionsTree | |
case PATCH: | |
return r.patchTree | |
case HEAD: | |
return r.headTree | |
case CONNECT: | |
return r.connectTree | |
case TRACE: | |
return r.traceTree | |
} | |
return nil | |
} | |
func findUncommonTree(r *Router, method string) (n *node) { | |
switch method { | |
case OPTIONS: | |
return r.optionsTree | |
case PATCH: | |
return r.patchTree | |
case HEAD: | |
return r.headTree | |
case CONNECT: | |
return r.connectTree | |
case TRACE: | |
return r.traceTree | |
} | |
return nil | |
} | |
func findCommonTree(r *Router, method string) (n *node) { | |
if method == POST { | |
return r.postTree | |
} else if method == DELETE { | |
return r.deleteTree | |
} | |
if method[1] == 0x55 { | |
if method[0] == 0x50 && method[2] == 0x54 { | |
return r.putTree | |
} | |
} | |
return findUncommonTree(r, method) | |
} | |
func (r *Router) findTreeWithSwitchOverOpt(method string) (n *node) { | |
if method == GET { | |
return r.getTree | |
} | |
return findCommonTree(r, method) | |
} | |
// findTreeWithHashSwitch | |
func (r *Router) findTreeWithHashSwitch(method string) (n *node) { | |
switch method[0] { | |
case 'G': // GET | |
m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24 | |
if m == 0x47455400 { | |
n = r.getTree | |
} | |
case 'P': // POST, PUT or PATCH | |
switch method[1] { | |
case 'O': // POST | |
m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 | | |
uint32(method[0])<<24 | |
if m == 0x504f5354 { | |
n = r.postTree | |
} | |
case 'U': // PUT | |
m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24 | |
if m == 0x50555400 { | |
n = r.putTree | |
} | |
case 'A': // PATCH | |
m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 | | |
uint64(method[1])<<48 | uint64(method[0])<<56 | |
if m == 0x5041544348000000 { | |
n = r.patchTree | |
} | |
} | |
case 'D': // DELETE | |
m := uint64(method[5])<<16 | uint64(method[4])<<24 | uint64(method[3])<<32 | | |
uint64(method[2])<<40 | uint64(method[1])<<48 | uint64(method[0])<<56 | |
if m == 0x44454c4554450000 { | |
n = r.deleteTree | |
} | |
case 'C': // CONNECT | |
m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 | | |
uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 | | |
uint64(method[0])<<56 | |
if m == 0x434f4e4e45435400 { | |
n = r.connectTree | |
} | |
case 'H': // HEAD | |
m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 | | |
uint32(method[0])<<24 | |
if m == 0x48454144 { | |
n = r.headTree | |
} | |
case 'O': // OPTIONS | |
m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 | | |
uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 | | |
uint64(method[0])<<56 | |
if m == 0x4f5054494f4e5300 { | |
n = r.optionsTree | |
} | |
case 'T': // TRACE | |
m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 | | |
uint64(method[1])<<48 | uint64(method[0])<<56 | |
if m == 0x5452414345000000 { | |
n = r.traceTree | |
} | |
} | |
return | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package findmethod | |
import ( | |
"testing" | |
"github.com/stretchr/testify/assert" | |
) | |
func TestFindTreeWithSwitch(t *testing.T) { | |
r := NewRouter() | |
methodShort := "G" | |
methodLong := "GETTER" | |
m := r.findTreeWithSwitch(methodLong) | |
assert.Nil(t, m) | |
r.findTreeWithSwitch(methodShort) | |
defer func() { | |
v := recover() | |
assert.Nil(t, v) | |
}() | |
} | |
// Calling findTreeWithHashSwitch and passing in a string that matches | |
// the first letter of a valid HTTP method but is shorter than that method | |
// will cause an index out of range panic. Calling findTreeWithHashSwitch | |
// and passing in a string that begins with a valid HTTP method will cause | |
// that method to be matched. | |
func TestFindTreeWithHashSwitch(t *testing.T) { | |
r := NewRouter() | |
methodLong := "GETTER" | |
methodShort := "G" | |
m := r.findTreeWithHashSwitch(methodLong) | |
assert.Nil(t, m) | |
r.findTreeWithHashSwitch(methodShort) | |
defer func() { | |
v := recover() | |
assert.Nil(t, v) | |
}() | |
} | |
func BenchmarkFindTreeWithSwitch_GET(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitch(GET) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOpt_GET(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOpt(GET) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOverOpt_GET(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOverOpt(GET) | |
} | |
} | |
func BenchmarkFindTreeWithHashSwitch_GET(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithHashSwitch(GET) | |
} | |
} | |
func BenchmarkFindTreeWithSwitch_DELETE(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitch(DELETE) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOpt_DELETE(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOpt(DELETE) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOverOpt_DELETE(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOverOpt(DELETE) | |
} | |
} | |
func BenchmarkFindTreeWithHashSwitch_DELETE(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithHashSwitch(DELETE) | |
} | |
} | |
func BenchmarkFindTreeWithSwitch_POST(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitch(POST) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOpt_POST(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOpt(POST) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOverOpt_POST(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOverOpt(POST) | |
} | |
} | |
func BenchmarkFindTreeWithHashSwitch_POST(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithHashSwitch(POST) | |
} | |
} | |
func BenchmarkFindTreeWithSwitch_PUT(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitch(PUT) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOpt_PUT(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOpt(PUT) | |
} | |
} | |
func BenchmarkFindTreeWithSwitchOverOpt_PUT(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithSwitchOverOpt(PUT) | |
} | |
} | |
func BenchmarkFindTreeWithHashSwitch_PUT(b *testing.B) { | |
r := NewRouter() | |
for n := 0; n < b.N; n++ { | |
r.findTreeWithHashSwitch(PUT) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To run the tests:
To run the benchmarks: