| 1 | module main |
| 2 | |
| 3 | import veb |
| 4 | import os |
| 5 | import json |
| 6 | import arrays |
| 7 | import net.http |
| 8 | import math |
| 9 | import v.util.version |
| 10 | |
| 11 | @[table: 'benchmark'] |
| 12 | struct Task { |
| 13 | mut: |
| 14 | id u32 @[primary; serial; sql: serial] |
| 15 | title string |
| 16 | status string |
| 17 | } |
| 18 | |
| 19 | struct FrameworkBenchmarkResponse { |
| 20 | insert []int |
| 21 | select []int |
| 22 | update []int |
| 23 | } |
| 24 | |
| 25 | struct FrameworkPlatform { |
| 26 | mut: |
| 27 | v_sqlite_memory []int |
| 28 | // v_sqlite_file []int |
| 29 | typescript_sqlite_memory []int |
| 30 | } |
| 31 | |
| 32 | fn (framework_platform FrameworkPlatform) to_map() map[string][]int { |
| 33 | mut mapa := map[string][]int{} |
| 34 | |
| 35 | mapa['v_sqlite_memory'] = framework_platform.v_sqlite_memory |
| 36 | // mapa['v_sqlite_file'] = framework_platform.v_sqlite_file |
| 37 | mapa['typescript_sqlite_memory'] = framework_platform.typescript_sqlite_memory |
| 38 | return mapa |
| 39 | } |
| 40 | |
| 41 | const http_port = 3001 |
| 42 | const benchmark_loop_length = 20 |
| 43 | |
| 44 | pub struct Context { |
| 45 | veb.Context |
| 46 | } |
| 47 | |
| 48 | struct App { |
| 49 | veb.StaticHandler |
| 50 | } |
| 51 | |
| 52 | enum SqliteDbConnection { |
| 53 | sqlite_memory |
| 54 | sqlite_file |
| 55 | } |
| 56 | |
| 57 | fn main() { |
| 58 | mut app := &App{} |
| 59 | app.serve_static('/favicon.ico', 'favicon.ico') or { panic(err) } |
| 60 | app.serve_static('/draw.js', 'draw.js') or { panic(err) } |
| 61 | app.mount_static_folder_at(os.resource_abs_path('.'), '/') or { panic(err) } |
| 62 | |
| 63 | veb.run[App, Context](mut app, http_port) |
| 64 | } |
| 65 | |
| 66 | pub fn (app &App) before_request(mut ctx Context) { |
| 67 | os.execute_or_panic('v -b js_browser draw.js.v ') |
| 68 | } |
| 69 | |
| 70 | @['/'; get] |
| 71 | pub fn (mut app App) controller_get_all_task(mut ctx Context) !veb.Result { |
| 72 | v_version := version.full_v_version(true) |
| 73 | orm_stmt_kinds := ['insert', 'select', 'update'] |
| 74 | |
| 75 | mut attribute_names := map[string][]string{} |
| 76 | // Used to garante the chart proposionalite |
| 77 | mut max_benchmark := map[string]int{} |
| 78 | mut from_framework := map[string]string{} |
| 79 | mut maxs := map[string][]int{} |
| 80 | mut framework_platform := map[string]map[string][]int{} |
| 81 | mut table := map[string]map[string]map[string]string{} |
| 82 | |
| 83 | chart_colors := ['gray', 'red', 'orange', 'purple', 'red', 'orange', 'purple'] |
| 84 | for orm_stmt_kind in orm_stmt_kinds { |
| 85 | match orm_stmt_kind { |
| 86 | 'insert' { |
| 87 | framework_platform[orm_stmt_kind] = insert_framework_benchmark_times() or { |
| 88 | return error('') |
| 89 | }.to_map() |
| 90 | } |
| 91 | 'select' { |
| 92 | framework_platform[orm_stmt_kind] = select_framework_benchmark_times() or { |
| 93 | return error('') |
| 94 | }.to_map() |
| 95 | } |
| 96 | 'update' { |
| 97 | framework_platform[orm_stmt_kind] = update_framework_benchmark_times() or { |
| 98 | return error('') |
| 99 | }.to_map() |
| 100 | } |
| 101 | else {} |
| 102 | } |
| 103 | |
| 104 | for key, values in framework_platform[orm_stmt_kind] { |
| 105 | attribute_names[orm_stmt_kind] << key |
| 106 | maxs[orm_stmt_kind] << arrays.max(values) or { continue } |
| 107 | } |
| 108 | |
| 109 | from_framework[orm_stmt_kind] = json.encode(framework_platform[orm_stmt_kind]) |
| 110 | table[orm_stmt_kind] = gen_table_info(attribute_names[orm_stmt_kind], |
| 111 | framework_platform[orm_stmt_kind]) |
| 112 | max_benchmark[orm_stmt_kind] = arrays.max(maxs[orm_stmt_kind]) or { continue } |
| 113 | } |
| 114 | |
| 115 | return $veb.html() |
| 116 | } |
| 117 | |
| 118 | fn insert_framework_benchmark_times() !FrameworkPlatform { |
| 119 | numbers := FrameworkPlatform{ |
| 120 | v_sqlite_memory: v_sqlite_memory()!.insert |
| 121 | // v_sqlite_file: v_sqlite_file()!.insert |
| 122 | typescript_sqlite_memory: typescript_sqlite_memory()!.insert |
| 123 | } |
| 124 | |
| 125 | return numbers |
| 126 | } |
| 127 | |
| 128 | fn select_framework_benchmark_times() !FrameworkPlatform { |
| 129 | numbers := FrameworkPlatform{ |
| 130 | v_sqlite_memory: v_sqlite_memory()!.select |
| 131 | // v_sqlite_file: v_sqlite_file()!.select |
| 132 | typescript_sqlite_memory: typescript_sqlite_memory()!.select |
| 133 | } |
| 134 | |
| 135 | return numbers |
| 136 | } |
| 137 | |
| 138 | fn update_framework_benchmark_times() !FrameworkPlatform { |
| 139 | numbers := FrameworkPlatform{ |
| 140 | v_sqlite_memory: v_sqlite_memory()!.update |
| 141 | // v_sqlite_file: v_sqlite_file()!.select |
| 142 | typescript_sqlite_memory: typescript_sqlite_memory()!.update |
| 143 | } |
| 144 | |
| 145 | return numbers |
| 146 | } |
| 147 | |
| 148 | fn typescript_sqlite_memory() !FrameworkBenchmarkResponse { |
| 149 | url := 'http://localhost:3000/sqlite-memory/${benchmark_loop_length}' |
| 150 | res := http.get(url) or { panic(err) } |
| 151 | framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)! |
| 152 | return framework_benchmark_response |
| 153 | } |
| 154 | |
| 155 | fn v_sqlite_memory() !FrameworkBenchmarkResponse { |
| 156 | url := 'http://localhost:4000/sqlite-memory/${benchmark_loop_length}' |
| 157 | res := http.get(url) or { panic(err) } |
| 158 | framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)! |
| 159 | return framework_benchmark_response |
| 160 | } |
| 161 | |
| 162 | fn gen_table_info(attribute_names []string, framework_platform map[string][]int) map[string]map[string]string { |
| 163 | mut table := map[string]map[string]string{} |
| 164 | |
| 165 | // nanoseconds |
| 166 | mut max_times := map[string]int{} |
| 167 | mut ten_perc_max_times := map[string]int{} |
| 168 | mut min_times := map[string]int{} |
| 169 | mut ten_perc_min_times := map[string]int{} |
| 170 | |
| 171 | // bigger to calculate percent |
| 172 | mut max := 0.0 |
| 173 | mut ten_perc_max := 0.0 |
| 174 | mut min := 0.0 |
| 175 | mut ten_perc_min := 0.0 |
| 176 | |
| 177 | // percentes |
| 178 | mut max_fast := map[string]int{} |
| 179 | mut ten_perc_max_fast := map[string]int{} |
| 180 | mut min_fast := map[string]int{} |
| 181 | mut ten_perc_min_fast := map[string]int{} |
| 182 | |
| 183 | // nanoseconds |
| 184 | for idx, name in attribute_names { |
| 185 | // qtd. of values in 10 % of arrays |
| 186 | ten_perc := int(framework_platform[name].len / 10) |
| 187 | |
| 188 | // get 10% higher |
| 189 | mut min_ten_array := framework_platform[name].clone() |
| 190 | min_ten_array.sort() |
| 191 | min_ten_array.trim(ten_perc) |
| 192 | |
| 193 | // get 10% lower |
| 194 | mut max_ten_array := framework_platform[name].clone() |
| 195 | max_ten_array.sort(a > b) |
| 196 | max_ten_array.trim(ten_perc) |
| 197 | |
| 198 | // popule array with nanoseconds to which benchmark |
| 199 | max_times[name] = arrays.max(framework_platform[name]) or { 0 } // int |
| 200 | ten_perc_max_times[name] = arrays.sum(max_ten_array) or { 0 } / ten_perc // int |
| 201 | min_times[name] = arrays.min(framework_platform[name]) or { 0 } // int |
| 202 | ten_perc_min_times[name] = arrays.sum(min_ten_array) or { 0 } / ten_perc // int |
| 203 | |
| 204 | // set bigger values |
| 205 | if idx < 1 { |
| 206 | max = f64(max_times[name]) |
| 207 | ten_perc_max = f64(ten_perc_max_times[name]) |
| 208 | min = f64(min_times[name]) |
| 209 | ten_perc_min = f64(ten_perc_min_times[name]) |
| 210 | } else { |
| 211 | if max < f64(max_times[name]) { |
| 212 | max = f64(max_times[name]) |
| 213 | } |
| 214 | if ten_perc_max < f64(ten_perc_max_times[name]) { |
| 215 | ten_perc_max = f64(ten_perc_max_times[name]) |
| 216 | } |
| 217 | if min < f64(min_times[name]) { |
| 218 | min = f64(min_times[name]) |
| 219 | } |
| 220 | if ten_perc_min < f64(ten_perc_min_times[name]) { |
| 221 | ten_perc_min = f64(ten_perc_min_times[name]) |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | // percents |
| 227 | for name in attribute_names { |
| 228 | max_fast[name] = int(max / f64(max_times[name])) |
| 229 | ten_perc_max_fast[name] = int(ten_perc_max / f64(ten_perc_max_times[name])) |
| 230 | min_fast[name] = int(min / f64(min_times[name])) |
| 231 | ten_perc_min_fast[name] = int(ten_perc_min / f64(ten_perc_min_times[name])) |
| 232 | } |
| 233 | |
| 234 | for name in attribute_names { |
| 235 | table[name]['max.'] = '${math.round_sig(f64(max_times[name]) / 1000000, 2)} ms (${max_fast[name]}x faster)' |
| 236 | table[name]['10% max.'] = '${math.round_sig(f64(ten_perc_max_times[name]) / 1000000, 2)} ms (${ten_perc_max_fast[name]}x faster)' |
| 237 | table[name]['min.'] = '${math.round_sig(f64(min_times[name]) / 1000000, 2)} ms (${min_fast[name]}x faster)' |
| 238 | table[name]['10% min.'] = '${math.round_sig(f64(ten_perc_min_times[name]) / 1000000, 2)} ms (${ten_perc_min_fast[name]}x faster)' |
| 239 | } |
| 240 | return table |
| 241 | } |
| 242 | |