1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

examples: V orm still fast? (#15330)

This commit is contained in:
Hitalo de Jesus do Rosário Souza 2022-08-07 22:38:38 -03:00 committed by GitHub
parent 0b1486f014
commit ee9142a113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 403 additions and 0 deletions

View File

@ -0,0 +1,3 @@
*.js
*.exe
*.db

View File

@ -0,0 +1,7 @@
FROM thevlang/vlang:alpine-dev
WORKDIR /app
COPY . .
RUN v up && v -prod main.v

View File

@ -0,0 +1,27 @@
# 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
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
02/09/2022
- [ ] select bench (easy)
- [ ] vsql (easy)

View File

@ -0,0 +1,111 @@
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{})
}

View File

@ -0,0 +1,217 @@
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
// }

View File

@ -0,0 +1,38 @@
<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>