Skip to content

Commit

Permalink
add bench
Browse files Browse the repository at this point in the history
  • Loading branch information
kelindar committed Jul 14, 2021
1 parent c1ef184 commit 90e5237
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
43 changes: 43 additions & 0 deletions examples/bench/README.md
@@ -0,0 +1,43 @@
# Concurrency Benchmark

This is an example benchmark with various workloads (90% read / 10% write, etc) on a collection of 1 million elements with different goroutine pools. In this example we're combining two types of transactions:
* Read transactions that query a random index and iterate over the results over a single column.
* Write transactions that update a random element (point-write).

Note that the goal of this benchmark is to validater concurrency, not throughput this represents the current "best" case scenario when the updates are random and do less likely to incur contention. Reads, however quite often would hit the same chunks as only the index itself is randomized.

```
90%-10% 1 procs 143,221,213 read/s 70 write/s
90%-10% 8 procs 1,081,511,102 read/s 483 write/s
90%-10% 16 procs 1,068,562,727 read/s 455 write/s
90%-10% 32 procs 1,042,382,561 read/s 442 write/s
90%-10% 64 procs 1,039,644,346 read/s 446 write/s
90%-10% 128 procs 1,049,228,432 read/s 442 write/s
90%-10% 256 procs 1,027,362,194 read/s 477 write/s
90%-10% 512 procs 1,023,097,576 read/s 457 write/s
90%-10% 1024 procs 996,585,722 read/s 436 write/s
90%-10% 2048 procs 948,455,719 read/s 494 write/s
90%-10% 4096 procs 930,094,338 read/s 540 write/s
50%-50% 1 procs 142,015,047 read/s 598 write/s
50%-50% 8 procs 1,066,028,881 read/s 4,300 write/s
50%-50% 16 procs 1,039,210,987 read/s 4,191 write/s
50%-50% 32 procs 1,042,789,993 read/s 4,123 write/s
50%-50% 64 procs 1,040,410,050 read/s 4,102 write/s
50%-50% 128 procs 1,006,464,963 read/s 4,008 write/s
50%-50% 256 procs 1,008,663,071 read/s 4,170 write/s
50%-50% 512 procs 989,864,228 read/s 4,146 write/s
50%-50% 1024 procs 998,826,089 read/s 4,258 write/s
50%-50% 2048 procs 939,110,917 read/s 4,515 write/s
50%-50% 4096 procs 866,137,428 read/s 5,291 write/s
10%-90% 1 procs 135,493,165 read/s 4,968 write/s
10%-90% 8 procs 1,017,928,553 read/s 37,130 write/s
10%-90% 16 procs 1,040,251,193 read/s 37,521 write/s
10%-90% 32 procs 982,115,784 read/s 35,689 write/s
10%-90% 64 procs 975,158,264 read/s 34,041 write/s
10%-90% 128 procs 940,466,888 read/s 34,827 write/s
10%-90% 256 procs 930,871,315 read/s 34,399 write/s
10%-90% 512 procs 892,502,438 read/s 33,955 write/s
10%-90% 1024 procs 834,594,229 read/s 32,953 write/s
10%-90% 2048 procs 785,583,770 read/s 32,882 write/s
10%-90% 4096 procs 688,402,474 read/s 34,646 write/s
```
144 changes: 144 additions & 0 deletions examples/bench/bench.go
@@ -0,0 +1,144 @@
// Copyright (c) Roman Atachiants and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

package main

import (
"context"
"encoding/json"
"fmt"
"math/rand"
"os"
"sync"
"sync/atomic"
"time"

"github.com/dustin/go-humanize"
"github.com/kelindar/async"
"github.com/kelindar/column"
)

var (
classes = []string{"fighter", "mage", "rogue"}
races = []string{"human", "elf", "dwarf", "orc"}
)

func main() {
amount := 1000000
players := column.NewCollection(column.Options{
Capacity: amount,
})

// insert the data first
createCollection(players, amount)

// Iterate over various workloads
for _, w := range []int{10, 50, 90} {

// Iterate over various concurrency levels
for _, n := range []int{1, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096} {

// Create a pool of N goroutines
work := make(chan async.Task, n)
pool := async.Consume(context.Background(), n, work)

//run(fmt.Sprintf("(%v/%v)-%v", 100-w, w, n), func(b *testing.B) {
var reads int64
var writes int64

var wg sync.WaitGroup

start := time.Now()
for time.Since(start) < 2*time.Second {
wg.Add(1)
work <- async.NewTask(func(ctx context.Context) (interface{}, error) {
defer wg.Done()
offset := uint32(rand.Int31n(int32(amount - 1)))

// Given our write probabiliy, randomly update an offset
if rand.Int31n(100) < int32(w) {
players.UpdateAt(offset, "balance", 0.0)
atomic.AddInt64(&writes, 1)
return nil, nil
}

// Otherwise, randomly read something
players.Query(func(txn *column.Txn) error {
var count int64
txn.With(races[rand.Int31n(4)]).Range("balance", func(v column.Cursor) {
count++
})
atomic.AddInt64(&reads, count)
return nil
})

return nil, nil
})
}

elapsed := time.Since(start)
readsPerSec := int64(float64(reads) / elapsed.Seconds())
writesPerSec := int64(float64(writes) / elapsed.Seconds())

wg.Wait()
pool.Cancel()
fmt.Printf("%v%%-%v%% %4v procs %20v %15v\n", 100-w, w, n,
humanize.Comma(readsPerSec)+" read/s",
humanize.Comma(writesPerSec)+" write/s",
)
}

}
}

// createCollection loads a collection of players
func createCollection(out *column.Collection, amount int) *column.Collection {
out.CreateColumn("serial", column.ForEnum())
out.CreateColumn("name", column.ForEnum())
out.CreateColumn("active", column.ForBool())
out.CreateColumn("class", column.ForEnum())
out.CreateColumn("race", column.ForEnum())
out.CreateColumn("age", column.ForFloat64())
out.CreateColumn("hp", column.ForFloat64())
out.CreateColumn("mp", column.ForFloat64())
out.CreateColumn("balance", column.ForFloat64())
out.CreateColumn("gender", column.ForEnum())
out.CreateColumn("guild", column.ForEnum())

for _, v := range classes {
class := v
out.CreateIndex(class, "class", func(r column.Reader) bool {
return r.String() == class
})
}

for _, v := range races {
race := v
out.CreateIndex(race, "race", func(r column.Reader) bool {
return r.String() == race
})
}
// Load the 500 rows from JSON
b, err := os.ReadFile("../../fixtures/players.json")
if err != nil {
panic(err)
}

// Unmarshal the items
var data []map[string]interface{}
if err := json.Unmarshal(b, &data); err != nil {
panic(err)
}

// Load the data in
for i := 0; i < amount/len(data); i++ {
out.Query(func(txn *column.Txn) error {
for _, p := range data {
txn.Insert(p)
}
return nil
})
}

return out
}
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0
github.com/kelindar/async v1.0.0
github.com/kelindar/bitmap v1.1.0
github.com/kelindar/smutex v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/kelindar/async v1.0.0 h1:oJiFAt3fVB/b5zVZKPBU+pP9lR3JVyeox9pYlpdnIK8=
github.com/kelindar/async v1.0.0/go.mod h1:bJRlwaRiqdHi+4dpVDNHdwgyRyk6TxpA21fByLf7hIY=
github.com/kelindar/bitmap v1.1.0 h1:67PfkHFb+II2HQdeKrPugxMC7fZFEdKq31X+AOaHDq0=
Expand Down

0 comments on commit 90e5237

Please sign in to comment.