-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add a simple benchmark suite * add a simple benchmark suite * add a simple benchmark suite * add a simple benchmark suite
- Loading branch information
1 parent
a8f42b3
commit a6785be
Showing
8 changed files
with
300 additions
and
2 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Benchmarks | ||
|
||
To run the benchmark suite, navigate to the same folder and execute the main.go file. | ||
This suite will test the performance of hypermatch with plain Go objects, hypermatch with JSON objects, and [quamina](https://github.com/timbray/quamina) against each other. | ||
Simply run the command go run main.go to start the benchmarks and compare the results. | ||
|
||
Results as of Aug, 29th, 2024 with Go 1.23.0 on MacBook Pro M1 Max, 32GB RAM with 100,000 rules: | ||
|
||
``` | ||
---Starting with hypermatch | ||
adding 100000 rules took 0.51862s | ||
processed 51753 events with 517530 matches in 1.00001s -> 51752.42425 evt/s | ||
processed 103199 events with 1031990 matches in 2.00004s -> 51598.36053 evt/s | ||
processed 156249 events with 1562490 matches in 3.00009s -> 52081.45563 evt/s | ||
processed 209523 events with 2095230 matches in 4.00013s -> 52379.05586 evt/s | ||
processed 262257 events with 2622570 matches in 5.00016s -> 52449.76793 evt/s | ||
---Starting with hypermatch-json | ||
adding 100000 rules took 1.95150s | ||
processed 39732 events with 397320 matches in 1.00000s -> 39731.90564 evt/s | ||
processed 80432 events with 804320 matches in 2.00003s -> 40215.31718 evt/s | ||
processed 121915 events with 1219150 matches in 3.00006s -> 40637.55840 evt/s | ||
processed 164093 events with 1640930 matches in 4.00009s -> 41022.33768 evt/s | ||
processed 206235 events with 2062350 matches in 5.00013s -> 41245.96473 evt/s | ||
---Starting with quamina | ||
adding 100000 rules took 4.54697s | ||
processed 4 events with 0 matches in 1.24154s -> 3.22181 evt/s | ||
processed 7 events with 0 matches in 2.31263s -> 3.02685 evt/s | ||
processed 11 events with 0 matches in 3.50818s -> 3.13552 evt/s | ||
processed 15 events with 0 matches in 4.70148s -> 3.19049 evt/s | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package candidates | ||
|
||
import ( | ||
"fmt" | ||
"github.com/SchwarzIT/hypermatch" | ||
"log" | ||
) | ||
|
||
type Hypermatch struct { | ||
h *hypermatch.HyperMatch | ||
} | ||
|
||
func NewHypermatch() *Hypermatch { | ||
return &Hypermatch{h: hypermatch.NewHyperMatch()} | ||
} | ||
|
||
func (h *Hypermatch) Name() string { | ||
return "hypermatch" | ||
} | ||
|
||
func (h *Hypermatch) AddRule(number int, modulo int) { | ||
err := h.h.AddRule(hypermatch.RuleIdentifier(number), hypermatch.ConditionSet{ | ||
{Path: "name", Pattern: hypermatch.Pattern{Type: hypermatch.PatternWildcard, Value: "*-myapp-*"}}, | ||
{Path: "env", Pattern: hypermatch.Pattern{Type: hypermatch.PatternEquals, Value: "prod"}}, | ||
{Path: "number", Pattern: hypermatch.Pattern{Type: hypermatch.PatternEquals, Value: fmt.Sprintf("%d", number%modulo)}}, | ||
{Path: "tags", Pattern: hypermatch.Pattern{ | ||
Type: hypermatch.PatternAllOf, Sub: []hypermatch.Pattern{ | ||
{Type: hypermatch.PatternEquals, Value: "tag1"}, | ||
{Type: hypermatch.PatternEquals, Value: "tag2"}, | ||
}, | ||
}}, | ||
{Path: "region", Pattern: hypermatch.Pattern{ | ||
Type: hypermatch.PatternAnythingBut, Sub: []hypermatch.Pattern{ | ||
{Type: hypermatch.PatternEquals, Value: "moon"}, | ||
}, | ||
}}, | ||
{Path: "type", Pattern: hypermatch.Pattern{ | ||
Type: hypermatch.PatternAnyOf, Sub: []hypermatch.Pattern{ | ||
{Type: hypermatch.PatternEquals, Value: "app"}, | ||
{Type: hypermatch.PatternEquals, Value: "database"}, | ||
}, | ||
}}, | ||
}) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
} | ||
|
||
func (h *Hypermatch) Match(number int, modulo int) int { | ||
event := []hypermatch.Property{ | ||
{ | ||
Path: "name", | ||
Values: []string{fmt.Sprintf("app-myapp-%d", number)}, | ||
}, | ||
{ | ||
Path: "env", | ||
Values: []string{"prod"}, | ||
}, | ||
{ | ||
Path: "number", | ||
Values: []string{fmt.Sprintf("%d", number%modulo)}, | ||
}, | ||
{ | ||
Path: "tags", | ||
Values: []string{"tag1", "tag2"}, | ||
}, | ||
{ | ||
Path: "region", | ||
Values: []string{"earth"}, | ||
}, | ||
{ | ||
Path: "type", | ||
Values: []string{"app"}, | ||
}, | ||
} | ||
matches := h.h.Match(event) | ||
return len(matches) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package candidates | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/SchwarzIT/hypermatch" | ||
) | ||
|
||
type HypermatchJson struct { | ||
h *hypermatch.HyperMatch | ||
} | ||
|
||
func NewHypermatchJson() *HypermatchJson { | ||
return &HypermatchJson{h: hypermatch.NewHyperMatch()} | ||
} | ||
|
||
func (h *HypermatchJson) Name() string { | ||
return "hypermatch-json" | ||
} | ||
|
||
func (h *HypermatchJson) AddRule(number int, modulo int) { | ||
jsonStr := fmt.Sprintf(` | ||
{ | ||
"name": {"wildcard": "*-myapp-*"}, | ||
"env": {"equals": "prod"}, | ||
"number": {"equals": "%d"}, | ||
"tags": {"allOf": [{"equals": "tag1"}, {"equals": "tag2"}]}, | ||
"region": {"anythingBut": [{"equals": "moon"}]}, | ||
"type": {"anyOf": [{"equals": "app"}, {"equals": "database"}]} | ||
} | ||
`, number%modulo) | ||
var conditionSet hypermatch.ConditionSet | ||
if err := json.Unmarshal([]byte(jsonStr), &conditionSet); err != nil { | ||
panic(err) | ||
} | ||
if err := h.h.AddRule(hypermatch.RuleIdentifier(number), conditionSet); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func (h *HypermatchJson) Match(number int, modulo int) int { | ||
eventStr := fmt.Sprintf(` | ||
[ | ||
{"Path": "name", "Values": ["app-myapp-%d"]}, | ||
{"Path": "env", "Values": ["prod"]}, | ||
{"Path": "number", "Values": ["%d"]}, | ||
{"Path": "tags", "Values": ["tag1", "tag2"]}, | ||
{"Path": "region", "Values": ["earth"]}, | ||
{"Path": "type", "Values": ["app"]} | ||
] | ||
`, number, number%modulo) | ||
|
||
var properties []hypermatch.Property | ||
if err := json.Unmarshal([]byte(eventStr), &properties); err != nil { | ||
panic(err) | ||
} | ||
|
||
matches := h.h.Match(properties) | ||
return len(matches) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package candidates | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"quamina.net/go/quamina" | ||
) | ||
|
||
type Quamina struct { | ||
q *quamina.Quamina | ||
} | ||
|
||
func NewQuamina() *Quamina { | ||
q, err := quamina.New(quamina.WithMediaType("application/json")) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return &Quamina{q: q} | ||
} | ||
|
||
func (q *Quamina) Name() string { | ||
return "quamina" | ||
} | ||
|
||
func (q *Quamina) AddRule(number int, modulo int) { | ||
str := fmt.Sprintf(` | ||
{ | ||
"name": [{"shellstyle": "*-myapp-*"}], | ||
"env": ["prod"], | ||
"nunmber": ["%d"], | ||
"tags": ["tag1", "tag2"], | ||
"region": [{"anything-but": ["moon"]}], | ||
"type": ["app", "database"] | ||
} | ||
`, number%modulo) | ||
err := q.q.AddPattern(number, str) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
} | ||
|
||
func (q *Quamina) Match(number int, modulo int) int { | ||
event := fmt.Sprintf(` | ||
{ | ||
"name": "app-myapp-%d", | ||
"env": "prod", | ||
"number": "%d", | ||
"tags": ["tag1", "tag2"], | ||
"region": "earth", | ||
"type": "app" | ||
} | ||
`, number, number%modulo) | ||
r, _ := q.q.MatchesForEvent([]byte(event)) | ||
return len(r) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module benchmark | ||
|
||
go 1.23.0 | ||
|
||
require ( | ||
github.com/SchwarzIT/hypermatch v0.1.0 | ||
quamina.net/go/quamina v1.3.0 | ||
) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
github.com/SchwarzIT/hypermatch v0.1.0 h1:ytJivIAFP++88WaiIFD/7+yl6Yz4gPfVNrodMe6Tmqc= | ||
github.com/SchwarzIT/hypermatch v0.1.0/go.mod h1:H/WStKuHk4FprRLaR6nBC2PY1oKNqIsDysiKREZLLcY= | ||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= | ||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= | ||
quamina.net/go/quamina v1.3.0 h1:8CI8InbNYbswmnda70fU2YItHxEb4cmq0p0mttBKL2w= | ||
quamina.net/go/quamina v1.3.0/go.mod h1:EJ1teLWOcAHYfOUE+w2B6OQq5sAxEiwE0EDlcRxx+TQ= |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"benchmark/candidates" | ||
"context" | ||
"log" | ||
"time" | ||
) | ||
|
||
const ( | ||
numberOfRules = 100000 | ||
eventCheckDuration = 5 * time.Second | ||
) | ||
|
||
type Candidate interface { | ||
Name() string | ||
AddRule(number int, modulo int) | ||
Match(number int, modulo int) int | ||
} | ||
|
||
func main() { | ||
cs := []Candidate{candidates.NewHypermatch(), candidates.NewHypermatchJson(), candidates.NewQuamina()} | ||
|
||
for _, c := range cs { | ||
log.Printf("---Starting with %s\n", c.Name()) | ||
beforeAddingRules := time.Now() | ||
|
||
for i := 0; i < numberOfRules; i++ { | ||
c.AddRule(i, numberOfRules/10) | ||
} | ||
log.Printf("adding %d rules took %.5fs\n", numberOfRules, time.Since(beforeAddingRules).Seconds()) | ||
runEvents(c) | ||
} | ||
} | ||
|
||
func runEvents(c Candidate) { | ||
numberOfEvents := 0 | ||
numberOfMatches := 0 | ||
beforeCheckingEvents := time.Now() | ||
lastPrint := beforeCheckingEvents | ||
ctx, cancel := context.WithTimeout(context.Background(), eventCheckDuration) | ||
defer cancel() | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
default: | ||
numberOfMatches += c.Match(numberOfMatches, numberOfRules/10) | ||
numberOfEvents += 1 | ||
|
||
if time.Since(lastPrint).Seconds() >= 1 { | ||
log.Printf("processed %d events with %d matches in %.5fs -> %.5f evt/s\n", numberOfEvents, numberOfMatches, time.Since(beforeCheckingEvents).Seconds(), float64(numberOfEvents)/time.Since(beforeCheckingEvents).Seconds()) | ||
lastPrint = time.Now() | ||
} | ||
} | ||
} | ||
} |