From cda9902346c5154b8b4ca61bfdb8d2f1f83b672b Mon Sep 17 00:00:00 2001 From: Changkun Ou Date: Sat, 2 Feb 2019 17:33:44 +0100 Subject: [PATCH] protocol: benchmarks for protocol parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This intend to give a benchmark comparison between Guacamole protocol and Occamy protocol design. name old time/op new time/op delta InstructionParser/occamy-0-6 325ns ± 2% 126ns ± 3% -61.16% (p=0.000 n=10+9) InstructionParser/occamy-1-6 54.3µs ± 1% 1.2µs ± 9% -97.73% (p=0.000 n=9+10) name old alloc/op new alloc/op delta InstructionParser/occamy-0-6 120B ± 0% 96B ± 0% -20.00% (p=0.000 n=10+10) InstructionParser/occamy-1-6 36.4kB ± 0% 8.3kB ± 0% -77.26% (p=0.000 n=10+10) name old allocs/op new allocs/op delta InstructionParser/occamy-0-6 7.00 ± 0% 3.00 ± 0% -57.14% (p=0.000 n=10+10) InstructionParser/occamy-1-6 23.0 ± 0% 3.0 ± 0% -86.96% (p=0.000 n=10+10) As we can see, eliminate the numbers of instruction length reduces the parsing cost significantly. See #3. --- README.md | 10 ++-- docker/docker-compose.yaml | 1 - docs/README.md | 32 ++++++----- protocol/benchmark_test.go | 104 ++++++++++++++++++++++++++++++++++ protocol/instruction.go | 111 +++++++++++++++++++------------------ 5 files changed, 185 insertions(+), 73 deletions(-) create mode 100644 protocol/benchmark_test.go diff --git a/README.md b/README.md index a2938c2..49b5041 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,15 @@ in a single middleware application. Any client that involves Guacamole protocol uses WebSocket for authentication can directly switch to interact to Occamy without any changes. -Read more details in [docs](./docs/README.md) +Read more details in [docs](./docs/README.md). + +## Routers + +Occamy offers two APIs `/api/v1/login`, which distribute JWT tokens for authentication and `/api/v1/connect` for WebSocket based Guacamole connection. These two APIs are simple enough to serve all users. ## Contributing -Easiest way to contribute is to provide feedback! -We would love to hear what you like and what you think is missing. -PRs are welcome. Please follow the given PR template before you send your pull request. +Easiest way to contribute is to provide feedback! We would love to hear what you like and what you think is missing. PRs are welcome. Please follow the given PR template before you send your pull request. ## Development diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index ba97508..71ca6e8 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -26,7 +26,6 @@ services: - "5636:5636" depends_on: - vnc - - rdp command: /go/src/github.com/changkun/occamy/occamyd -conf=./conf.yaml networks: occamy_network: diff --git a/docs/README.md b/docs/README.md index e91f54f..0a62e2b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,33 +9,37 @@ Futhermore, `guacd` manages connection in different processes, which can limits connection of Guacamole application. ``` -|-- Browser --|----- Guacamole Server ------|--- Intranet ---| +|-- Browser --|-------- Guacamole Server -----------|--- Intranet ---| -UserA ---+ +---- RDP server - +------ Guacamole Servlet | -UserB ---+ | +---- VNC server - +------- guacd -------+ - +---- Others +UserA --------+ +---- RDP server + +------ Guacamole Servlet | +UserB --------+ | +---- VNC server + +------- guacd -------+ + +---- Others ``` _Figure 1: Guacamole Architecture_ -Occamy solves these issue, and it uses JWT for authentication as default option, manages -all connection in mutiple thread rather than multiple processes. +Occamy solves these issues, and it uses JWT for authentication as default option, manages +all connection in mutiple thread rather than multiple processes, as shown in Figure 2. ``` -|-- Browser --|-- Occamy Server --|--- Intranet ---| +|-- Browser --|---- Occamy Server -----|--- Intranet ---| -UserA ---+ +---- RDP server - +------ Occamy ----------+ -UserB ---+ +---- VNC server - | - +---- Others +UserA --------+ +---- RDP server + +------ Occamy ----------+ +UserB --------+ +---- VNC server + | + +---- Others ``` _Figure 2: Occamy Architecture_ +## Protocol Instructions + +Refer to [Guacamole protocol reference](https://guacamole.apache.org/doc/gug/protocol-reference.html). Note that Occamy has no handshake process between client and Occamy, one can simply POST the connection information to Occamy for getting authentication tokens. + ## License diff --git a/protocol/benchmark_test.go b/protocol/benchmark_test.go new file mode 100644 index 0000000..7a024db --- /dev/null +++ b/protocol/benchmark_test.go @@ -0,0 +1,104 @@ +package protocol_test + +import ( + "fmt" + "os" + "strconv" + "strings" + "testing" + "unicode/utf8" + + "github.com/changkun/occamy/protocol" +) + +// ParseInstructionGuac parses an instruction: 1.a,2.bc,3.def,10.abcdefghij; +func ParseInstructionGuac(raw []byte) (ins *protocol.Instruction, err error) { + var ( + cursor int + elements []string + ) + + bytes := len(raw) + for cursor < bytes { + + // 1. parse digit + lengthEnd := -1 + for i := cursor; i < bytes; i++ { + if raw[i] == '.' { + lengthEnd = i + break + } + } + if lengthEnd == -1 { // cannot find '.' + return nil, protocol.ErrInstructionMissDot + } + length, err := strconv.Atoi(string(raw[cursor:lengthEnd])) + if err != nil { + return nil, protocol.ErrInstructionBadDigit + } + + // 2. parse rune + cursor = lengthEnd + 1 + element := new(strings.Builder) + for i := 1; i <= length; i++ { + r, n := utf8.DecodeRune(raw[cursor:]) + if r == utf8.RuneError { + return nil, protocol.ErrInstructionBadRune + } + cursor += n + element.WriteRune(r) + } + elements = append(elements, element.String()) + + // 3. done + if cursor == bytes-1 { + break + } + + // 4. parse next + if raw[cursor] != ',' { + return nil, protocol.ErrInstructionMissComma + } + + cursor++ + } + + return protocol.NewInstruction(elements), nil +} + +// ParseInstructionOccamy parses an instruction: a,bc,def,abcdefghij; +func ParseInstructionOccamy(raw []byte) (ins *protocol.Instruction, err error) { + if string(raw[len(raw)-1]) != ";" { + return nil, protocol.ErrInstructionMissSemi + } + + elements := strings.Split(string(raw)[:len(raw)-1], ",") + return protocol.NewInstruction(elements), nil +} + +func BenchmarkInstructionParser(b *testing.B) { + guacamoleProtocol := [][]byte{ + []byte("4.sync,11.10574782313;"), + []byte("4.blob,1.1,8064.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;"), + } + occamyProtocol := [][]byte{ + []byte("sync,10574782313;"), + []byte("blob,1,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;"), + } + + parser := ParseInstructionGuac + ins := guacamoleProtocol + proto := os.Getenv("PROTO") + if proto == "occamy" { + parser = ParseInstructionOccamy + ins = occamyProtocol + } + + for idx := range ins { + b.Run(fmt.Sprintf("occamy-%d", idx), func(b *testing.B) { + for i := 0; i < b.N; i++ { + parser(ins[idx]) + } + }) + } +} diff --git a/protocol/instruction.go b/protocol/instruction.go index 5ca1f06..6dfdfd1 100644 --- a/protocol/instruction.go +++ b/protocol/instruction.go @@ -20,6 +20,7 @@ const MaxInstructionLength = 8192 var ( ErrInstructionMissDot = errors.New("instruction without dot") ErrInstructionMissComma = errors.New("instruction without comma") + ErrInstructionMissSemi = errors.New("instruction withou semi") ErrInstructionBadDigit = errors.New("instruction with bad digit") ErrInstructionBadRune = errors.New("instruction with bad rune") ) @@ -34,6 +35,61 @@ func NewInstruction(elements []string) *Instruction { return &Instruction{elements} } +// ParseInstruction parses an instruction: 1.a,2.bc,3.def,10.abcdefghij; +func ParseInstruction(raw []byte) (ins *Instruction, err error) { + var ( + cursor int + elements []string + ) + + bytes := len(raw) + for cursor < bytes { + + // 1. parse digit + lengthEnd := -1 + for i := cursor; i < bytes; i++ { + if raw[i]^'.' == 0 { + lengthEnd = i + break + } + } + if lengthEnd == -1 { // cannot find '.' + return nil, ErrInstructionMissDot + } + length, err := strconv.Atoi(string(raw[cursor:lengthEnd])) + if err != nil { + return nil, ErrInstructionBadDigit + } + + // 2. parse rune + cursor = lengthEnd + 1 + element := new(strings.Builder) + for i := 1; i <= length; i++ { + r, n := utf8.DecodeRune(raw[cursor:]) + if r == utf8.RuneError { + return nil, ErrInstructionBadRune + } + cursor += n + element.WriteRune(r) + } + elements = append(elements, element.String()) + + // 3. done + if cursor == bytes-1 { + break + } + + // 4. parse next + if raw[cursor]^',' != 0 { + return nil, ErrInstructionMissComma + } + + cursor++ + } + + return NewInstruction(elements), nil +} + func (i Instruction) String() string { buffer := new(bytes.Buffer) buffer.WriteString(strconv.FormatInt(int64(utf8.RuneCountInString(i.elements[0])), 10)) @@ -98,60 +154,7 @@ func (io *InstructionIO) Read() (*Instruction, error) { if err != nil { return nil, err } - - var ( - cursor int - elements []string - ) - - // an instruction: - // 1.a,2.bc,3.def,10.abcdefghij; - bytes := len(raw) - for cursor < bytes { - - // 1. parse digit - lengthEnd := -1 - for i := cursor; i < bytes; i++ { - if raw[i]^'.' == 0 { - lengthEnd = i - break - } - } - if lengthEnd == -1 { // cannot find '.' - return nil, ErrInstructionMissDot - } - length, err := strconv.Atoi(string(raw[cursor:lengthEnd])) - if err != nil { - return nil, ErrInstructionBadDigit - } - - // 2. parse rune - cursor = lengthEnd + 1 - element := new(strings.Builder) - for i := 1; i <= length; i++ { - r, n := utf8.DecodeRune(raw[cursor:]) - if r == utf8.RuneError { - return nil, ErrInstructionBadRune - } - cursor += n - element.WriteRune(r) - } - elements = append(elements, element.String()) - - // 3. done - if cursor == bytes-1 { - break - } - - // 4. parse next - if raw[cursor]^',' != 0 { - return nil, ErrInstructionMissComma - } - - cursor++ - } - - return NewInstruction(elements), nil + return ParseInstruction(raw) } // WriteRaw writes raw buffer into io output