mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
examples: js_dom_draw_bechmark_chart (#15518)
This commit is contained in:
parent
ca99a1d355
commit
21b2a9841a
@ -1,4 +1,15 @@
|
|||||||
# To run app
|
# To run app
|
||||||
|
## From root
|
||||||
|
- run typescript project
|
||||||
|
`npm i --prefix examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm`
|
||||||
|
`npm run start:dev --prefix examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm`
|
||||||
|
|
||||||
|
- run v project
|
||||||
|
`v run examples/js_dom_draw_bechmark_chart/v_vweb_orm `
|
||||||
|
|
||||||
|
- running v chart
|
||||||
|
`cd examples/js_dom_draw_bechmark_chart/chart && v run .`
|
||||||
|
|
||||||
Dockerfile
|
Dockerfile
|
||||||
[docker build]=> Docker image
|
[docker build]=> Docker image
|
||||||
[docker run]=> Docker container
|
[docker run]=> Docker container
|
||||||
@ -13,12 +24,83 @@ A message like `[Vweb] Running app on http://localhost:3001/` should appear
|
|||||||
|
|
||||||
`exit`
|
`exit`
|
||||||
|
|
||||||
# To implement new bechmarks
|
# To implement new bechmarks in v
|
||||||
|
|
||||||
|
In `examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v` path
|
||||||
|
Create a route returning a `Response` struct like:
|
||||||
|
|
||||||
|
```v ignore
|
||||||
|
['/sqlite-memory/:count']
|
||||||
|
pub fn (mut app App) sqlite_memory(count int) vweb.Result {
|
||||||
|
mut insert_stopwatchs := []int{}
|
||||||
|
mut select_stopwatchs := []int{}
|
||||||
|
mut update_stopwatchs := []int{}
|
||||||
|
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
|
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
task_model := Task{
|
||||||
|
title: 'a'
|
||||||
|
status: 'done'
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sw.start()
|
||||||
|
sql db {
|
||||||
|
insert task_model into Task
|
||||||
|
}
|
||||||
|
sw.stop()
|
||||||
|
insert_stopwatchs << int(sw.end - sw.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
response := Response{
|
||||||
|
insert: insert_stopwatchs
|
||||||
|
@select:select_stopwatchs
|
||||||
|
update: update_stopwatchs
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
In `examples/chart/services.v` path
|
||||||
|
Create a service to request the benchmarks data by http
|
||||||
|
Decode the info to `FrameworkBenchmarkResponse`
|
||||||
|
```v ignore
|
||||||
|
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `examples/chart/main.v` path
|
||||||
|
Create a service to request the benchmarks data by http
|
||||||
|
Decode the info to `FrameworkBenchmarkResponse`
|
||||||
|
```v ignore
|
||||||
|
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Then, update:
|
||||||
|
`insert_framework_benchmark_times()`;
|
||||||
|
`select_framework_benchmark_times()`;
|
||||||
|
`update_framework_benchmark_times()`.
|
||||||
|
with the new function
|
||||||
|
|
||||||
create a function to bench in main.v like `fn any_function() []int {}`
|
|
||||||
that must factory return the array of time spended.
|
|
||||||
So set the attribute in canvas (with id "canvas_insert_id")
|
|
||||||
In draw.js.v put the attribute name inside of attribute_names array
|
|
||||||
|
|
||||||
|
|
||||||
# ROADMAP
|
# ROADMAP
|
||||||
|
98
examples/js_dom_draw_bechmark_chart/chart/README.md
Normal file
98
examples/js_dom_draw_bechmark_chart/chart/README.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# To run app
|
||||||
|
Dockerfile
|
||||||
|
[docker build]=> Docker image
|
||||||
|
[docker run]=> Docker container
|
||||||
|
|
||||||
|
`sudo docker build -t <name> .`
|
||||||
|
|
||||||
|
`sudo docker run --name <container name> --interactive --tty --publish 3001:3001 <name>`
|
||||||
|
|
||||||
|
`v run .`
|
||||||
|
|
||||||
|
A message like `[Vweb] Running app on http://localhost:3001/` should appear
|
||||||
|
|
||||||
|
`exit`
|
||||||
|
|
||||||
|
# To implement new bechmarks in v
|
||||||
|
|
||||||
|
In `examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v` path
|
||||||
|
Create a route returning a `Response` struct like:
|
||||||
|
|
||||||
|
```v ignore
|
||||||
|
['/sqlite-memory/:count']
|
||||||
|
pub fn (mut app App) sqlite_memory(count int) vweb.Result {
|
||||||
|
mut insert_stopwatchs := []int{}
|
||||||
|
mut select_stopwatchs := []int{}
|
||||||
|
mut update_stopwatchs := []int{}
|
||||||
|
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
|
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
task_model := Task{
|
||||||
|
title: 'a'
|
||||||
|
status: 'done'
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sw.start()
|
||||||
|
sql db {
|
||||||
|
insert task_model into Task
|
||||||
|
}
|
||||||
|
sw.stop()
|
||||||
|
insert_stopwatchs << int(sw.end - sw.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
response := Response{
|
||||||
|
insert: insert_stopwatchs
|
||||||
|
@select:select_stopwatchs
|
||||||
|
update: update_stopwatchs
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
In `examples/chart/services.v` path
|
||||||
|
Create a service to request the benchmarks data by http
|
||||||
|
Decode the info to `FrameworkBenchmarkResponse`
|
||||||
|
```v ignore
|
||||||
|
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `examples/chart/main.v` path
|
||||||
|
Create a service to request the benchmarks data by http
|
||||||
|
Decode the info to `FrameworkBenchmarkResponse`
|
||||||
|
```v ignore
|
||||||
|
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Then, update:
|
||||||
|
`insert_framework_benchmark_times()`;
|
||||||
|
`select_framework_benchmark_times()`;
|
||||||
|
`update_framework_benchmark_times()`.
|
||||||
|
with the new function
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ROADMAP
|
||||||
|
02/09/2022
|
||||||
|
- [ ] select bench (easy)
|
||||||
|
- [ ] vsql (easy)
|
129
examples/js_dom_draw_bechmark_chart/chart/draw.js.v
Normal file
129
examples/js_dom_draw_bechmark_chart/chart/draw.js.v
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import js.dom
|
||||||
|
|
||||||
|
fn get_canvas(elem JS.HTMLElement) JS.HTMLCanvasElement {
|
||||||
|
// error: `JS.HTMLElement` doesn't implement method `getContext` of interface `JS.HTMLCanvasElement`
|
||||||
|
match elem {
|
||||||
|
JS.HTMLCanvasElement {
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JS.console.log('Not canvas')
|
||||||
|
return JS.HTMLCanvasElement{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_line(mut context JS.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
||||||
|
context.beginPath()
|
||||||
|
context.strokeStyle = 'black'.str
|
||||||
|
context.lineWidth = JS.Number(1)
|
||||||
|
context.moveTo(0, 0)
|
||||||
|
context.lineTo(100, 100)
|
||||||
|
context.stroke()
|
||||||
|
context.closePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DrawState {
|
||||||
|
mut:
|
||||||
|
context JS.CanvasRenderingContext2D
|
||||||
|
drawing bool
|
||||||
|
x f64
|
||||||
|
y f64
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FrameworkPlatform {
|
||||||
|
mut:
|
||||||
|
v_sqlite_memory []int
|
||||||
|
// v_sqlite_file []int
|
||||||
|
typescript_sqlite_memory []int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut state DrawState) draw_bench_chart(color string, time_array []int, max_time int) ? {
|
||||||
|
max_height := f64(480)
|
||||||
|
max_width := f64(720)
|
||||||
|
|
||||||
|
state.drawing = true
|
||||||
|
state.x = f64(0)
|
||||||
|
state.y = f64(max_height)
|
||||||
|
state.context.strokeStyle = color.str
|
||||||
|
state.context.lineWidth = JS.Number(1)
|
||||||
|
|
||||||
|
for i := 0; i <= time_array.len; i++ {
|
||||||
|
state.context.beginPath()
|
||||||
|
state.context.moveTo(state.x, state.y)
|
||||||
|
state.x = max_width / f64(time_array.len) * i + 1.0
|
||||||
|
state.y = max_height - (max_height / f64(max_time) * f64(time_array[i]))
|
||||||
|
state.context.lineTo(state.x, state.y)
|
||||||
|
state.context.stroke()
|
||||||
|
state.context.closePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
state.drawing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
document := dom.document
|
||||||
|
|
||||||
|
mut canvas_elem := map[string]JS.HTMLElement{}
|
||||||
|
mut canvas := map[string]JS.HTMLCanvasElement{}
|
||||||
|
|
||||||
|
canvas_elem['insert'] = document.getElementById('canvas_insert_id'.str)?
|
||||||
|
JS.console.log('canvas_insert_id')
|
||||||
|
|
||||||
|
canvas_elem['select'] = document.getElementById('canvas_select_id'.str)?
|
||||||
|
JS.console.log('canvas_select_id')
|
||||||
|
|
||||||
|
canvas_elem['update'] = document.getElementById('canvas_update_id'.str)?
|
||||||
|
JS.console.log('canvas_update_id')
|
||||||
|
|
||||||
|
// for orm_stmt_kind in ["insert", "select", "update"]{
|
||||||
|
for orm_stmt_kind in ['insert', 'select', 'update'] {
|
||||||
|
// type HTMLElement
|
||||||
|
|
||||||
|
canvas[orm_stmt_kind] = get_canvas(canvas_elem[orm_stmt_kind])
|
||||||
|
|
||||||
|
ctx := canvas[orm_stmt_kind].getContext('2d'.str, js_undefined())?
|
||||||
|
|
||||||
|
context := match ctx {
|
||||||
|
JS.CanvasRenderingContext2D {
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic('can not get 2d context')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mut state := DrawState{context, false, 0, 0}
|
||||||
|
|
||||||
|
mut inserts_from_framework := canvas_elem[orm_stmt_kind].getAttribute('inserts_from_framework'.str)?
|
||||||
|
|
||||||
|
mut max_benchmark := canvas_elem[orm_stmt_kind].getAttribute('max_benchmark'.str)?
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
mut obj := FrameworkPlatform{}
|
||||||
|
obj = JS.JSON.parse(tos(inserts_from_framework))
|
||||||
|
|
||||||
|
// Waiting for v implement for loop getting key and value of object in v.js
|
||||||
|
mut attribute_int_values := []int{}
|
||||||
|
|
||||||
|
//* v framework
|
||||||
|
for variable in obj.v_sqlite_memory {
|
||||||
|
attribute_int_values << variable
|
||||||
|
}
|
||||||
|
|
||||||
|
state.draw_bench_chart('gray', attribute_int_values, tos(max_benchmark).int())?
|
||||||
|
attribute_int_values = []
|
||||||
|
|
||||||
|
//* typescript framework
|
||||||
|
|
||||||
|
for variable in obj.typescript_sqlite_memory {
|
||||||
|
attribute_int_values << variable
|
||||||
|
}
|
||||||
|
|
||||||
|
state.draw_bench_chart('red', attribute_int_values, tos(max_benchmark).int())?
|
||||||
|
|
||||||
|
attribute_int_values = []
|
||||||
|
}
|
||||||
|
}
|
BIN
examples/js_dom_draw_bechmark_chart/chart/favicon.ico
Normal file
BIN
examples/js_dom_draw_bechmark_chart/chart/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 303 KiB |
249
examples/js_dom_draw_bechmark_chart/chart/main.v
Normal file
249
examples/js_dom_draw_bechmark_chart/chart/main.v
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import vweb
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import arrays
|
||||||
|
import net.http
|
||||||
|
import math
|
||||||
|
import v.util.version
|
||||||
|
|
||||||
|
[table: 'benchmark']
|
||||||
|
struct Task {
|
||||||
|
mut:
|
||||||
|
id u32 [primary; serial; sql: serial]
|
||||||
|
title string
|
||||||
|
status string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FrameworkBenchmarkResponse {
|
||||||
|
insert []int
|
||||||
|
@select []int
|
||||||
|
update []int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FrameworkPlatform {
|
||||||
|
mut:
|
||||||
|
v_sqlite_memory []int
|
||||||
|
// v_sqlite_file []int
|
||||||
|
typescript_sqlite_memory []int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (framework_platform FrameworkPlatform) to_map() map[string][]int {
|
||||||
|
mut mapa := map[string][]int{}
|
||||||
|
|
||||||
|
mapa['v_sqlite_memory'] = framework_platform.v_sqlite_memory
|
||||||
|
// mapa['v_sqlite_file'] = framework_platform.v_sqlite_file
|
||||||
|
mapa['typescript_sqlite_memory'] = framework_platform.typescript_sqlite_memory
|
||||||
|
return mapa
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
http_port = 3001
|
||||||
|
benchmark_loop_length = 20
|
||||||
|
)
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
vweb.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SqliteDbConnection {
|
||||||
|
sqlite_memory
|
||||||
|
sqlite_file
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
vweb.run(new_app(), http_port)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut app App) before_request() {
|
||||||
|
os.execute_or_panic('v -b js_browser draw.js.v ')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_app() &App {
|
||||||
|
mut app := &App{}
|
||||||
|
app.serve_static('/favicon.ico', 'favicon.ico')
|
||||||
|
app.serve_static('/draw.js', 'draw.js')
|
||||||
|
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
['/'; get]
|
||||||
|
pub fn (mut app App) controller_get_all_task() ?vweb.Result {
|
||||||
|
v_version := version.full_v_version(true)
|
||||||
|
orm_stmt_kinds := ['insert', 'select', 'update']
|
||||||
|
|
||||||
|
mut attribute_names := map[string][]string{}
|
||||||
|
// Used to garante the chart proposionalite
|
||||||
|
mut max_benchmark := map[string]int{}
|
||||||
|
mut from_framework := map[string]string{}
|
||||||
|
mut maxs := map[string][]int{}
|
||||||
|
mut framework_platform := map[string]map[string][]int{}
|
||||||
|
mut table := map[string]map[string]map[string]string{}
|
||||||
|
|
||||||
|
chart_colors := ['gray', 'red', 'orange', 'purple', 'red', 'orange', 'purple']
|
||||||
|
for orm_stmt_kind in orm_stmt_kinds {
|
||||||
|
match orm_stmt_kind {
|
||||||
|
'insert' {
|
||||||
|
framework_platform[orm_stmt_kind] = insert_framework_benchmark_times().to_map()
|
||||||
|
}
|
||||||
|
'select' {
|
||||||
|
framework_platform[orm_stmt_kind] = select_framework_benchmark_times().to_map()
|
||||||
|
}
|
||||||
|
'update' {
|
||||||
|
framework_platform[orm_stmt_kind] = update_framework_benchmark_times().to_map()
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, values in framework_platform[orm_stmt_kind] {
|
||||||
|
attribute_names[orm_stmt_kind] << key
|
||||||
|
maxs[orm_stmt_kind] << arrays.max(values)?
|
||||||
|
}
|
||||||
|
|
||||||
|
max_benchmark[orm_stmt_kind] = arrays.max(maxs[orm_stmt_kind])?
|
||||||
|
from_framework[orm_stmt_kind] = json.encode(framework_platform[orm_stmt_kind])
|
||||||
|
table[orm_stmt_kind] = gen_table_info(attribute_names[orm_stmt_kind], framework_platform[orm_stmt_kind])
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vweb.html()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_framework_benchmark_times() FrameworkPlatform {
|
||||||
|
numbers := FrameworkPlatform{
|
||||||
|
v_sqlite_memory: v_sqlite_memory()!.insert
|
||||||
|
// v_sqlite_file: v_sqlite_file()!.insert
|
||||||
|
typescript_sqlite_memory: typescript_sqlite_memory()!.insert
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_framework_benchmark_times() FrameworkPlatform {
|
||||||
|
numbers := FrameworkPlatform{
|
||||||
|
v_sqlite_memory: v_sqlite_memory()!.@select
|
||||||
|
// v_sqlite_file: v_sqlite_file()!.@select
|
||||||
|
typescript_sqlite_memory: typescript_sqlite_memory()!.@select
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_framework_benchmark_times() FrameworkPlatform {
|
||||||
|
numbers := FrameworkPlatform{
|
||||||
|
v_sqlite_memory: v_sqlite_memory()!.update
|
||||||
|
// v_sqlite_file: v_sqlite_file()!.@select
|
||||||
|
typescript_sqlite_memory: typescript_sqlite_memory()!.update
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
|
||||||
|
fn v_sqlite_memory() ?FrameworkBenchmarkResponse {
|
||||||
|
url := 'http://localhost:4000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
res := http.get(url) or { panic(err) }
|
||||||
|
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
|
||||||
|
fn v_sqlite_file() ?FrameworkBenchmarkResponse {
|
||||||
|
// url := 'http://localhost:3000/sqlite-memory/$benchmark_loop_length'
|
||||||
|
// res := http.get(url) or { panic(err) }
|
||||||
|
// framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)?
|
||||||
|
framework_benchmark_response := FrameworkBenchmarkResponse{
|
||||||
|
insert: []
|
||||||
|
@select: []
|
||||||
|
update: []
|
||||||
|
}
|
||||||
|
return framework_benchmark_response
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_table_info(attribute_names []string, framework_platform map[string][]int) map[string]map[string]string {
|
||||||
|
mut table := map[string]map[string]string{}
|
||||||
|
|
||||||
|
// nanoseconds
|
||||||
|
mut max_times := map[string]int{}
|
||||||
|
mut ten_perc_max_times := map[string]int{}
|
||||||
|
mut min_times := map[string]int{}
|
||||||
|
mut ten_perc_min_times := map[string]int{}
|
||||||
|
|
||||||
|
// bigger to calculate percent
|
||||||
|
mut max := 0.0
|
||||||
|
mut ten_perc_max := 0.0
|
||||||
|
mut min := 0.0
|
||||||
|
mut ten_perc_min := 0.0
|
||||||
|
|
||||||
|
// percentes
|
||||||
|
mut max_fast := map[string]int{}
|
||||||
|
mut ten_perc_max_fast := map[string]int{}
|
||||||
|
mut min_fast := map[string]int{}
|
||||||
|
mut ten_perc_min_fast := map[string]int{}
|
||||||
|
|
||||||
|
// nanoseconds
|
||||||
|
for idx, name in attribute_names {
|
||||||
|
// qtd. of values in 10 % of arrays
|
||||||
|
ten_perc := int(framework_platform[name].len / 10)
|
||||||
|
|
||||||
|
// get 10% highter
|
||||||
|
mut min_ten_array := framework_platform[name].clone()
|
||||||
|
min_ten_array.sort()
|
||||||
|
min_ten_array.trim(ten_perc)
|
||||||
|
|
||||||
|
// get 10% lower
|
||||||
|
mut max_ten_array := framework_platform[name].clone()
|
||||||
|
max_ten_array.sort(a > b)
|
||||||
|
max_ten_array.trim(ten_perc)
|
||||||
|
|
||||||
|
// popule array with nanoseconds to which benchmark
|
||||||
|
max_times[name] = arrays.max(framework_platform[name]) or { 0 } // int
|
||||||
|
ten_perc_max_times[name] = arrays.sum(max_ten_array) or { 0 } / ten_perc // int
|
||||||
|
min_times[name] = arrays.min(framework_platform[name]) or { 0 } // int
|
||||||
|
ten_perc_min_times[name] = arrays.sum(min_ten_array) or { 0 } / ten_perc // int
|
||||||
|
|
||||||
|
// set bigger values
|
||||||
|
if idx < 1 {
|
||||||
|
max = f64(max_times[name])
|
||||||
|
ten_perc_max = f64(ten_perc_max_times[name])
|
||||||
|
min = f64(min_times[name])
|
||||||
|
ten_perc_min = f64(ten_perc_min_times[name])
|
||||||
|
} else {
|
||||||
|
if max < f64(max_times[name]) {
|
||||||
|
max = f64(max_times[name])
|
||||||
|
}
|
||||||
|
if ten_perc_max < f64(ten_perc_max_times[name]) {
|
||||||
|
ten_perc_max = f64(ten_perc_max_times[name])
|
||||||
|
}
|
||||||
|
if min < f64(min_times[name]) {
|
||||||
|
min = f64(min_times[name])
|
||||||
|
}
|
||||||
|
if ten_perc_min < f64(ten_perc_min_times[name]) {
|
||||||
|
ten_perc_min = f64(ten_perc_min_times[name])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// percents
|
||||||
|
for name in attribute_names {
|
||||||
|
max_fast[name] = int(max / f64(max_times[name]))
|
||||||
|
ten_perc_max_fast[name] = int(ten_perc_max / f64(ten_perc_max_times[name]))
|
||||||
|
min_fast[name] = int(min / f64(min_times[name]))
|
||||||
|
ten_perc_min_fast[name] = int(ten_perc_min / f64(ten_perc_min_times[name]))
|
||||||
|
}
|
||||||
|
|
||||||
|
for name in attribute_names {
|
||||||
|
table[name]['max.'] = '${math.round_sig(f64(max_times[name]) / 1000000, 2)} ms (${max_fast[name]}x faster)'
|
||||||
|
table[name]['10% max.'] = '${math.round_sig(f64(ten_perc_max_times[name]) / 1000000,
|
||||||
|
2)} ms (${ten_perc_max_fast[name]}x faster)'
|
||||||
|
table[name]['min.'] = '${math.round_sig(f64(min_times[name]) / 1000000, 2)} ms (${min_fast[name]}x faster)'
|
||||||
|
table[name]['10% min.'] = '${math.round_sig(f64(ten_perc_min_times[name]) / 1000000,
|
||||||
|
2)} ms (${ten_perc_min_fast[name]}x faster)'
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
<body class="main">
|
||||||
|
<style>
|
||||||
|
table,
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<title>Is V orm still fast? ${v_version}</title>
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<h2
|
||||||
|
style="
|
||||||
|
font-family: Menlo, Monospace, 'Courier New';
|
||||||
|
margin-left: 30px;
|
||||||
|
margin-top: 30px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Is V orm still fast?
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<img src="./../../../../favicon.ico" height="35px" />
|
||||||
|
<h5 style="font-family: Menlo, Monospace, 'Courier New'; color: #3b7bbf">
|
||||||
|
${v_version}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; flex-direction: row; flex-wrap: wrap">
|
||||||
|
@for orm_stmt_kind in orm_stmt_kinds
|
||||||
|
<!-- <div style="display: flex; flex-direction: column; "> -->
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px;
|
||||||
|
box-shadow: 0px 2px 10px 1px grey;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div style="display: flex; flex-direction: column; max-width: 850px">
|
||||||
|
<h2 style="font-family: Arial, Helvetica, sans-serif">
|
||||||
|
${orm_stmt_kind} benchmark
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 480;
|
||||||
|
margin-right: 20px;
|
||||||
|
background-image: linear-gradient(red, yellow, green, #3b7bbf);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
@for number in 0..11
|
||||||
|
<div style="font-family: Arial, Helvetica, sans-serif">
|
||||||
|
${int(number*(f64(max_benchmark[orm_stmt_kind])/10))} ns
|
||||||
|
</div>
|
||||||
|
@end
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas
|
||||||
|
id="canvas_${orm_stmt_kind}_id"
|
||||||
|
inserts_from_framework="@{from_framework[orm_stmt_kind]}"
|
||||||
|
max_benchmark="@{max_benchmark[orm_stmt_kind]}"
|
||||||
|
style="border: 1px solid grey"
|
||||||
|
width="720"
|
||||||
|
height="480"
|
||||||
|
></canvas>
|
||||||
|
</div>
|
||||||
|
<table style="margin-top: 10px">
|
||||||
|
<tr>
|
||||||
|
<th>Benchmark name</th>
|
||||||
|
<th>max.</th>
|
||||||
|
<th>10% max.</th>
|
||||||
|
<th>min.</th>
|
||||||
|
<th>10% min.</th>
|
||||||
|
</tr>
|
||||||
|
@for idx, name in attribute_names[orm_stmt_kind]
|
||||||
|
<tr style="font-family:arial; color: ${chart_colors[idx]};">
|
||||||
|
<td style="padding-right: 5px" id="benchmark_name" +idx>@name</td>
|
||||||
|
<td style="padding-left: 5px; padding-right: 5px">
|
||||||
|
@{table[orm_stmt_kind][name]["max."]}
|
||||||
|
</td>
|
||||||
|
<td style="padding-left: 5px; padding-right: 5px">
|
||||||
|
@{table[orm_stmt_kind][name]["10% max."]}
|
||||||
|
</td>
|
||||||
|
<td style="padding-left: 5px; padding-right: 5px">
|
||||||
|
@{table[orm_stmt_kind][name]["min."]}
|
||||||
|
</td>
|
||||||
|
<td style="padding-left: 5px; padding-right: 5px">
|
||||||
|
@{table[orm_stmt_kind][name]["10% min."]}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@end
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- </div> -->
|
||||||
|
</div>
|
||||||
|
@end
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="draw.js"></script>
|
||||||
|
</body>
|
@ -1,111 +0,0 @@
|
|||||||
module main
|
|
||||||
|
|
||||||
import js.dom
|
|
||||||
|
|
||||||
fn get_canvas(elem JS.HTMLElement) JS.HTMLCanvasElement {
|
|
||||||
match elem {
|
|
||||||
JS.HTMLCanvasElement {
|
|
||||||
return elem
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
panic('Not a canvas')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_line(mut context JS.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
|
||||||
context.beginPath()
|
|
||||||
context.strokeStyle = 'black'.str
|
|
||||||
context.lineWidth = JS.Number(1)
|
|
||||||
context.moveTo(0, 0)
|
|
||||||
context.lineTo(100, 100)
|
|
||||||
context.stroke()
|
|
||||||
context.closePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DrawState {
|
|
||||||
mut:
|
|
||||||
context JS.CanvasRenderingContext2D
|
|
||||||
drawing bool
|
|
||||||
x f64
|
|
||||||
y f64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut state DrawState) draw_bench_chart(color string, time_array []int, max_time int) ? {
|
|
||||||
println(time_array.len)
|
|
||||||
max_height := f64(480)
|
|
||||||
max_width := f64(720)
|
|
||||||
|
|
||||||
state.drawing = true
|
|
||||||
state.x = f64(0)
|
|
||||||
state.y = f64(max_height)
|
|
||||||
state.context.strokeStyle = color.str
|
|
||||||
state.context.lineWidth = JS.Number(1)
|
|
||||||
|
|
||||||
for i := 0; i <= time_array.len; i++ {
|
|
||||||
state.context.beginPath()
|
|
||||||
state.context.moveTo(state.x, state.y)
|
|
||||||
state.x = max_width / f64(time_array.len) * i + 1.0
|
|
||||||
state.y = max_height - (max_height / f64(max_time) * f64(time_array[i]))
|
|
||||||
state.context.lineTo(state.x, state.y)
|
|
||||||
state.context.stroke()
|
|
||||||
state.context.closePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
state.drawing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
document := dom.document
|
|
||||||
|
|
||||||
clear_btn := document.getElementById('clearButton'.str)?
|
|
||||||
|
|
||||||
canvas_elem := document.getElementById('canvas_insert_id'.str)?
|
|
||||||
|
|
||||||
canvas := get_canvas(canvas_elem)
|
|
||||||
ctx := canvas.getContext('2d'.str, js_undefined())?
|
|
||||||
context := match ctx {
|
|
||||||
JS.CanvasRenderingContext2D {
|
|
||||||
ctx
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
panic('can not get 2d context')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut state := DrawState{context, false, 0, 0}
|
|
||||||
|
|
||||||
attribute_names := ['sqlite_memory_insert_times', 'sqlite_file_insert_times' /*
|
|
||||||
,
|
|
||||||
'postgres_insert_times', 'mysql_insert_times'
|
|
||||||
*/]
|
|
||||||
chart_colors := ['gray', 'black', 'red', 'orange', 'purple']
|
|
||||||
|
|
||||||
for idx, name in attribute_names {
|
|
||||||
// get values in JS.String values
|
|
||||||
mut attribute_js_values := canvas_elem.getAttribute(name.str) or {
|
|
||||||
println('Não pegou o attributo')
|
|
||||||
continue // if attribute not exist, jump.
|
|
||||||
}
|
|
||||||
if attribute_js_values.length < JS.Number(1) {
|
|
||||||
continue // if attribute value is empty, jump.
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert []JS.String in v []string
|
|
||||||
mut attribute_string_values := tos(attribute_js_values).replace('[', '').replace(']',
|
|
||||||
'').split(',')
|
|
||||||
|
|
||||||
// convert []string in []int
|
|
||||||
mut attribute_int_values := []int{}
|
|
||||||
for variable in attribute_string_values {
|
|
||||||
attribute_int_values << variable.int()
|
|
||||||
}
|
|
||||||
// draw chart
|
|
||||||
state.draw_bench_chart(chart_colors[idx], attribute_int_values, 11204530) or {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_btn.addEventListener('click'.str, fn [mut state, canvas] (_ JS.Event) {
|
|
||||||
state.context.clearRect(0, 0, canvas.width, canvas.height)
|
|
||||||
}, JS.EventListenerOptions{})
|
|
||||||
}
|
|
@ -1,217 +0,0 @@
|
|||||||
module main
|
|
||||||
|
|
||||||
import vweb
|
|
||||||
import os
|
|
||||||
import sqlite
|
|
||||||
// import pg
|
|
||||||
// import mysql
|
|
||||||
import time
|
|
||||||
import arrays
|
|
||||||
|
|
||||||
[table: 'benchmark']
|
|
||||||
struct Task {
|
|
||||||
mut:
|
|
||||||
id u32 [primary; serial; sql: serial]
|
|
||||||
title string
|
|
||||||
status string
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
http_port = 3001
|
|
||||||
benchmark_loop_length = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
struct App {
|
|
||||||
vweb.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SqliteDbConnection {
|
|
||||||
sqlite_memory
|
|
||||||
sqlite_file
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
vweb.run(new_app(), http_port)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut app App) before_request() {
|
|
||||||
os.execute_or_panic('v -b js_browser draw.js.v ')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_app() &App {
|
|
||||||
mut app := &App{}
|
|
||||||
app.serve_static('/favicon.ico', 'favicon.ico')
|
|
||||||
app.serve_static('/draw.js', 'draw.js')
|
|
||||||
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
['/'; get]
|
|
||||||
pub fn (mut app App) controller_get_all_task() vweb.Result {
|
|
||||||
// attribute_names := ['sqlite_memory_insert_times', 'sqlite_file_insert_times',
|
|
||||||
// 'postgres_insert_times', 'mysql_insert_times']
|
|
||||||
attribute_names := ['sqlite_memory_insert_times', 'sqlite_file_insert_times']
|
|
||||||
chart_colors := ['gray', 'black', 'red', 'orange', 'purple']
|
|
||||||
mut insert_times := [][]int{}
|
|
||||||
|
|
||||||
mut max_times := []int{}
|
|
||||||
mut ten_perc_max_times := []int{}
|
|
||||||
mut min_times := []int{}
|
|
||||||
mut ten_perc_min_times := []int{}
|
|
||||||
|
|
||||||
mut max_fast := []int{}
|
|
||||||
mut ten_perc_max_fast := []int{}
|
|
||||||
mut min_fast := []int{}
|
|
||||||
mut ten_perc_min_fast := []int{}
|
|
||||||
|
|
||||||
insert_times << factory_sqlite_memory_insert_benchmark(.sqlite_memory)
|
|
||||||
insert_times << factory_sqlite_memory_insert_benchmark(.sqlite_file)
|
|
||||||
// insert_times << factory_postgres_insert_benchmark()
|
|
||||||
// insert_times << factory_mysql_insert_benchmark()
|
|
||||||
|
|
||||||
sqlite_memory_insert_times := insert_times[0].str().replace(' ', '')
|
|
||||||
sqlite_file_insert_times := insert_times[1].str().replace(' ', '')
|
|
||||||
// postgres_insert_times := insert_times[2].str().replace(' ', '')
|
|
||||||
// mysql_insert_times := insert_times[3].str().replace(' ', '')
|
|
||||||
|
|
||||||
for i := 0; i < attribute_names.len; i++ {
|
|
||||||
println('insert_times[i]: ${insert_times[i]}')
|
|
||||||
ten_perc := int(insert_times[i].len / 10)
|
|
||||||
|
|
||||||
mut min_ten_array := insert_times[i].clone()
|
|
||||||
min_ten_array.sort()
|
|
||||||
min_ten_array.trim(ten_perc)
|
|
||||||
|
|
||||||
mut max_ten_array := insert_times[i].clone()
|
|
||||||
max_ten_array.sort(a > b)
|
|
||||||
max_ten_array.trim(ten_perc)
|
|
||||||
|
|
||||||
max_times << arrays.max(insert_times[i]) or { 0 }
|
|
||||||
ten_perc_max_times << arrays.sum(max_ten_array) or { 0 } / ten_perc
|
|
||||||
min_times << arrays.min(insert_times[i]) or { 0 }
|
|
||||||
ten_perc_min_times << arrays.sum(min_ten_array) or { 0 } / ten_perc
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < attribute_names.len; i++ {
|
|
||||||
max_fast << int(100 - (f64(max_times[i] * 100) / f64(arrays.max(max_times) or {
|
|
||||||
panic('deu ruim no max_fas')
|
|
||||||
})))
|
|
||||||
ten_perc_max_fast << int(100 - (f64(ten_perc_max_times[i] * 100) / f64(arrays.max(ten_perc_max_times) or {
|
|
||||||
panic('deu ruim no max_fas')
|
|
||||||
})))
|
|
||||||
min_fast << int(100 - (f64(min_times[i] * 100) / f64(arrays.max(min_times) or {
|
|
||||||
panic('deu ruim no max_fas')
|
|
||||||
})))
|
|
||||||
ten_perc_min_fast << int(100 - (f64(ten_perc_min_times[i] * 100) / f64(arrays.max(ten_perc_min_times) or {
|
|
||||||
panic('deu ruim no max_fas')
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vweb.html()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn factory_sqlite_memory_insert_benchmark(db_connection SqliteDbConnection) []int {
|
|
||||||
mut result := []int{}
|
|
||||||
mut sw := time.new_stopwatch()
|
|
||||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
|
||||||
|
|
||||||
if db_connection == .sqlite_file {
|
|
||||||
db.close() or { println('text: $err') }
|
|
||||||
db = sqlite.connect('salada.db') or { panic(err) }
|
|
||||||
}
|
|
||||||
|
|
||||||
sql db {
|
|
||||||
create table Task
|
|
||||||
}
|
|
||||||
|
|
||||||
task_model := Task{
|
|
||||||
title: 'a'
|
|
||||||
status: 'done'
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < benchmark_loop_length; i++ {
|
|
||||||
sw.start()
|
|
||||||
sql db {
|
|
||||||
insert task_model into Task
|
|
||||||
}
|
|
||||||
sw.stop()
|
|
||||||
result << int(sw.end - sw.start)
|
|
||||||
}
|
|
||||||
|
|
||||||
sql db {
|
|
||||||
drop table Task
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn factory_postgres_insert_benchmark() []int {
|
|
||||||
// mut result := []int{}
|
|
||||||
// mut sw := time.new_stopwatch()
|
|
||||||
|
|
||||||
// mut db := pg.connect(pg.Config{
|
|
||||||
// host: '127.0.0.1'
|
|
||||||
// port: 5432
|
|
||||||
// user: 'hitalo'
|
|
||||||
// password: 'password'
|
|
||||||
// dbname: 'username'
|
|
||||||
// }) or { panic(err) }
|
|
||||||
// sql db {
|
|
||||||
// create table Task
|
|
||||||
// }
|
|
||||||
|
|
||||||
// task_model := Task{
|
|
||||||
// title: 'a'
|
|
||||||
// status: 'done'
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for i := 0; i < benchmark_loop_length; i++ {
|
|
||||||
// sw.start()
|
|
||||||
// sql db {
|
|
||||||
// insert task_model into Task
|
|
||||||
// }
|
|
||||||
// sw.stop()
|
|
||||||
// result << int(sw.end - sw.start)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// sql db {
|
|
||||||
// drop table Task
|
|
||||||
// }
|
|
||||||
// return result
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn factory_mysql_insert_benchmark() []int {
|
|
||||||
// mut result := []int{}
|
|
||||||
// mut sw := time.new_stopwatch()
|
|
||||||
|
|
||||||
// mut db := mysql.Connection{
|
|
||||||
// host: '127.0.0.1'
|
|
||||||
// port: 3306
|
|
||||||
// username: 'username'
|
|
||||||
// password: 'password'
|
|
||||||
// dbname: 'benchmark'
|
|
||||||
// }
|
|
||||||
// db.connect() or { println(err) }
|
|
||||||
|
|
||||||
// sql db {
|
|
||||||
// create table Task
|
|
||||||
// }
|
|
||||||
|
|
||||||
// task_model := Task{
|
|
||||||
// title: 'a'
|
|
||||||
// status: 'done'
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for i := 0; i < benchmark_loop_length; i++ {
|
|
||||||
// sw.start()
|
|
||||||
// sql db {
|
|
||||||
// insert task_model into Task
|
|
||||||
// }
|
|
||||||
// sw.stop()
|
|
||||||
// result << int(sw.end - sw.start)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// sql db {
|
|
||||||
// drop table Task
|
|
||||||
// }
|
|
||||||
// return result
|
|
||||||
// }
|
|
@ -1,38 +0,0 @@
|
|||||||
|
|
||||||
<body class="main">
|
|
||||||
<style>
|
|
||||||
table, th, td {
|
|
||||||
border:1px solid black;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>V orm still fast?</title>
|
|
||||||
<input type="button" id="clearButton" value="Clear canvas">
|
|
||||||
<div style="float: left; width: 100%;">
|
|
||||||
<canvas style="border: 1px solid black;" width="100" height="480" id="canvas_left_bar_id"></canvas>
|
|
||||||
<canvas sqlite_memory_insert_times=@sqlite_memory_insert_times sqlite_file_insert_times=@sqlite_file_insert_times style="border: 1px solid black;" width="720" height="480" id="canvas_insert_id"></canvas>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript" src="draw.js"></script>
|
|
||||||
|
|
||||||
<h2>Insert test</h2>
|
|
||||||
|
|
||||||
<table style="width:1080px">
|
|
||||||
<tr>
|
|
||||||
<th>Benchmark name</th>
|
|
||||||
<th>max.</th>
|
|
||||||
<th>10% max.</th>
|
|
||||||
<th>min.</th>
|
|
||||||
<th>10% min.</th>
|
|
||||||
</tr>
|
|
||||||
@for idx, name in attribute_names
|
|
||||||
<tr style="font-family:arial; color: ${chart_colors[idx]};" >
|
|
||||||
<td id="benchmark_name"+idx >@name</td>
|
|
||||||
<td>@{max_times[idx]} ns (@{max_fast[idx]}%faster)</td>
|
|
||||||
<td>@{ten_perc_max_times[idx]} ns (@{ten_perc_max_fast[idx]}%faster)</td>
|
|
||||||
<td>@{min_times[idx]} ns (@{min_fast[idx]}%faster)</td>
|
|
||||||
<td>@{ten_perc_min_times[idx]} ns (@{ten_perc_min_fast[idx]}%faster)</td>
|
|
||||||
</tr>
|
|
||||||
@end
|
|
||||||
</table>
|
|
||||||
<p>V orm still fast?</p>
|
|
||||||
</body>
|
|
25
examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm/.gitignore
vendored
Normal file
25
examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
*/node_modules/**/*
|
||||||
|
/node_modules/**/*
|
||||||
|
node_modules/**/*
|
||||||
|
/node_modules/
|
||||||
|
node_modules/
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Ignore built ts files
|
||||||
|
*/dist/**/*
|
||||||
|
/dist/**/*
|
||||||
|
dist/**/*
|
||||||
|
/dist/
|
||||||
|
dist/
|
||||||
|
dist
|
||||||
|
|
||||||
|
temp/*
|
||||||
|
temp/
|
||||||
|
*/temp/**/*
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# Not ignore built js or ts files
|
||||||
|
!*.js
|
||||||
|
!*.ts
|
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "js_dom_draw_chart_ts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "npm run build && node src/server.js",
|
||||||
|
"start:dev": "./node_modules/nodemon/bin/nodemon.js -e ts --exec \"npm run start\"",
|
||||||
|
"build": "tsc"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"nodemon": "^2.0.19",
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"sqlite3": "^5.0.11",
|
||||||
|
"typeorm": "^0.3.7",
|
||||||
|
"typescript": "^4.7.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.6.4"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
import { performance } from "perf_hooks";
|
||||||
|
import { Entity, Column, PrimaryGeneratedColumn, DataSource } from "typeorm";
|
||||||
|
|
||||||
|
type Response = {
|
||||||
|
insert: number[];
|
||||||
|
select: number[];
|
||||||
|
update: number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
@Entity("benchmark")
|
||||||
|
export class Task {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@Column("text")
|
||||||
|
title!: string;
|
||||||
|
|
||||||
|
@Column("text")
|
||||||
|
status!: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const appDataSource = new DataSource({
|
||||||
|
type: "sqlite",
|
||||||
|
database: ":memory:",
|
||||||
|
dropSchema: true,
|
||||||
|
entities: [Task],
|
||||||
|
synchronize: true, // create a new table
|
||||||
|
logging: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function sqlite_memory(count: Number): Promise<Response> {
|
||||||
|
var insert_stopwatchs: number[] = [];
|
||||||
|
let select_stopwatchs: number[] = [];
|
||||||
|
let update_stopwatchs: number[] = [];
|
||||||
|
|
||||||
|
let sw = performance;
|
||||||
|
|
||||||
|
const taskRepository = appDataSource.getRepository(Task);
|
||||||
|
|
||||||
|
// inserts
|
||||||
|
for (let index = 0; index < count; index++) {
|
||||||
|
const task_model = new Task();
|
||||||
|
task_model.title = "a";
|
||||||
|
task_model.status = "done";
|
||||||
|
|
||||||
|
const start = sw.now();
|
||||||
|
await taskRepository.save(task_model).then((value) => {
|
||||||
|
const insert_stopwatch = (sw.now() - start) * 1000000;
|
||||||
|
insert_stopwatchs.push(Math.floor(insert_stopwatch)); //nanoseconds
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// selects
|
||||||
|
for (let index = 0; index < count; index++) {
|
||||||
|
const start = sw.now();
|
||||||
|
await taskRepository.find().then((value) => {
|
||||||
|
const select_stopwatch = (sw.now() - start) * 1000000;
|
||||||
|
select_stopwatchs.push(Math.floor(select_stopwatch)); //nanoseconds
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates
|
||||||
|
for (let index = 0; index < count; index++) {
|
||||||
|
const taskToUpdate = await taskRepository.findOneBy({ id: 1 });
|
||||||
|
|
||||||
|
taskToUpdate!.title = "b";
|
||||||
|
taskToUpdate!.status = "finish";
|
||||||
|
|
||||||
|
const start = sw.now();
|
||||||
|
await taskRepository.save(taskToUpdate!).then((value) => {
|
||||||
|
const update_stopwatch = (sw.now() - start) * 1000000;
|
||||||
|
update_stopwatchs.push(Math.floor(update_stopwatch)); //nanoseconds
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// taskRepository.find().then((value) => {
|
||||||
|
// console.log(`value: %j`, value);
|
||||||
|
// });
|
||||||
|
|
||||||
|
let response: Response = {
|
||||||
|
insert: insert_stopwatchs,
|
||||||
|
select: select_stopwatchs,
|
||||||
|
update: update_stopwatchs,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Promise.resolve(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function sqlite_file(count: Number): Response {
|
||||||
|
// var insert_stopwatchs: number[] = [];
|
||||||
|
// let select_stopwatchs: number[] = [];
|
||||||
|
// let update_stopwatchs: number[] = [];
|
||||||
|
|
||||||
|
// for (let index = 0; index < count; index++) {
|
||||||
|
// insert_stopwatchs.push(index);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let response: Response = {
|
||||||
|
// insert: insert_stopwatchs,
|
||||||
|
// select: select_stopwatchs,
|
||||||
|
// update: update_stopwatchs,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function postgres(count: Number): Response {
|
||||||
|
// var insert_stopwatchs: number[] = [];
|
||||||
|
// let select_stopwatchs: number[] = [];
|
||||||
|
// let update_stopwatchs: number[] = [];
|
||||||
|
|
||||||
|
// for (let index = 0; index < count; index++) {
|
||||||
|
// insert_stopwatchs.push(index);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let response: Response = {
|
||||||
|
// insert: insert_stopwatchs,
|
||||||
|
// select: select_stopwatchs,
|
||||||
|
// update: update_stopwatchs,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function mysql(count: Number): Response {
|
||||||
|
// var insert_stopwatchs: number[] = [];
|
||||||
|
// let select_stopwatchs: number[] = [];
|
||||||
|
// let update_stopwatchs: number[] = [];
|
||||||
|
|
||||||
|
// for (let index = 0; index < count; index++) {
|
||||||
|
// insert_stopwatchs.push(index);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let response: Response = {
|
||||||
|
// insert: insert_stopwatchs,
|
||||||
|
// select: select_stopwatchs,
|
||||||
|
// update: update_stopwatchs,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return response;
|
||||||
|
// }
|
@ -0,0 +1,90 @@
|
|||||||
|
const http = require("http");
|
||||||
|
const fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
const { hello, sqlite_memory, appDataSource } = require("..");
|
||||||
|
|
||||||
|
const host = "localhost";
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
// const hello = require("../index")
|
||||||
|
|
||||||
|
const reqListener = async (req, res) => {
|
||||||
|
console.log(`[route] - (${req.method}) ${req.url}`);
|
||||||
|
|
||||||
|
var filePath = "." + req.url;
|
||||||
|
// if (filePath == './') {
|
||||||
|
// filePath = './index.html';
|
||||||
|
// }
|
||||||
|
|
||||||
|
var extname = String(path.extname(filePath)).toLowerCase();
|
||||||
|
var mimeTypes = {
|
||||||
|
".html": "text/html",
|
||||||
|
".js": "text/javascript",
|
||||||
|
".css": "text/css",
|
||||||
|
".json": "application/json",
|
||||||
|
".png": "image/png",
|
||||||
|
".jpg": "image/jpg",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".wav": "audio/wav",
|
||||||
|
".mp4": "video/mp4",
|
||||||
|
".woff": "application/font-woff",
|
||||||
|
".ttf": "application/font-ttf",
|
||||||
|
".eot": "application/vnd.ms-fontobject",
|
||||||
|
".otf": "application/font-otf",
|
||||||
|
".wasm": "application/wasm",
|
||||||
|
};
|
||||||
|
|
||||||
|
var contentType = mimeTypes[extname] || "application/octet-stream";
|
||||||
|
|
||||||
|
fs.readFile(filePath, function (error, content) {
|
||||||
|
if (error) {
|
||||||
|
if (error.code == "ENOENT") {
|
||||||
|
fs.readFile("./404.html", function (error, content) {
|
||||||
|
// res.writeHead(404, { "Content-Type": "text/html" });
|
||||||
|
// res.end(content, "utf-8");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(500);
|
||||||
|
res.end(
|
||||||
|
"Sorry, check with the site admin for error: " + error.code + " ..\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, { "Content-Type": contentType });
|
||||||
|
res.end(content, "utf-8");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
if (req.url == "/" && req.method == "GET") {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end("adad");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.url == "/hello-world" && req.method == "GET") {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end("hello world");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.url.includes("/sqlite-memory/") && req.method == "GET") {
|
||||||
|
var count = req.url.replace("/sqlite-memory/", "");
|
||||||
|
|
||||||
|
await sqlite_memory(count).then((response) => {
|
||||||
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
|
res.end(JSON.stringify(response));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const server = http.createServer(reqListener);
|
||||||
|
|
||||||
|
appDataSource.initialize();
|
||||||
|
console.log("Database working");
|
||||||
|
|
||||||
|
server.listen(port, host);
|
||||||
|
console.log(`Server is running on http://${host}:${port}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
|
||||||
|
|
||||||
|
/* Language and Environment */
|
||||||
|
"target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
|
"lib": ["es2022"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
|
||||||
|
/* Modules */
|
||||||
|
//Specify what module code is generated.
|
||||||
|
"module": "commonjs",
|
||||||
|
|
||||||
|
/* Emit */
|
||||||
|
// Specify an output folder for all emitted files.
|
||||||
|
"outDir": "./dist",
|
||||||
|
// Disable emitting comments.
|
||||||
|
"removeComments": true,
|
||||||
|
|
||||||
|
|
||||||
|
/* Interop Constraints */
|
||||||
|
// Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility.
|
||||||
|
"esModuleInterop": true,
|
||||||
|
// Ensure that casing is correct in imports.
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
|
||||||
|
/* Type Checking */
|
||||||
|
// Enable all strict type-checking options.
|
||||||
|
"strict": true,
|
||||||
|
|
||||||
|
|
||||||
|
// Completeness
|
||||||
|
// Skip type checking all .d.ts files.
|
||||||
|
"skipLibCheck": true },
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
|
||||||
|
}
|
131
examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v
Normal file
131
examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import vweb
|
||||||
|
import time
|
||||||
|
import sqlite
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
vweb.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
[table: 'benchmark']
|
||||||
|
struct Task {
|
||||||
|
mut:
|
||||||
|
id u32 [primary; serial; sql: serial]
|
||||||
|
title string
|
||||||
|
status string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Response {
|
||||||
|
insert []int
|
||||||
|
@select []int
|
||||||
|
update []int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
vweb.run_at(new_app(), vweb.RunParams{
|
||||||
|
port: 4000
|
||||||
|
}) or { panic(err) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_app() &App {
|
||||||
|
mut app := &App{}
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
['/hello-world']
|
||||||
|
pub fn (mut app App) hello_world() vweb.Result {
|
||||||
|
return app.text('hello world')
|
||||||
|
}
|
||||||
|
|
||||||
|
['/sqlite-memory/:count']
|
||||||
|
pub fn (mut app App) sqlite_memory(count int) vweb.Result {
|
||||||
|
mut insert_stopwatchs := []int{}
|
||||||
|
mut select_stopwatchs := []int{}
|
||||||
|
mut update_stopwatchs := []int{}
|
||||||
|
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
|
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
task_model := Task{
|
||||||
|
title: 'a'
|
||||||
|
status: 'done'
|
||||||
|
}
|
||||||
|
|
||||||
|
// inserts
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sw.start()
|
||||||
|
sql db {
|
||||||
|
insert task_model into Task
|
||||||
|
}
|
||||||
|
sw.stop()
|
||||||
|
insert_stopwatchs << int(sw.end - sw.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// selects
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sw.start()
|
||||||
|
result := sql db {
|
||||||
|
select from Task
|
||||||
|
}
|
||||||
|
sw.stop()
|
||||||
|
eprintln(result)
|
||||||
|
select_stopwatchs << int(sw.end - sw.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sw.start()
|
||||||
|
sql db {
|
||||||
|
update Task set title = 'b', status = 'finish' where id == i
|
||||||
|
}
|
||||||
|
sw.stop()
|
||||||
|
update_stopwatchs << int(sw.end - sw.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Task
|
||||||
|
}
|
||||||
|
|
||||||
|
response := Response{
|
||||||
|
insert: insert_stopwatchs
|
||||||
|
@select: select_stopwatchs
|
||||||
|
update: update_stopwatchs
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
['/sqlite-file/:count']
|
||||||
|
pub fn (mut app App) sqlite_file(count int) vweb.Result {
|
||||||
|
response := Response{
|
||||||
|
insert: []
|
||||||
|
@select: []
|
||||||
|
update: []
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
['/postgres/:count']
|
||||||
|
pub fn (mut app App) postgres(count int) vweb.Result {
|
||||||
|
response := Response{
|
||||||
|
insert: []
|
||||||
|
@select: []
|
||||||
|
update: []
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
['/mysql/:count']
|
||||||
|
pub fn (mut app App) mysql(count int) vweb.Result {
|
||||||
|
response := Response{
|
||||||
|
insert: []
|
||||||
|
@select: []
|
||||||
|
update: []
|
||||||
|
}
|
||||||
|
return app.json(response)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user