Skip to content

Commit e981b59

Browse files
authored
Merge pull request #13 from kefniark/feature/bench
Improve Benchmark
2 parents 84998fb + 1f9101b commit e981b59

21 files changed

Lines changed: 973 additions & 371 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ devenv.local.nix
1010

1111
coverage.*
1212
*.test
13+
*.log
14+
1315
bin/
1416
codegen/test/
1517
node_modules/

Readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ MangoSQL is a fresh and juicy SQL code generator.
88
2. You run MangoSQL cli to generate a client with type-safe interfaces and queries
99
3. You write application code that calls the generated code
1010

11-
This is not an ORM, and you can easily inspect the code generated.
12-
This is inspired by [SQLC](https://github.com/sqlc-dev/sqlc) but pushes the idea farther by supporting batching, relations and dynamic queries.
11+
The perfect choice if you don't want an ORM, but don't want to write all your application queries by hand either.
12+
This is inspired by [SQLC](https://github.com/sqlc-dev/sqlc), but pushes the idea farther by supporting batching, relations and dynamic queries.
1313

1414
## Features
1515

16-
* **Convenient**: All the structs are generated for you, No need for manual DTO/PDO
16+
* **Convenient**: All the structs are generated for you, No need to write manually DTO/PDO
1717
* **Time Saver**: All the basic queries (CRUD) are generated from your schema alone, less queries to write
1818
* **Developer Friendly**: The code generated contains comments, examples and is designed with IDE autocompletion in mind
1919
* **Flexible**: Provide a way to run dynamic queries (pagination, search, ...)

cmd/bench/bench.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/go-echarts/go-echarts/v2/charts"
11+
"github.com/go-echarts/go-echarts/v2/opts"
12+
)
13+
14+
func parseBenchmarks() []BenchData {
15+
f, err := os.OpenFile("bench.log", os.O_RDONLY, os.ModePerm)
16+
if err != nil {
17+
panic(err)
18+
}
19+
defer f.Close()
20+
21+
entries := []BenchData{}
22+
sc := bufio.NewScanner(f)
23+
for sc.Scan() {
24+
line := sc.Text()
25+
if !strings.HasPrefix(line, "Benchmark") {
26+
continue
27+
}
28+
29+
fields := strings.Fields(line)
30+
31+
// name
32+
suite := strings.Replace(strings.Split(fields[0], "/")[0], "Benchmark", "", -1)
33+
sub := strings.Split(fields[0], "/")[1]
34+
name := sub
35+
param := "1"
36+
if strings.Contains(sub, "_") {
37+
name = strings.Split(strings.Split(fields[0], "/")[1], "_")[0]
38+
param = strings.Split(strings.Split(fields[0], "/")[1], "_")[1]
39+
40+
if strings.Contains(param, "-") {
41+
param = strings.Split(param, "-")[0]
42+
}
43+
}
44+
45+
// math
46+
paramValue, _ := strconv.Atoi(param)
47+
iteration, _ := strconv.Atoi(fields[1])
48+
speed, _ := strconv.Atoi(fields[2])
49+
data, _ := strconv.Atoi(fields[4])
50+
alloc, _ := strconv.Atoi(fields[6])
51+
52+
entries = append(entries, BenchData{
53+
Suite: suite,
54+
Name: name,
55+
Param: paramValue,
56+
Iter: iteration,
57+
Speed: speed,
58+
Data: data,
59+
Alloc: alloc,
60+
})
61+
}
62+
return entries
63+
}
64+
65+
type BenchData struct {
66+
Suite string
67+
Name string
68+
Param int
69+
Iter int
70+
Speed int
71+
Data int
72+
Alloc int
73+
}
74+
75+
func groupBySuite(data []BenchData) map[string][]BenchData {
76+
entries := map[string][]BenchData{}
77+
for _, bench := range data {
78+
entries[bench.Suite] = append(entries[bench.Suite], bench)
79+
}
80+
return entries
81+
}
82+
83+
func generateLineSpeedData(data []BenchData, filters ...string) []opts.LineData {
84+
items := make([]opts.LineData, 0)
85+
for _, v := range data {
86+
for _, f := range filters {
87+
if !strings.Contains(v.Name, f) {
88+
continue
89+
}
90+
}
91+
items = append(items, opts.LineData{Value: 1000000000 / v.Speed})
92+
}
93+
return items
94+
}
95+
96+
func generateLineAllocData(data []BenchData, filters ...string) []opts.LineData {
97+
items := make([]opts.LineData, 0)
98+
for _, v := range data {
99+
for _, f := range filters {
100+
if !strings.Contains(v.Name, f) {
101+
continue
102+
}
103+
}
104+
items = append(items, opts.LineData{Value: v.Alloc})
105+
}
106+
return items
107+
}
108+
109+
func generateInsertManyCPULines(data []BenchData, name string, filter string) *charts.Line {
110+
entries := groupBySuite(data)
111+
112+
line := charts.NewLine()
113+
line.SetGlobalOptions(
114+
charts.WithTitleOpts(opts.Title{
115+
Title: name + "|CPU",
116+
Subtitle: "Higher is Better (op/s)",
117+
}),
118+
charts.WithInitializationOpts(opts.Initialization{
119+
Theme: "shine",
120+
Width: "576px",
121+
Height: "320px",
122+
}),
123+
)
124+
line.SetXAxis([]string{"10", "25", "50", "100", "250", "500"})
125+
126+
for k, v := range entries {
127+
if !strings.Contains(k, filter) {
128+
continue
129+
}
130+
131+
line.AddSeries(strings.ReplaceAll(k, filter, ""), generateLineSpeedData(v, name))
132+
}
133+
134+
return line
135+
}
136+
137+
func generateInsertManyAllocLines(data []BenchData, name string, filter string) *charts.Line {
138+
entries := groupBySuite(data)
139+
140+
line := charts.NewLine()
141+
line.SetGlobalOptions(
142+
charts.WithTitleOpts(opts.Title{
143+
Title: name + "|Mem",
144+
Subtitle: "Lower is Better (allocs/op)",
145+
}),
146+
charts.WithInitializationOpts(opts.Initialization{
147+
Theme: "shine",
148+
Width: "576px",
149+
Height: "320px",
150+
}),
151+
)
152+
line.SetXAxis([]string{"10", "25", "50", "100", "250", "500"})
153+
154+
for k, v := range entries {
155+
if !strings.Contains(k, filter) {
156+
continue
157+
}
158+
line.AddSeries(strings.ReplaceAll(k, filter, ""), generateLineAllocData(v, name))
159+
}
160+
161+
return line
162+
}
163+
164+
func main() {
165+
data := parseBenchmarks()
166+
167+
for _, db := range []string{"Postgres", "SQLite"} {
168+
for _, op := range []string{"InsertMany", "FindMany"} {
169+
f1, _ := os.Create(fmt.Sprintf("docs/public/bench_%s_%s_cpu.html", strings.ToLower(db), strings.ToLower(op)))
170+
defer f1.Close()
171+
generateInsertManyCPULines(data, op, db).Render(f1)
172+
173+
f2, _ := os.Create(fmt.Sprintf("docs/public/bench_%s_%s_alloc.html", strings.ToLower(db), strings.ToLower(op)))
174+
defer f2.Close()
175+
generateInsertManyAllocLines(data, op, db).Render(f2)
176+
}
177+
}
178+
}

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export default defineConfig({
3636
{ text: 'Soft Delete', link: '/features/soft-delete' },
3737
{ text: 'Logging', link: '/features/logging' },
3838
// { text: 'Migrations', link: '/api/mutations' },
39+
{ text: 'Benchmark', link: '/bench/bench' },
3940
]
4041
},
4142
// {

docs/bench/bench.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script setup>
2+
import { withBase } from 'vitepress'
3+
</script>
4+
5+
# Benchmark
6+
7+
The following benchmarks are just here to help development and give a general performance idea of MangoSQL.
8+
9+
It's not intended to cover every method or library on the market.
10+
11+
## Postgres
12+
13+
::: info
14+
15+
Library Tested:
16+
* MangoSQL with PQ+SQLX driver
17+
* MangoSQL with PGX
18+
* [Gorm](https://gorm.io/) with PGX
19+
20+
:::
21+
22+
### CPU (Operation per second)
23+
24+
<iframe :src="withBase('/bench_postgres_insertmany_cpu.html')" width=576 height=320 frameBorder="0" scrolling="no" />
25+
26+
<iframe :src="withBase('/bench_postgres_findmany_cpu.html')" width=576 height=320 frameBorder="0" scrolling="no" />
27+
28+
### Memory Allocation
29+
30+
<iframe :src="withBase('/bench_postgres_insertmany_alloc.html')" width=576 height=320 frameBorder="0" scrolling="no"/>
31+
32+
<iframe :src="withBase('/bench_postgres_findmany_alloc.html')" width=576 height=320 frameBorder="0" scrolling="no"/>
33+
34+
---
35+
36+
## SQLite
37+
38+
::: info
39+
40+
Library Tested:
41+
* MangoSQL with modernc driver
42+
* [Gorm](https://gorm.io/) with gorm sqlite driver
43+
44+
:::
45+
46+
### CPU (Operation per second)
47+
48+
<iframe :src="withBase('/bench_sqlite_insertmany_cpu.html')" width=576 height=320 frameBorder="0" scrolling="no" />
49+
50+
<iframe :src="withBase('/bench_sqlite_findmany_cpu.html')" width=576 height=320 frameBorder="0" scrolling="no" />
51+
52+
### Memory Allocation
53+
54+
<iframe :src="withBase('/bench_sqlite_insertmany_alloc.html')" width=576 height=320 frameBorder="0" scrolling="no"/>
55+
56+
<iframe :src="withBase('/bench_sqlite_findmany_alloc.html')" width=576 height=320 frameBorder="0" scrolling="no"/>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Awesome go-echarts</title>
7+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/echarts.min.js"></script>
8+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/themes/shine.js"></script>
9+
</head>
10+
11+
<body><div class="container">
12+
<div class="item" id="ZZPtlicaSdWE" style="width:576px;height:320px;"></div>
13+
</div><script type="text/javascript">
14+
"use strict";
15+
let goecharts_ZZPtlicaSdWE = echarts.init(document.getElementById('ZZPtlicaSdWE'), "shine", { renderer: "canvas" });
16+
let option_ZZPtlicaSdWE = {"legend":{},"series":[{"name":"GormPGX","type":"line","data":[{"value":118},{"value":462},{"value":1079},{"value":2160},{"value":4322},{"value":10786},{"value":22039},{"value":1090},{"value":437},{"value":981},{"value":1888},{"value":3703},{"value":9269},{"value":18538}]},{"name":"MangoPGX","type":"line","data":[{"value":40},{"value":112},{"value":248},{"value":474},{"value":925},{"value":2278},{"value":5042},{"value":1190},{"value":325},{"value":631},{"value":1138},{"value":2142},{"value":5152},{"value":10163}]},{"name":"MangoPQ","type":"line","data":[{"value":41},{"value":131},{"value":282},{"value":533},{"value":1034},{"value":2536},{"value":5557},{"value":1190},{"value":293},{"value":580},{"value":1057},{"value":2008},{"value":4862},{"value":9618}]}],"title":{"text":"FindMany|Mem","subtext":"Lower is Better (allocs/op)"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["10","25","50","100","250","500"]}],"yAxis":[{}]}
17+
18+
goecharts_ZZPtlicaSdWE.setOption(option_ZZPtlicaSdWE);
19+
</script>
20+
<style>
21+
.container {margin-top:30px; display: flex;justify-content: center;align-items: center;}
22+
.item {margin: auto;}
23+
</style>
24+
</body>
25+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Awesome go-echarts</title>
7+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/echarts.min.js"></script>
8+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/themes/shine.js"></script>
9+
</head>
10+
11+
<body><div class="container">
12+
<div class="item" id="bLaRExjBYFRC" style="width:576px;height:320px;"></div>
13+
</div><script type="text/javascript">
14+
"use strict";
15+
let goecharts_bLaRExjBYFRC = echarts.init(document.getElementById('bLaRExjBYFRC'), "shine", { renderer: "canvas" });
16+
let option_bLaRExjBYFRC = {"legend":{},"series":[{"name":"MangoPQ","type":"line","data":[{"value":6663},{"value":4408},{"value":2876},{"value":1787},{"value":996},{"value":417},{"value":197},{"value":652},{"value":4903},{"value":3474},{"value":2300},{"value":1376},{"value":592},{"value":265}]},{"name":"GormPGX","type":"line","data":[{"value":2246},{"value":1756},{"value":1232},{"value":847},{"value":509},{"value":209},{"value":116},{"value":561},{"value":4056},{"value":2742},{"value":1803},{"value":941},{"value":394},{"value":181}]},{"name":"MangoPGX","type":"line","data":[{"value":6317},{"value":4207},{"value":2864},{"value":1673},{"value":993},{"value":398},{"value":196},{"value":583},{"value":4680},{"value":3304},{"value":2305},{"value":1397},{"value":578},{"value":276}]}],"title":{"text":"FindMany|CPU","subtext":"Higher is Better (op/s)"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["10","25","50","100","250","500"]}],"yAxis":[{}]}
17+
18+
goecharts_bLaRExjBYFRC.setOption(option_bLaRExjBYFRC);
19+
</script>
20+
<style>
21+
.container {margin-top:30px; display: flex;justify-content: center;align-items: center;}
22+
.item {margin: auto;}
23+
</style>
24+
</body>
25+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Awesome go-echarts</title>
7+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/echarts.min.js"></script>
8+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/themes/shine.js"></script>
9+
</head>
10+
11+
<body><div class="container">
12+
<div class="item" id="vLSVLHUOMKXa" style="width:576px;height:320px;"></div>
13+
</div><script type="text/javascript">
14+
"use strict";
15+
let goecharts_vLSVLHUOMKXa = echarts.init(document.getElementById('vLSVLHUOMKXa'), "shine", { renderer: "canvas" });
16+
let option_vLSVLHUOMKXa = {"legend":{},"series":[{"name":"MangoPQ","type":"line","data":[{"value":41},{"value":131},{"value":282},{"value":533},{"value":1034},{"value":2536},{"value":5557},{"value":1190},{"value":293},{"value":580},{"value":1057},{"value":2008},{"value":4862},{"value":9618}]},{"name":"GormPGX","type":"line","data":[{"value":118},{"value":462},{"value":1079},{"value":2160},{"value":4322},{"value":10786},{"value":22039},{"value":1090},{"value":437},{"value":981},{"value":1888},{"value":3703},{"value":9269},{"value":18538}]},{"name":"MangoPGX","type":"line","data":[{"value":40},{"value":112},{"value":248},{"value":474},{"value":925},{"value":2278},{"value":5042},{"value":1190},{"value":325},{"value":631},{"value":1138},{"value":2142},{"value":5152},{"value":10163}]}],"title":{"text":"InsertMany|Mem","subtext":"Lower is Better (allocs/op)"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["10","25","50","100","250","500"]}],"yAxis":[{}]}
17+
18+
goecharts_vLSVLHUOMKXa.setOption(option_vLSVLHUOMKXa);
19+
</script>
20+
<style>
21+
.container {margin-top:30px; display: flex;justify-content: center;align-items: center;}
22+
.item {margin: auto;}
23+
</style>
24+
</body>
25+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Awesome go-echarts</title>
7+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/echarts.min.js"></script>
8+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/themes/shine.js"></script>
9+
</head>
10+
11+
<body><div class="container">
12+
<div class="item" id="dDNCMeSzVGGQ" style="width:576px;height:320px;"></div>
13+
</div><script type="text/javascript">
14+
"use strict";
15+
let goecharts_dDNCMeSzVGGQ = echarts.init(document.getElementById('dDNCMeSzVGGQ'), "shine", { renderer: "canvas" });
16+
let option_dDNCMeSzVGGQ = {"legend":{},"series":[{"name":"GormPGX","type":"line","data":[{"value":2246},{"value":1756},{"value":1232},{"value":847},{"value":509},{"value":209},{"value":116},{"value":561},{"value":4056},{"value":2742},{"value":1803},{"value":941},{"value":394},{"value":181}]},{"name":"MangoPGX","type":"line","data":[{"value":6317},{"value":4207},{"value":2864},{"value":1673},{"value":993},{"value":398},{"value":196},{"value":583},{"value":4680},{"value":3304},{"value":2305},{"value":1397},{"value":578},{"value":276}]},{"name":"MangoPQ","type":"line","data":[{"value":6663},{"value":4408},{"value":2876},{"value":1787},{"value":996},{"value":417},{"value":197},{"value":652},{"value":4903},{"value":3474},{"value":2300},{"value":1376},{"value":592},{"value":265}]}],"title":{"text":"InsertMany|CPU","subtext":"Higher is Better (op/s)"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["10","25","50","100","250","500"]}],"yAxis":[{}]}
17+
18+
goecharts_dDNCMeSzVGGQ.setOption(option_dDNCMeSzVGGQ);
19+
</script>
20+
<style>
21+
.container {margin-top:30px; display: flex;justify-content: center;align-items: center;}
22+
.item {margin: auto;}
23+
</style>
24+
</body>
25+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Awesome go-echarts</title>
7+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/echarts.min.js"></script>
8+
<script src="https://go-echarts.github.io/go-echarts-assets/assets/themes/shine.js"></script>
9+
</head>
10+
11+
<body><div class="container">
12+
<div class="item" id="SXhfkDruOJft" style="width:576px;height:320px;"></div>
13+
</div><script type="text/javascript">
14+
"use strict";
15+
let goecharts_SXhfkDruOJft = echarts.init(document.getElementById('SXhfkDruOJft'), "shine", { renderer: "canvas" });
16+
let option_SXhfkDruOJft = {"legend":{},"series":[{"name":"Mango","type":"line","data":[{"value":94},{"value":152},{"value":333},{"value":634},{"value":1235},{"value":3036},{"value":6560},{"value":1640},{"value":596},{"value":1332},{"value":2558},{"value":5009},{"value":12362},{"value":24617}]},{"name":"Gorm","type":"line","data":[{"value":102},{"value":345},{"value":736},{"value":1387},{"value":2689},{"value":6592},{"value":13583},{"value":1080},{"value":503},{"value":1152},{"value":2230},{"value":4385},{"value":10841},{"value":21602}]}],"title":{"text":"FindMany|Mem","subtext":"Lower is Better (allocs/op)"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["10","25","50","100","250","500"]}],"yAxis":[{}]}
17+
18+
goecharts_SXhfkDruOJft.setOption(option_SXhfkDruOJft);
19+
</script>
20+
<style>
21+
.container {margin-top:30px; display: flex;justify-content: center;align-items: center;}
22+
.item {margin: auto;}
23+
</style>
24+
</body>
25+
</html>

0 commit comments

Comments
 (0)