├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── doc ├── intro-history.png ├── intro-svg.png ├── intro-tbl.png ├── intro-viewer-graph.png ├── intro-viewer-table.png ├── sort-tbl.png └── sql.png ├── examples └── lettersorter │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── benches │ └── sort_numbers.rs │ └── src │ └── lib.rs ├── rsc ├── README.md ├── dom-doll.js ├── sql-wasm.js ├── sql-wasm.wasm ├── viewer.css ├── viewer.js ├── vis-timeline-graph2d.min.css └── vis-timeline-graph2d.min.js └── src ├── bench.rs ├── black_box.rs ├── command.rs ├── db.rs ├── error.rs ├── git_info.rs ├── glassbench.rs ├── history_graph.rs ├── history_tbl.rs ├── html_viewer.rs ├── lib.rs ├── main_macro.rs ├── printer.rs ├── report.rs ├── skin.rs ├── task_bench.rs ├── task_bench_diff.rs ├── task_history.rs └── task_measure.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .bacon-locations 2 | /target 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### v0.4.3 - 2024-08-15 3 | - update git2 to 0.19 4 | - update rusqlite to 0.31 5 | 6 | 7 | ### v0.4.2 - 2024-08-12 8 | - update termimad to 0.30 9 | 10 | 11 | ### v0.4.1 - 2024-01-29 12 | - update termimad to 0.29 13 | 14 | 15 | ### v0.4.0 - 2024-01-18 16 | - cross-project dependency versions harmonization, termimad is now 0.28 17 | 18 | 19 | ### v0.3.6 - 2023/10/14 20 | - cross-project dependency versions harmonization to ease vetting 21 | 22 | 23 | ### v0.3.4 - 2022-12-10 24 | - fix a compilation problem (import ambiguity) - Thanks @orhun 25 | 26 | 27 | ### v0.3.3 - 2022-06-07 28 | - upgrade dependencies to fix compilation problems 29 | 30 | 31 | ### v0.3.1 - 2021-03-12 32 | - upgrade git2 dependency due to compilation problem with a minor 0.13 version 33 | 34 | 35 | ### v0.3.0 - 2021-04-02 36 | - new grapher, generated on `--graph` 37 | 38 | 39 | ### v0.2.2 - 2021-03-28 40 | - documentation improvements 41 | 42 | 43 | ### v0.2.1 - 2021-03-28 44 | - better documentation 45 | 46 | 47 | ### v0.2.0 - 2021-03-27 48 | - storage now based on sqlite3 49 | - `--tag` and `--history` 50 | 51 | 52 | ### v0.1.0 - 2021-03-25 53 | - first public release 54 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glassbench" 3 | version = "0.4.3" 4 | authors = ["dystroy "] 5 | repository = "https://github.com/Canop/glassbench" 6 | description = "rust benchmark with memory" 7 | edition = "2021" 8 | keywords = ["benchmark"] 9 | license = "MIT" 10 | categories = ["development-tools", "development-tools::profiling"] 11 | 12 | [dependencies] 13 | base64 = "0.13" 14 | chrono = { version = "0.4", features = ["serde"] } 15 | csv2svg = "0.2.3" 16 | git2 = { version="0.19", default-features=false } 17 | lazy_static = "1.4" 18 | open = "1.1" 19 | rusqlite = { version = "0.31", features = ["bundled"] } 20 | serde = { version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" 22 | tempfile = "3.1" 23 | termimad = { version = "0.30", default-features = false, features = ["special-renders"] } 24 | thiserror = "1.0" 25 | 26 | [patch.crates-io] 27 | # crokey = { path = "../crokey" } 28 | # termimad = { path = "../termimad" } 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Version][s1]][l1] [![docs][s3]][l3] [![Chat on Miaou][s4]][l4] [![MIT][s2]][l2] 2 | 3 | [s1]: https://img.shields.io/crates/v/glassbench.svg 4 | [l1]: https://crates.io/crates/glassbench 5 | 6 | [s2]: https://img.shields.io/badge/license-MIT-blue.svg 7 | [l2]: LICENSE 8 | 9 | [s3]: https://docs.rs/glassbench/badge.svg 10 | [l3]: https://docs.rs/glassbench/ 11 | 12 | [s4]: https://miaou.dystroy.org/static/shields/room.svg 13 | [l4]: https://miaou.dystroy.org/3768?rust 14 | 15 | Glassbench is a micro-benchmark library with memory, to use with `cargo bench`. 16 | 17 | # Why 18 | 19 | ## Run benchmarks and get a comparison with the previous execution 20 | 21 | ```bash 22 | cargo bench 23 | ``` 24 | 25 | You get compact tables with the mean durations of all the tasks you defined: 26 | 27 | ![tbl](doc/intro-tbl.png) 28 | 29 | ## Record every tests, with tags to help you compare strategies 30 | 31 | Read the whole history of your project's benchmarks, as everything is stored in SQLite. 32 | 33 | 34 | ```bash 35 | cargo bench -- -- --history 2 36 | ``` 37 | 38 | ![history](doc/intro-history.png) 39 | 40 | When trying optimization strategies, or just anything which you suspect may impact performance, you may tag a bench execution: 41 | 42 | ```bash 43 | cargo bench -- -- --tag "no zero" 44 | ``` 45 | 46 | ## Graph your various tests, filtering on tags 47 | 48 | Open the grapher: 49 | 50 | ```bash 51 | cargo bench -- -- --graph 52 | ``` 53 | 54 | (yes, there are two `--` before `--graph`) 55 | 56 | Graph a specific task: 57 | 58 | ```bash 59 | cargo bench -- my_task -- --graph 2 60 | ``` 61 | 62 | The viewer, with tabular and graphical views, opens in your browser: 63 | 64 | ![graph](doc/intro-viewer-graph.png) 65 | 66 | The graph can be zoomed with the mouse wheel and moved with the mouse. 67 | 68 | You can read the precise data in a table too: 69 | 70 | ![table](doc/intro-viewer-table.png) 71 | 72 | Everything is embedded in a standalone HTML page, there's no process running. The page can even be sent or hosted. 73 | 74 | ## Read or Edit benchmark history with SQL 75 | 76 | Using the [sqlite3 command line shell](https://sqlite.org/cli.html), you can run your own SQL queries: 77 | 78 | ![sql](doc/sql.png) 79 | 80 | You may remove the benchmarks of a period if you like, change tags a posteriori, etc. 81 | 82 | If you want to get rid of the whole histoyr, you can simply delete the `glassbench_v1.db` file. 83 | 84 | # Usage 85 | 86 | The complete testable example is in `/examples/lettersorter`. 87 | 88 | ## Add the dev-dependency 89 | 90 | ```TOML 91 | [dev-dependencies] 92 | glassbench = "0.3" 93 | ``` 94 | 95 | ## Prepare the benchmark 96 | 97 | Your bench file, located in `/benches`, must have a task defining function and a `glassbench!` call. 98 | 99 | Here we define one group, with two tasks, stressing the `lettersort::sort` function with two kinds of inputs. 100 | 101 | ```rust 102 | use { 103 | lettersorter::sort, 104 | glassbench::*, 105 | }; 106 | 107 | static SMALL_NUMBERS: &[&str] = &[ 108 | "0.123456789", 109 | "42", 110 | "-6", 111 | "π/2", 112 | "e²", 113 | ]; 114 | 115 | static BIG_NUMBERS: &[&str] = &[ 116 | "424568", 117 | "45865452*44574*778141*78999", 118 | "same but even bigger", 119 | "42!", 120 | "infinite", 121 | ]; 122 | 123 | fn bench_number_sorting(bench: &mut Bench) { 124 | bench.task("small numbers", |task| { 125 | task.iter(|| { 126 | for n in SMALL_NUMBERS { 127 | pretend_used(sort(n)); 128 | } 129 | }); 130 | }); 131 | bench.task("big numbers", |task| { 132 | task.iter(|| { 133 | for n in BIG_NUMBERS { 134 | pretend_used(sort(n)); 135 | } 136 | }); 137 | }); 138 | } 139 | 140 | glassbench!( 141 | "Number Sorting", 142 | bench_number_sorting, 143 | // you can pass other task defining functions here 144 | ); 145 | 146 | ``` 147 | 148 | The callback you give to `b.iter` will be executed many times after an initial warming. 149 | 150 | If you have some preparation to do, do it before `b.iter`. 151 | 152 | To prevent your function to be optimized away by the compiler, pass the values you build to `pretend_used`. 153 | 154 | The bench must be defined in `Cargo.toml` with `harness = false`: 155 | 156 | ```TOML 157 | [[bench]] 158 | name = "sort_numbers" 159 | harness = false 160 | ``` 161 | 162 | Until you finished preparing your benchmark, you probably don't want to save the results so you'll run glassbench with 163 | 164 | ```bash 165 | cargo bench -- -- --no-save 166 | ``` 167 | 168 | ## Bench command overview 169 | 170 | The command has the following form: 171 | 172 | ```bash 173 | cargo bench -- -- 174 | ``` 175 | 176 | The names of the benchs are the names of the bench files (see examples below). 177 | 178 | The glassbench arguments let you display the history or graph the records for a specific task, specify a tag, etc. 179 | 180 | ## Run all benchmarks 181 | 182 | ```bash 183 | cargo bench 184 | ``` 185 | 186 | This will run all benchmarks groups (even the ones not using Glassbench) and will produce something like this after a few tries and some optimization efforts: 187 | 188 | ![sort tbl](doc/sort-tbl.png) 189 | 190 | Be careful that you should not stress your system otherwise if you want to be able to compare executions. It's better to close everything else until it's done. 191 | 192 | ## Run just one benchmark 193 | 194 | Specify the id of the benchmark (taken from the bench file name) after `--` 195 | 196 | ```bash 197 | cargo bench -- sort_numbers 198 | ``` 199 | 200 | (as our example only has one benchmark, it's useless) 201 | 202 | You could specify several benchmarks like this: 203 | 204 | ```bash 205 | cargo bench -- sort_numbers sort_colors sort_flowers 206 | ``` 207 | 208 | ## Benchmark with a tag 209 | 210 | Let's assume we're trying with notable conditions, maybe a genius strategy, then we may want to have this information in the history. We can do 211 | 212 | ```bash 213 | cargo bench -- sort_numbers -- --tag "deep learning" 214 | ``` 215 | 216 | ## Look at the history of a specific task 217 | 218 | You refer to a task by its number in the table: 219 | 220 | ```bash 221 | cargo bench -- sort_numbers --history 1 222 | ``` 223 | 224 | ## Graph a task over executions 225 | 226 | Addition arguments are given after a second `--`. To graph a task, refer to it by its number in the table: 227 | 228 | ```bash 229 | cargo bench -- sort_numbers -- --graph 1 230 | ``` 231 | 232 | This opens in your browser a graph of the durations in nanoseconds of the first (`1`) task of the "sort_numbers" bench. 233 | 234 | *(note: the graph is a work in progress and should be improved in the future)* 235 | 236 | ## Other arguments 237 | 238 | `--no-save` just runs the benchmark, and compares with the previous saved execution, but doesn't save the result: 239 | 240 | ```bash 241 | cargo bench -- -- --no-save 242 | ``` 243 | 244 | # Read (or rewrite) the history with SQLite 245 | 246 | History is saved in the local `glassbench_v1.db` sqlite3 file. 247 | 248 | You should put its path in your vcs ignore list as measures can't be compared from one system to other ones. 249 | 250 | To enter an interactive SQL session, do 251 | 252 | ```bash 253 | sqlite3 glassbench_v1.db 254 | ``` 255 | 256 | Besides SQL queries, you might find useful `.schema`, which shows you the tables, and `.quit`. 257 | 258 | # Limits 259 | 260 | Glassbench measures the time really taken by your functions. It's the time which matters for your users but it's extremely sensible to the load of your system and can't be compared from one computer to another one. 261 | 262 | You must be cautious when looking at the history. Changes may be related to more than just your code efficiency: even if you didn't change the task, there may have been changes in your system load or efficiency. 263 | 264 | # Alternatives 265 | 266 | [Criterion](https://docs.rs/crate/criterion/0.3.4) is very similar. It produces detailed reports, and has more options than Glassbench, but doesn't have an history past the previous `cargo bench` (which is usually the one you most want). Glassbench tries to offer a more compact and easier to read display and encourages you to define as many tasks as your can have performance impacting kinds of inputs. 267 | 268 | # License 269 | 270 | MIT 271 | -------------------------------------------------------------------------------- /doc/intro-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/intro-history.png -------------------------------------------------------------------------------- /doc/intro-svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/intro-svg.png -------------------------------------------------------------------------------- /doc/intro-tbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/intro-tbl.png -------------------------------------------------------------------------------- /doc/intro-viewer-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/intro-viewer-graph.png -------------------------------------------------------------------------------- /doc/intro-viewer-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/intro-viewer-table.png -------------------------------------------------------------------------------- /doc/sort-tbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/sort-tbl.png -------------------------------------------------------------------------------- /doc/sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Canop/glassbench/114b6e48c3feec685af60c2bf5e01f50c9ec38d3/doc/sql.png -------------------------------------------------------------------------------- /examples/lettersorter/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /glassbench_*.db 3 | -------------------------------------------------------------------------------- /examples/lettersorter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lettersorter" 3 | version = "0.1.0" 4 | authors = ["Canop "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | [dev-dependencies] 10 | glassbench = { path = "../.." } 11 | 12 | [[bench]] 13 | name = "sort_numbers" 14 | harness = false 15 | -------------------------------------------------------------------------------- /examples/lettersorter/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | In this directory, run `cargo bench`. 4 | 5 | After that, have a look at the `sort` function in `lib.rs`. Try to optimize it, then check the results by running `cargo bench` again. 6 | 7 | Be careful that changing the benchmark test cases or the load on your system will impact the results. 8 | -------------------------------------------------------------------------------- /examples/lettersorter/benches/sort_numbers.rs: -------------------------------------------------------------------------------- 1 | use { 2 | lettersorter::sort, 3 | glassbench::*, 4 | }; 5 | 6 | static SMALL_NUMBERS: &[&str] = &[ 7 | "0.123456789", 8 | "42", 9 | "-6", 10 | "π/2", 11 | "e²", 12 | ]; 13 | 14 | static BIG_NUMBERS: &[&str] = &[ 15 | "424568", 16 | "45865452*44574*778141*78999", 17 | "same but even bigger", 18 | "42!", 19 | "infinite", 20 | ]; 21 | 22 | fn bench_number_sorting(bench: &mut Bench) { 23 | bench.task("small numbers", |task| { 24 | task.iter(|| { 25 | for n in SMALL_NUMBERS { 26 | pretend_used(sort(n)); 27 | } 28 | }); 29 | }); 30 | bench.task("big numbers", |task| { 31 | task.iter(|| { 32 | for n in BIG_NUMBERS { 33 | pretend_used(sort(n)); 34 | } 35 | }); 36 | }); 37 | } 38 | 39 | glassbench!( 40 | "Number Sorting", 41 | bench_number_sorting, 42 | ); 43 | 44 | -------------------------------------------------------------------------------- /examples/lettersorter/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | /// sort the letters in the string 3 | pub fn sort(s: &str) -> String { 4 | // let's build a string 5 | let mut s = s.to_string(); 6 | // let's add a 0 because strings should be zero terminated, right ? 7 | s.push_str("0"); 8 | // now make a vector: it's easier to sort 9 | let mut chars: Vec = s.chars().collect(); 10 | // sort in place (so it's faaast!) 11 | chars.sort(); 12 | // make the string to return 13 | let mut s: String = chars.iter().collect(); 14 | // wait, I've been told there should not be a zero, where is it ? 15 | let zero_idx = s.find('0'); 16 | // remove it before somebody notices it 17 | s.remove(zero_idx.unwrap()); 18 | // well, it's done 19 | s 20 | } 21 | 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use crate::*; 26 | #[test] 27 | fn it_works() { 28 | assert_eq!(sort("bac").as_str(), "abc"); 29 | assert_eq!(sort("π/2").as_str(), "/2π"); 30 | assert_eq!(sort("52145729034508").as_str(), "00122344555789"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rsc/README.md: -------------------------------------------------------------------------------- 1 | 2 | The files of this directory are directly embedded in the temporary HTML file you generate with `--graph`. 3 | 4 | `sql-*` files come from https://github.com/sql-js/sql.js (MIT license) and provide SQLite3 querying capabilities. 5 | 6 | `vis-*` files come from https://visjs.org/ (dual-licensed under Apache-2.0 and MIT) and provide the grapher. 7 | 8 | `dom-doll.js` comes from https://github.com/Canop/dom-doll (MIT license) and is an HTML DOM utility. 9 | -------------------------------------------------------------------------------- /rsc/dom-doll.js: -------------------------------------------------------------------------------- 1 | // dom-doll by dystroy 2 | // https://github.com/Canop/dom-doll 3 | 4 | function $() { 5 | const parser = /^<([^ .#>]+)?(?:#([^ .#>]+))?(?:\.([^ #>]+))?(?:[^>]*>(.+))?$/ 6 | var nodes 7 | for (let arg of arguments) { 8 | if (typeof arg == "string") { 9 | let parents = nodes || [document] 10 | nodes = [] 11 | for (let parent of parents) { 12 | let creator = arg.match(parser) 13 | if (creator) { 14 | let e = document.createElement(creator[1] || "div") 15 | if (creator[2]) e.id = creator[2] 16 | if (creator[3]) e.className = creator[3].replaceAll('.', ' ') 17 | if (creator[4]) e.textContent = creator[4] 18 | if (parent != document) { 19 | parent.appendChild(e) 20 | } 21 | nodes.push(e) 22 | } else { 23 | for (let child of parent.querySelectorAll(arg)) { 24 | nodes.push(child) 25 | } 26 | } 27 | } 28 | } else if (typeof arg == "function") { 29 | if (nodes) nodes.forEach(arg) 30 | else nodes = arg() 31 | } else if (arg instanceof Element) { 32 | if (nodes) nodes[0].appendChild(arg) 33 | else nodes = [arg] 34 | } else if (Array.isArray(arg)) { 35 | for (let e of arg) { 36 | nodes[0].appendChild(e) 37 | } 38 | } else if (typeof arg == "object") { 39 | for (let e of nodes) { 40 | for (let attr in arg) { 41 | let val = arg[attr] 42 | if (typeof val == "function") { 43 | e.addEventListener(attr, val) 44 | } else if (["textContent", "innerHTML"].includes(attr)) { 45 | e[attr] = val 46 | } else { 47 | e.setAttribute(attr, val) 48 | } 49 | } 50 | } 51 | } 52 | } 53 | return (nodes && nodes.length==1) ? nodes[0] : nodes 54 | } 55 | 56 | const $$ = document.querySelectorAll.bind(document) 57 | 58 | 59 | -------------------------------------------------------------------------------- /rsc/sql-wasm.js: -------------------------------------------------------------------------------- 1 | 2 | // We are modularizing this manually because the current modularize setting in Emscripten has some issues: 3 | // https://github.com/kripken/emscripten/issues/5820 4 | // In addition, When you use emcc's modularization, it still expects to export a global object called `Module`, 5 | // which is able to be used/called before the WASM is loaded. 6 | // The modularization below exports a promise that loads and resolves to the actual sql.js module. 7 | // That way, this module can't be used before the WASM is finished loading. 8 | 9 | // We are going to define a function that a user will call to start loading initializing our Sql.js library 10 | // However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module 11 | // Instead, we want to return the previously loaded module 12 | 13 | // TODO: Make this not declare a global if used in the browser 14 | var initSqlJsPromise = undefined; 15 | 16 | var initSqlJs = function (moduleConfig) { 17 | 18 | if (initSqlJsPromise){ 19 | return initSqlJsPromise; 20 | } 21 | // If we're here, we've never called this function before 22 | initSqlJsPromise = new Promise(function (resolveModule, reject) { 23 | 24 | // We are modularizing this manually because the current modularize setting in Emscripten has some issues: 25 | // https://github.com/kripken/emscripten/issues/5820 26 | 27 | // The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add 28 | // properties to it, like `preRun`, `postRun`, etc 29 | // We are using that to get notified when the WASM has finished loading. 30 | // Only then will we return our promise 31 | 32 | // If they passed in a moduleConfig object, use that 33 | // Otherwise, initialize Module to the empty object 34 | var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {}; 35 | 36 | // EMCC only allows for a single onAbort function (not an array of functions) 37 | // So if the user defined their own onAbort function, we remember it and call it 38 | var originalOnAbortFunction = Module['onAbort']; 39 | Module['onAbort'] = function (errorThatCausedAbort) { 40 | reject(new Error(errorThatCausedAbort)); 41 | if (originalOnAbortFunction){ 42 | originalOnAbortFunction(errorThatCausedAbort); 43 | } 44 | }; 45 | 46 | Module['postRun'] = Module['postRun'] || []; 47 | Module['postRun'].push(function () { 48 | // When Emscripted calls postRun, this promise resolves with the built Module 49 | resolveModule(Module); 50 | }); 51 | 52 | // There is a section of code in the emcc-generated code below that looks like this: 53 | // (Note that this is lowercase `module`) 54 | // if (typeof module !== 'undefined') { 55 | // module['exports'] = Module; 56 | // } 57 | // When that runs, it's going to overwrite our own modularization export efforts in shell-post.js! 58 | // The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags, 59 | // but that carries with it additional unnecessary baggage/bugs we don't want either. 60 | // So, we have three options: 61 | // 1) We undefine `module` 62 | // 2) We remember what `module['exports']` was at the beginning of this function and we restore it later 63 | // 3) We write a script to remove those lines of code as part of the Make process. 64 | // 65 | // Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward 66 | // of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future. 67 | // That's a nice side effect since we're handling the modularization efforts ourselves 68 | module = undefined; 69 | 70 | // The emcc-generated code and shell-post.js code goes below, 71 | // meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort 72 | 73 | var e;e||(e=typeof Module !== 'undefined' ? Module : {});null; 74 | e.onRuntimeInitialized=function(){function a(h,l){this.Ra=h;this.db=l;this.Qa=1;this.lb=[]}function b(h,l){this.db=l;l=aa(h)+1;this.eb=ba(l);if(null===this.eb)throw Error("Unable to allocate memory for the SQL string");k(h,m,this.eb,l);this.jb=this.eb;this.$a=this.pb=null}function c(h){this.filename="dbfile_"+(4294967295*Math.random()>>>0);if(null!=h){var l=this.filename,p=l?r("//"+l):"/";l=ca(!0,!0);p=da(p,(void 0!==l?l:438)&4095|32768,0);if(h){if("string"===typeof h){for(var q=Array(h.length),B= 75 | 0,ha=h.length;Bd;++d)g.parameters.push(f["viii"[d]]); 96 | d=new WebAssembly.Function(g,a)}else{f=[1,0,1,96];g={i:127,j:126,f:125,d:124};f.push(3);for(d=0;3>d;++d)f.push(g["iii"[d]]);f.push(0);f[1]=f.length-2;d=new Uint8Array([0,97,115,109,1,0,0,0].concat(f,[2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0]));d=new WebAssembly.Module(d);d=(new WebAssembly.Instance(d,{e:{f:a}})).exports.f}b.set(c,d)}Ia.set(a,c);a=c}return a}function ra(a){ua(a)}var Ka;e.wasmBinary&&(Ka=e.wasmBinary);var noExitRuntime;e.noExitRuntime&&(noExitRuntime=e.noExitRuntime); 97 | "object"!==typeof WebAssembly&&K("no native wasm support detected"); 98 | function pa(a){var b="i32";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":z[a>>0]=0;break;case "i8":z[a>>0]=0;break;case "i16":La[a>>1]=0;break;case "i32":L[a>>2]=0;break;case "i64":M=[0,(N=0,1<=+Math.abs(N)?0>>0:~~+Math.ceil((N-+(~~N>>>0))/4294967296)>>>0:0)];L[a>>2]=M[0];L[a+4>>2]=M[1];break;case "float":Ma[a>>2]=0;break;case "double":Na[a>>3]=0;break;default:K("invalid type for setValue: "+b)}} 99 | function x(a,b){b=b||"i8";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return z[a>>0];case "i8":return z[a>>0];case "i16":return La[a>>1];case "i32":return L[a>>2];case "i64":return L[a>>2];case "float":return Ma[a>>2];case "double":return Na[a>>3];default:K("invalid type for getValue: "+b)}return null}var Oa,Ja,Pa=!1;function assert(a,b){a||K("Assertion failed: "+b)}function Qa(a){var b=e["_"+a];assert(b,"Cannot call unknown function "+a+", make sure it is exported");return b} 100 | function Ra(a,b,c,d){var f={string:function(v){var C=0;if(null!==v&&void 0!==v&&0!==v){var H=(v.length<<2)+1;C=y(H);k(v,m,C,H)}return C},array:function(v){var C=y(v.length);z.set(v,C);return C}},g=Qa(a),n=[];a=0;if(d)for(var t=0;t=d);)++c;if(16f?d+=String.fromCharCode(f):(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else d+=String.fromCharCode(f)}return d}function A(a,b){return a?Va(m,a,b):""} 103 | function k(a,b,c,d){if(!(0=n){var t=a.charCodeAt(++g);n=65536+((n&1023)<<10)|t&1023}if(127>=n){if(c>=d)break;b[c++]=n}else{if(2047>=n){if(c+1>=d)break;b[c++]=192|n>>6}else{if(65535>=n){if(c+2>=d)break;b[c++]=224|n>>12}else{if(c+3>=d)break;b[c++]=240|n>>18;b[c++]=128|n>>12&63}b[c++]=128|n>>6&63}b[c++]=128|n&63}}b[c]=0;return c-f} 104 | function aa(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}return b}function Wa(a){var b=aa(a)+1,c=ba(b);c&&k(a,z,c,b);return c}var Xa,z,m,La,L,Ma,Na; 105 | function Ya(a){Xa=a;e.HEAP8=z=new Int8Array(a);e.HEAP16=La=new Int16Array(a);e.HEAP32=L=new Int32Array(a);e.HEAPU8=m=new Uint8Array(a);e.HEAPU16=new Uint16Array(a);e.HEAPU32=new Uint32Array(a);e.HEAPF32=Ma=new Float32Array(a);e.HEAPF64=Na=new Float64Array(a)}var Za=e.INITIAL_MEMORY||16777216;e.wasmMemory?Oa=e.wasmMemory:Oa=new WebAssembly.Memory({initial:Za/65536,maximum:32768});Oa&&(Xa=Oa.buffer);Za=Xa.byteLength;Ya(Xa);var $a=[],ab=[],bb=[],cb=[]; 106 | function db(){var a=e.preRun.shift();$a.unshift(a)}var eb=0,fb=null,gb=null;e.preloadedImages={};e.preloadedAudios={};function K(a){if(e.onAbort)e.onAbort(a);J(a);Pa=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}function hb(a){var b=ib;return String.prototype.startsWith?b.startsWith(a):0===b.indexOf(a)}function jb(){return hb("data:application/octet-stream;base64,")}var ib="sql-wasm.wasm"; 107 | if(!jb()){ 108 | var kb=ib; 109 | ib = e.locateFile?e.locateFile(kb,I):I+kb 110 | } 111 | function lb(){ 112 | try{ 113 | if(Ka)return new Uint8Array(Ka); 114 | if(Ca)return Ca(ib); 115 | throw"both async and sync fetching of the wasm failed"; 116 | } catch(a){ 117 | K(a) 118 | } 119 | } 120 | function mb(){return Ka||!ya&&!G||"function"!==typeof fetch||hb("file://")?Promise.resolve().then(lb):fetch(ib,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+ib+"'";return a.arrayBuffer()}).catch(function(){return lb()})}var N,M; 121 | function nb(a){for(;0>2]=60*(new Date).getTimezoneOffset();var b=(new Date).getFullYear(),c=new Date(b,0,1);b=new Date(b,6,1);L[vb()>>2]=Number(c.getTimezoneOffset()!=b.getTimezoneOffset());var d=a(c),f=a(b);d=Wa(d);f=Wa(f);b.getTimezoneOffset()>2]=d,L[xb()+4>>2]=f):(L[xb()>>2]=f,L[xb()+4>>2]=d)}}var tb; 123 | function yb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var f=a[d];"."===f?a.splice(d,1):".."===f?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a}function r(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=yb(a.split("/").filter(function(d){return!!d}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} 124 | function zb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function Ab(a){if("/"===a)return"/";a=r(a);a=a.replace(/\/$/,"");var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function Bb(a){L[Cb()>>2]=a} 125 | function Db(){if("object"===typeof crypto&&"function"===typeof crypto.getRandomValues){var a=new Uint8Array(1);return function(){crypto.getRandomValues(a);return a[0]}}if(za)try{var b=require("crypto");return function(){return b.randomBytes(1)[0]}}catch(c){}return function(){K("randomDevice")}} 126 | function Eb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=yb(a.split("/").filter(function(d){return!!d}),!b).join("/");return(b?"/":"")+a||"."}var Fb=[];function Gb(a,b){Fb[a]={input:[],output:[],cb:b};Hb(a,Ib)} 127 | var Ib={open:function(a){var b=Fb[a.node.rdev];if(!b)throw new O(43);a.tty=b;a.seekable=!1},close:function(a){a.tty.cb.flush(a.tty)},flush:function(a){a.tty.cb.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.cb.xb)throw new O(60);for(var f=0,g=0;g=b||(b=Math.max(b,c*(1048576>c?2:1.125)>>>0),0!=c&&(b=Math.max(b,256)),c=a.Ma,a.Ma=new Uint8Array(b),0b)a.Ma.length=b;else for(;a.Ma.length=a.node.Sa)return 0;a=Math.min(a.node.Sa-f,d);if(8b)throw new O(28);return b},sb:function(a,b,c){P.vb(a.node,b+c);a.node.Sa=Math.max(a.node.Sa,b+c)},hb:function(a,b,c,d,f,g){assert(0===b);if(32768!==(a.node.mode&61440))throw new O(43);a=a.node.Ma; 137 | if(g&2||a.buffer!==Xa){if(0>>0)%T.length}function Wb(a){var b=Vb(a.parent.id,a.name);if(T[b]===a)T[b]=a.bb;else for(b=T[b];b;){if(b.bb===a){b.bb=a.bb;break}b=b.bb}} 140 | function Ob(a,b){var c;if(c=(c=Xb(a,"x"))?c:a.Na.lookup?0:2)throw new O(c,a);for(c=T[Vb(a.id,b)];c;c=c.bb){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.Na.lookup(a,b)}function Mb(a,b,c,d){a=new Yb(a,b,c,d);b=Vb(a.parent.id,a.name);a.bb=T[b];return T[b]=a}function Q(a){return 16384===(a&61440)}var Zb={r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218}; 141 | function $b(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}function Xb(a,b){if(Sb)return 0;if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return 2}else return 2;return 0}function ac(a,b){try{return Ob(a,b),20}catch(c){}return Xb(a,"wx")}function bc(a,b,c){try{var d=Ob(a,b)}catch(f){return f.Pa}if(a=Xb(a,"wx"))return a;if(c){if(!Q(d.mode))return 54;if(d===d.parent||"/"===Ub(d))return 10}else if(Q(d.mode))return 31;return 0} 142 | function cc(a){var b=4096;for(a=a||0;a<=b;a++)if(!S[a])return a;throw new O(33);}function dc(a,b){ec||(ec=function(){},ec.prototype={});var c=new ec,d;for(d in a)c[d]=a[d];a=c;b=cc(b);a.fd=b;return S[b]=a}var Lb={open:function(a){a.Oa=Qb[a.node.rdev].Oa;a.Oa.open&&a.Oa.open(a)},Za:function(){throw new O(70);}};function Hb(a,b){Qb[a]={Oa:b}} 143 | function fc(a,b){var c="/"===b,d=!b;if(c&&Pb)throw new O(10);if(!c&&!d){var f=V(b,{wb:!1});b=f.path;f=f.node;if(f.ab)throw new O(10);if(!Q(f.mode))throw new O(54);}b={type:a,Ub:{},yb:b,Mb:[]};a=a.Wa(b);a.Wa=b;b.root=a;c?Pb=a:f&&(f.ab=b,f.Wa&&f.Wa.Mb.push(b))}function da(a,b,c){var d=V(a,{parent:!0}).node;a=Ab(a);if(!a||"."===a||".."===a)throw new O(28);var f=ac(d,a);if(f)throw new O(f);if(!d.Na.gb)throw new O(63);return d.Na.gb(d,a,b,c)}function W(a,b){da(a,(void 0!==b?b:511)&1023|16384,0)} 144 | function hc(a,b,c){"undefined"===typeof c&&(c=b,b=438);da(a,b|8192,c)}function ic(a,b){if(!Eb(a))throw new O(44);var c=V(b,{parent:!0}).node;if(!c)throw new O(44);b=Ab(b);var d=ac(c,b);if(d)throw new O(d);if(!c.Na.symlink)throw new O(63);c.Na.symlink(c,b,a)} 145 | function ta(a){var b=V(a,{parent:!0}).node,c=Ab(a),d=Ob(b,c),f=bc(b,c,!1);if(f)throw new O(f);if(!b.Na.unlink)throw new O(63);if(d.ab)throw new O(10);try{U.willDeletePath&&U.willDeletePath(a)}catch(g){J("FS.trackingDelegate['willDeletePath']('"+a+"') threw an exception: "+g.message)}b.Na.unlink(b,c);Wb(d);try{if(U.onDeletePath)U.onDeletePath(a)}catch(g){J("FS.trackingDelegate['onDeletePath']('"+a+"') threw an exception: "+g.message)}} 146 | function Tb(a){a=V(a).node;if(!a)throw new O(44);if(!a.Na.readlink)throw new O(28);return Eb(Ub(a.parent),a.Na.readlink(a))}function jc(a,b){a=V(a,{Ya:!b}).node;if(!a)throw new O(44);if(!a.Na.Ua)throw new O(63);return a.Na.Ua(a)}function kc(a){return jc(a,!0)}function ea(a,b){var c;"string"===typeof a?c=V(a,{Ya:!0}).node:c=a;if(!c.Na.Ta)throw new O(63);c.Na.Ta(c,{mode:b&4095|c.mode&-4096,timestamp:Date.now()})} 147 | function lc(a){var b;"string"===typeof a?b=V(a,{Ya:!0}).node:b=a;if(!b.Na.Ta)throw new O(63);b.Na.Ta(b,{timestamp:Date.now()})}function mc(a,b){if(0>b)throw new O(28);var c;"string"===typeof a?c=V(a,{Ya:!0}).node:c=a;if(!c.Na.Ta)throw new O(63);if(Q(c.mode))throw new O(31);if(32768!==(c.mode&61440))throw new O(28);if(a=Xb(c,"w"))throw new O(a);c.Na.Ta(c,{size:b,timestamp:Date.now()})} 148 | function u(a,b,c,d){if(""===a)throw new O(44);if("string"===typeof b){var f=Zb[b];if("undefined"===typeof f)throw Error("Unknown file open mode: "+b);b=f}c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;if("object"===typeof a)var g=a;else{a=r(a);try{g=V(a,{Ya:!(b&131072)}).node}catch(n){}}f=!1;if(b&64)if(g){if(b&128)throw new O(20);}else g=da(a,c,0),f=!0;if(!g)throw new O(44);8192===(g.mode&61440)&&(b&=-513);if(b&65536&&!Q(g.mode))throw new O(54);if(!f&&(c=g?40960===(g.mode&61440)?32:Q(g.mode)&& 149 | ("r"!==$b(b)||b&512)?31:Xb(g,$b(b)):44))throw new O(c);b&512&&mc(g,0);b&=-131713;d=dc({node:g,path:Ub(g),flags:b,seekable:!0,position:0,Oa:g.Oa,Rb:[],error:!1},d);d.Oa.open&&d.Oa.open(d);!e.logReadFiles||b&1||(Pc||(Pc={}),a in Pc||(Pc[a]=1,J("FS.trackingDelegate error on read file: "+a)));try{U.onOpenFile&&(g=0,1!==(b&2097155)&&(g|=1),0!==(b&2097155)&&(g|=2),U.onOpenFile(a,g))}catch(n){J("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+n.message)}return d} 150 | function ka(a){if(null===a.fd)throw new O(8);a.ob&&(a.ob=null);try{a.Oa.close&&a.Oa.close(a)}catch(b){throw b;}finally{S[a.fd]=null}a.fd=null}function Qc(a,b,c){if(null===a.fd)throw new O(8);if(!a.seekable||!a.Oa.Za)throw new O(70);if(0!=c&&1!=c&&2!=c)throw new O(28);a.position=a.Oa.Za(a,b,c);a.Rb=[]} 151 | function Sc(a,b,c,d,f){if(0>d||0>f)throw new O(28);if(null===a.fd)throw new O(8);if(1===(a.flags&2097155))throw new O(8);if(Q(a.node.mode))throw new O(31);if(!a.Oa.read)throw new O(28);var g="undefined"!==typeof f;if(!g)f=a.position;else if(!a.seekable)throw new O(70);b=a.Oa.read(a,b,c,d,f);g||(a.position+=b);return b} 152 | function fa(a,b,c,d,f,g){if(0>d||0>f)throw new O(28);if(null===a.fd)throw new O(8);if(0===(a.flags&2097155))throw new O(8);if(Q(a.node.mode))throw new O(31);if(!a.Oa.write)throw new O(28);a.seekable&&a.flags&1024&&Qc(a,0,2);var n="undefined"!==typeof f;if(!n)f=a.position;else if(!a.seekable)throw new O(70);b=a.Oa.write(a,b,c,d,f,g);n||(a.position+=b);try{if(a.path&&U.onWriteToFile)U.onWriteToFile(a.path)}catch(t){J("FS.trackingDelegate['onWriteToFile']('"+a.path+"') threw an exception: "+t.message)}return b} 153 | function sa(a){var b={encoding:"binary"};b=b||{};b.flags=b.flags||"r";b.encoding=b.encoding||"binary";if("utf8"!==b.encoding&&"binary"!==b.encoding)throw Error('Invalid encoding type "'+b.encoding+'"');var c,d=u(a,b.flags);a=jc(a).size;var f=new Uint8Array(a);Sc(d,f,0,a,0);"utf8"===b.encoding?c=Va(f,0):"binary"===b.encoding&&(c=f);ka(d);return c} 154 | function Tc(){O||(O=function(a,b){this.node=b;this.Qb=function(c){this.Pa=c};this.Qb(a);this.message="FS error"},O.prototype=Error(),O.prototype.constructor=O,[44].forEach(function(a){Nb[a]=new O(a);Nb[a].stack=""}))}var Uc;function ca(a,b){var c=0;a&&(c|=365);b&&(c|=146);return c} 155 | function Vc(a,b,c){a=r("/dev/"+a);var d=ca(!!b,!!c);Wc||(Wc=64);var f=Wc++<<8|0;Hb(f,{open:function(g){g.seekable=!1},close:function(){c&&c.buffer&&c.buffer.length&&c(10)},read:function(g,n,t,w){for(var v=0,C=0;C>2]=d.dev;L[c+4>>2]=0;L[c+8>>2]=d.ino;L[c+12>>2]=d.mode;L[c+16>>2]=d.nlink;L[c+20>>2]=d.uid;L[c+24>>2]=d.gid;L[c+28>>2]=d.rdev;L[c+32>>2]=0;M=[d.size>>>0,(N=d.size,1<=+Math.abs(N)?0>>0:~~+Math.ceil((N-+(~~N>>>0))/4294967296)>>>0:0)];L[c+40>>2]=M[0];L[c+44>>2]=M[1];L[c+48>>2]=4096;L[c+52>>2]=d.blocks;L[c+56>>2]=d.atime.getTime()/1E3|0;L[c+60>>2]= 158 | 0;L[c+64>>2]=d.mtime.getTime()/1E3|0;L[c+68>>2]=0;L[c+72>>2]=d.ctime.getTime()/1E3|0;L[c+76>>2]=0;M=[d.ino>>>0,(N=d.ino,1<=+Math.abs(N)?0>>0:~~+Math.ceil((N-+(~~N>>>0))/4294967296)>>>0:0)];L[c+80>>2]=M[0];L[c+84>>2]=M[1];return 0}var Zc=void 0;function $c(){Zc+=4;return L[Zc-4>>2]}function Z(a){a=S[a];if(!a)throw new O(8);return a}var ad={}; 159 | function bd(){if(!cd){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:xa||"./this.program"},b;for(b in ad)a[b]=ad[b];var c=[];for(b in a)c.push(b+"="+a[b]);cd=c}return cd}var cd,dd;za?dd=function(){var a=process.hrtime();return 1E3*a[0]+a[1]/1E6}:"undefined"!==typeof dateNow?dd=dateNow:dd=function(){return performance.now()}; 160 | function ed(a){for(var b=dd();dd()-b>2]);L[b>>2]=a.getSeconds();L[b+4>>2]=a.getMinutes();L[b+8>>2]=a.getHours();L[b+12>>2]=a.getDate();L[b+16>>2]=a.getMonth();L[b+20>>2]=a.getFullYear()-1900;L[b+24>>2]=a.getDay();var c=new Date(a.getFullYear(),0,1);L[b+28>>2]=(a.getTime()-c.getTime())/864E5|0;L[b+36>>2]=-(60*a.getTimezoneOffset());var d=(new Date(a.getFullYear(),6,1)).getTimezoneOffset(); 164 | c=c.getTimezoneOffset();a=(d!=c&&a.getTimezoneOffset()==Math.min(c,d))|0;L[b+32>>2]=a;a=L[xb()+(a?4:0)>>2];L[b+40>>2]=a;return b},z:function(a,b){try{a=A(a);if(b&-8)var c=-28;else{var d;(d=V(a,{Ya:!0}).node)?(a="",b&4&&(a+="r"),b&2&&(a+="w"),b&1&&(a+="x"),c=a&&Xb(d,a)?-2:0):c=-44}return c}catch(f){return"undefined"!==typeof X&&f instanceof O||K(f),-f.Pa}},i:function(a,b){try{return a=A(a),ea(a,b),0}catch(c){return"undefined"!==typeof X&&c instanceof O||K(c),-c.Pa}},t:function(a){try{return a=A(a), 165 | lc(a),0}catch(b){return"undefined"!==typeof X&&b instanceof O||K(b),-b.Pa}},j:function(a,b){try{var c=S[a];if(!c)throw new O(8);ea(c.node,b);return 0}catch(d){return"undefined"!==typeof X&&d instanceof O||K(d),-d.Pa}},u:function(a){try{var b=S[a];if(!b)throw new O(8);lc(b.node);return 0}catch(c){return"undefined"!==typeof X&&c instanceof O||K(c),-c.Pa}},c:function(a,b,c){Zc=c;try{var d=Z(a);switch(b){case 0:var f=$c();return 0>f?-28:u(d.path,d.flags,0,f).fd;case 1:case 2:return 0;case 3:return d.flags; 166 | case 4:return f=$c(),d.flags|=f,0;case 12:return f=$c(),La[f+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return Bb(28),-1;default:return-28}}catch(g){return"undefined"!==typeof X&&g instanceof O||K(g),-g.Pa}},K:function(a,b){try{var c=Z(a);return Yc(jc,c.path,b)}catch(d){return"undefined"!==typeof X&&d instanceof O||K(d),-d.Pa}},v:function(a,b,c){try{var d=S[a];if(!d)throw new O(8);if(0===(d.flags&2097155))throw new O(28);mc(d.node,c);return 0}catch(f){return"undefined"!==typeof X&& 167 | f instanceof O||K(f),-f.Pa}},w:function(a,b){try{if(0===b)return-28;if(b=c)var d=-28;else{var f=Tb(a),g=Math.min(c,aa(f)),n=z[b+g];k(f,m,b,c+1);z[b+g]=n;d=g}return d}catch(t){return"undefined"!==typeof X&&t instanceof O||K(t),-t.Pa}},E:function(a){try{a=A(a);var b=V(a,{parent:!0}).node,c=Ab(a),d=Ob(b,c),f=bc(b,c,!0);if(f)throw new O(f);if(!b.Na.rmdir)throw new O(63);if(d.ab)throw new O(10);try{U.willDeletePath&&U.willDeletePath(a)}catch(g){J("FS.trackingDelegate['willDeletePath']('"+a+"') threw an exception: "+ 171 | g.message)}b.Na.rmdir(b,c);Wb(d);try{if(U.onDeletePath)U.onDeletePath(a)}catch(g){J("FS.trackingDelegate['onDeletePath']('"+a+"') threw an exception: "+g.message)}return 0}catch(g){return"undefined"!==typeof X&&g instanceof O||K(g),-g.Pa}},g:function(a,b){try{return a=A(a),Yc(jc,a,b)}catch(c){return"undefined"!==typeof X&&c instanceof O||K(c),-c.Pa}},y:function(a){try{return a=A(a),ta(a),0}catch(b){return"undefined"!==typeof X&&b instanceof O||K(b),-b.Pa}},m:function(a,b,c){m.copyWithin(a,b,b+c)}, 172 | d:function(a){a>>>=0;var b=m.length;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(16777216,a,d);0>>16);Ya(Oa.buffer);var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1},o:function(a,b){var c=0;bd().forEach(function(d,f){var g=b+c;f=L[a+4*f>>2]=g;for(g=0;g>0]=d.charCodeAt(g);z[f>>0]=0;c+=d.length+1});return 0},p:function(a,b){var c= 173 | bd();L[a>>2]=c.length;var d=0;c.forEach(function(f){d+=f.length+1});L[b>>2]=d;return 0},f:function(a){try{var b=Z(a);ka(b);return 0}catch(c){return"undefined"!==typeof X&&c instanceof O||K(c),c.Pa}},n:function(a,b){try{var c=Z(a);z[b>>0]=c.tty?2:Q(c.mode)?3:40960===(c.mode&61440)?7:4;return 0}catch(d){return"undefined"!==typeof X&&d instanceof O||K(d),d.Pa}},l:function(a,b,c,d,f){try{var g=Z(a);a=4294967296*c+(b>>>0);if(-9007199254740992>=a||9007199254740992<=a)return-61;Qc(g,a,d);M=[g.position>>> 174 | 0,(N=g.position,1<=+Math.abs(N)?0>>0:~~+Math.ceil((N-+(~~N>>>0))/4294967296)>>>0:0)];L[f>>2]=M[0];L[f+4>>2]=M[1];g.ob&&0===a&&0===d&&(g.ob=null);return 0}catch(n){return"undefined"!==typeof X&&n instanceof O||K(n),n.Pa}},x:function(a){try{var b=Z(a);return b.Oa&&b.Oa.fsync?-b.Oa.fsync(b):0}catch(c){return"undefined"!==typeof X&&c instanceof O||K(c),c.Pa}},F:function(a,b,c,d){try{a:{for(var f=Z(a),g=a=0;g>2],L[b+(8* 175 | g+4)>>2],void 0);if(0>n){var t=-1;break a}a+=n}t=a}L[d>>2]=t;return 0}catch(w){return"undefined"!==typeof X&&w instanceof O||K(w),w.Pa}},h:function(a){var b=Date.now();L[a>>2]=b/1E3|0;L[a+4>>2]=b%1E3*1E3|0;return 0},a:Oa,A:function(a,b){if(0===a)return Bb(28),-1;var c=L[a>>2];a=L[a+4>>2];if(0>a||999999999c)return Bb(28),-1;0!==b&&(L[b>>2]=0,L[b+4>>2]=0);return ed(1E6*c+a/1E3)},B:function(a){switch(a){case 30:return 16384;case 85:return 131072;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809; 176 | case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32; 177 | case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1E3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"===typeof navigator?navigator.hardwareConcurrency||1:1}Bb(28);return-1}, 178 | L:function(a){var b=Date.now()/1E3|0;a&&(L[a>>2]=b);return b},r:function(a,b){if(b){var c=1E3*L[b+8>>2];c+=L[b+12>>2]/1E3}else c=Date.now();a=A(a);try{b=c;var d=V(a,{Ya:!0}).node;d.Na.Ta(d,{timestamp:Math.max(b,c)});return 0}catch(f){a=f;if(!(a instanceof O)){a+=" : ";a:{d=Error();if(!d.stack){try{throw Error();}catch(g){d=g}if(!d.stack){d="(no stack trace available)";break a}}d=d.stack.toString()}e.extraStackTrace&&(d+="\n"+e.extraStackTrace());d=ob(d);throw a+d;}Bb(a.Pa);return-1}}}; 179 | (function(){function a(f){e.asm=f.exports;Ja=e.asm.M;eb--;e.monitorRunDependencies&&e.monitorRunDependencies(eb);0==eb&&(null!==fb&&(clearInterval(fb),fb=null),gb&&(f=gb,gb=null,f()))}function b(f){a(f.instance)}function c(f){return mb().then(function(g){return WebAssembly.instantiate(g,d)}).then(f,function(g){J("failed to asynchronously prepare wasm: "+g);K(g)})}var d={a:id};eb++;e.monitorRunDependencies&&e.monitorRunDependencies(eb);if(e.instantiateWasm)try{return e.instantiateWasm(d,a)}catch(f){return J("Module.instantiateWasm callback failed with error: "+ 180 | f),!1}(function(){if(Ka||"function"!==typeof WebAssembly.instantiateStreaming||jb()||hb("file://")||"function"!==typeof fetch)return c(b);fetch(ib,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(b,function(g){J("wasm streaming compile failed: "+g);J("falling back to ArrayBuffer instantiation");return c(b)})})})();return{}})(); 181 | var fd=e.___wasm_call_ctors=function(){return(fd=e.___wasm_call_ctors=e.asm.N).apply(null,arguments)},hd=e._memset=function(){return(hd=e._memset=e.asm.O).apply(null,arguments)};e._sqlite3_free=function(){return(e._sqlite3_free=e.asm.P).apply(null,arguments)};var Cb=e.___errno_location=function(){return(Cb=e.___errno_location=e.asm.Q).apply(null,arguments)};e._sqlite3_finalize=function(){return(e._sqlite3_finalize=e.asm.R).apply(null,arguments)}; 182 | e._sqlite3_reset=function(){return(e._sqlite3_reset=e.asm.S).apply(null,arguments)};e._sqlite3_clear_bindings=function(){return(e._sqlite3_clear_bindings=e.asm.T).apply(null,arguments)};e._sqlite3_value_blob=function(){return(e._sqlite3_value_blob=e.asm.U).apply(null,arguments)};e._sqlite3_value_text=function(){return(e._sqlite3_value_text=e.asm.V).apply(null,arguments)};e._sqlite3_value_bytes=function(){return(e._sqlite3_value_bytes=e.asm.W).apply(null,arguments)}; 183 | e._sqlite3_value_double=function(){return(e._sqlite3_value_double=e.asm.X).apply(null,arguments)};e._sqlite3_value_int=function(){return(e._sqlite3_value_int=e.asm.Y).apply(null,arguments)};e._sqlite3_value_type=function(){return(e._sqlite3_value_type=e.asm.Z).apply(null,arguments)};e._sqlite3_result_blob=function(){return(e._sqlite3_result_blob=e.asm._).apply(null,arguments)};e._sqlite3_result_double=function(){return(e._sqlite3_result_double=e.asm.$).apply(null,arguments)}; 184 | e._sqlite3_result_error=function(){return(e._sqlite3_result_error=e.asm.aa).apply(null,arguments)};e._sqlite3_result_int=function(){return(e._sqlite3_result_int=e.asm.ba).apply(null,arguments)};e._sqlite3_result_int64=function(){return(e._sqlite3_result_int64=e.asm.ca).apply(null,arguments)};e._sqlite3_result_null=function(){return(e._sqlite3_result_null=e.asm.da).apply(null,arguments)};e._sqlite3_result_text=function(){return(e._sqlite3_result_text=e.asm.ea).apply(null,arguments)}; 185 | e._sqlite3_step=function(){return(e._sqlite3_step=e.asm.fa).apply(null,arguments)};e._sqlite3_column_count=function(){return(e._sqlite3_column_count=e.asm.ga).apply(null,arguments)};e._sqlite3_data_count=function(){return(e._sqlite3_data_count=e.asm.ha).apply(null,arguments)};e._sqlite3_column_blob=function(){return(e._sqlite3_column_blob=e.asm.ia).apply(null,arguments)};e._sqlite3_column_bytes=function(){return(e._sqlite3_column_bytes=e.asm.ja).apply(null,arguments)}; 186 | e._sqlite3_column_double=function(){return(e._sqlite3_column_double=e.asm.ka).apply(null,arguments)};e._sqlite3_column_text=function(){return(e._sqlite3_column_text=e.asm.la).apply(null,arguments)};e._sqlite3_column_type=function(){return(e._sqlite3_column_type=e.asm.ma).apply(null,arguments)};e._sqlite3_column_name=function(){return(e._sqlite3_column_name=e.asm.na).apply(null,arguments)};e._sqlite3_bind_blob=function(){return(e._sqlite3_bind_blob=e.asm.oa).apply(null,arguments)}; 187 | e._sqlite3_bind_double=function(){return(e._sqlite3_bind_double=e.asm.pa).apply(null,arguments)};e._sqlite3_bind_int=function(){return(e._sqlite3_bind_int=e.asm.qa).apply(null,arguments)};e._sqlite3_bind_text=function(){return(e._sqlite3_bind_text=e.asm.ra).apply(null,arguments)};e._sqlite3_bind_parameter_index=function(){return(e._sqlite3_bind_parameter_index=e.asm.sa).apply(null,arguments)};e._sqlite3_sql=function(){return(e._sqlite3_sql=e.asm.ta).apply(null,arguments)}; 188 | e._sqlite3_normalized_sql=function(){return(e._sqlite3_normalized_sql=e.asm.ua).apply(null,arguments)};e._sqlite3_errmsg=function(){return(e._sqlite3_errmsg=e.asm.va).apply(null,arguments)};e._sqlite3_exec=function(){return(e._sqlite3_exec=e.asm.wa).apply(null,arguments)};e._sqlite3_prepare_v2=function(){return(e._sqlite3_prepare_v2=e.asm.xa).apply(null,arguments)};e._sqlite3_changes=function(){return(e._sqlite3_changes=e.asm.ya).apply(null,arguments)}; 189 | e._sqlite3_close_v2=function(){return(e._sqlite3_close_v2=e.asm.za).apply(null,arguments)};e._sqlite3_create_function_v2=function(){return(e._sqlite3_create_function_v2=e.asm.Aa).apply(null,arguments)};e._sqlite3_open=function(){return(e._sqlite3_open=e.asm.Ba).apply(null,arguments)};var ba=e._malloc=function(){return(ba=e._malloc=e.asm.Ca).apply(null,arguments)},na=e._free=function(){return(na=e._free=e.asm.Da).apply(null,arguments)}; 190 | e._RegisterExtensionFunctions=function(){return(e._RegisterExtensionFunctions=e.asm.Ea).apply(null,arguments)}; 191 | var xb=e.__get_tzname=function(){return(xb=e.__get_tzname=e.asm.Fa).apply(null,arguments)},vb=e.__get_daylight=function(){return(vb=e.__get_daylight=e.asm.Ga).apply(null,arguments)},ub=e.__get_timezone=function(){return(ub=e.__get_timezone=e.asm.Ha).apply(null,arguments)},oa=e.stackSave=function(){return(oa=e.stackSave=e.asm.Ia).apply(null,arguments)},qa=e.stackRestore=function(){return(qa=e.stackRestore=e.asm.Ja).apply(null,arguments)},y=e.stackAlloc=function(){return(y=e.stackAlloc=e.asm.Ka).apply(null, 192 | arguments)},gd=e._memalign=function(){return(gd=e._memalign=e.asm.La).apply(null,arguments)};e.cwrap=function(a,b,c,d){c=c||[];var f=c.every(function(g){return"number"===g});return"string"!==b&&f&&!d?Qa(a):function(){return Ra(a,b,c,arguments)}};e.UTF8ToString=A;e.stackSave=oa;e.stackRestore=qa;e.stackAlloc=y;var jd;gb=function kd(){jd||ld();jd||(gb=kd)}; 193 | function ld(){function a(){if(!jd&&(jd=!0,e.calledRun=!0,!Pa)){e.noFSInit||Uc||(Uc=!0,Tc(),e.stdin=e.stdin,e.stdout=e.stdout,e.stderr=e.stderr,e.stdin?Vc("stdin",e.stdin):ic("/dev/tty","/dev/stdin"),e.stdout?Vc("stdout",null,e.stdout):ic("/dev/tty","/dev/stdout"),e.stderr?Vc("stderr",null,e.stderr):ic("/dev/tty1","/dev/stderr"),u("/dev/stdin","r"),u("/dev/stdout","w"),u("/dev/stderr","w"));nb(ab);Sb=!1;nb(bb);if(e.onRuntimeInitialized)e.onRuntimeInitialized();if(e.postRun)for("function"==typeof e.postRun&& 194 | (e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();cb.unshift(b)}nb(cb)}}if(!(0Glassbench ${gb_conf.gb_version}`, { 16 | href: "https://github.com/Canop/glassbench", 17 | target: "_blank", 18 | }), 19 | ), 20 | $("<#selectors"), 21 | $("<#view", 22 | $("<.tabs"), 23 | $("<.pages"), 24 | ) 25 | ) 26 | function unselect() { 27 | $("#view .tabs .tab, #view .pages .page", e => { 28 | e.classList.remove("selected") 29 | }) 30 | } 31 | ;["Table", "Graph"].forEach(name => { 32 | unselect() 33 | let page = $("<.page.selected", { id: name }) 34 | let tab = $(" { 37 | unselect() 38 | tab.classList.add("selected") 39 | page.classList.add("selected") 40 | } 41 | }) 42 | $("#view .tabs", tab) 43 | $("#view .pages", page) 44 | }) 45 | $("#Table", 46 | $("<.table-wrapper", 47 | $("dataset"), 50 | $("bench id"), 51 | $("commit id"), 52 | $("date"), 53 | $("task name"), 54 | $("mean dur."), 55 | $("mean (ns)"), 56 | $("tag"), 57 | )), 58 | $(" ({ 114 | bench_id: row[0], 115 | commit_id: row[3], 116 | date: row[1] * 1000, 117 | duration_ns: row[5], 118 | tag: row[2], 119 | duration_str: fmt_nanos(row[5]) 120 | })) 121 | } 122 | 123 | function update_table(view_data) { 124 | let tbody = $("#tbody") 125 | while (tbody.firstChild) tbody.removeChild(tbody.lastChild) 126 | for (let g of view_data) { 127 | for (let row of g.rows) { 128 | $(tbody, $(`${g.group_id + 1}`), // counting from 1 130 | $("row.date)) max_date = row.date 156 | items.push({ 157 | x: row.date, 158 | y: row.duration_ns, 159 | group: g.group_id, 160 | label: { content: row.duration_str } 161 | }) 162 | } 163 | } 164 | var options = { 165 | start: min_date - (max_date-min_date)/10, 166 | end: max_date + (max_date-min_date)/10, 167 | shaded: true, 168 | } 169 | window.graph = new vis.Graph2d($("#vis"), items, groups, options) 170 | graph.on('click', function (properties) { 171 | console.log("click", properties) 172 | }) 173 | } 174 | 175 | function make_selector(bench_name, task_name) { 176 | let bench_name_select = $(" $(`