Skip to content

Commit

Permalink
Merge branch 'master' of github.com:lana-k/sqliteviz
Browse files Browse the repository at this point in the history
  • Loading branch information
lana-k committed May 17, 2023
2 parents 4e13a16 + 9c0103f commit db3dbdf
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 285 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
jobs:
test:
name: Run tests
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js
Expand Down
24 changes: 24 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# An easy way to run tests locally without Nodejs installed:
#
# docker build -t sqliteviz/test -f Dockerfile.test .
#

FROM node:12

RUN set -ex; \
apt update; \
apt install -y chromium firefox-esr; \
npm install -g npm@7

WORKDIR /tmp/build

COPY package.json package-lock.json ./
COPY lib lib
RUN npm install

COPY . .

RUN set -ex; \
sed -i 's/browsers: \[.*\],/browsers: ['"'FirefoxHeadlessTouch'"'],/' karma.conf.js

RUN npm run lint -- --no-fix && npm run test
2 changes: 1 addition & 1 deletion lib/sql-js/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM emscripten/emsdk:2.0.24
FROM emscripten/emsdk:3.0.1

WORKDIR /tmp/build

Expand Down
4 changes: 4 additions & 0 deletions lib/sql-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ SQLite [miscellaneous extensions][3] included:
SQLite 3rd party extensions included:

1. [pivot_vtab][5] -- a pivot virtual table
2. `pearson` correlation coefficient function extension from [sqlean][21]
(which is part of [squib][20])

To ease the step to have working clone locally, the build is committed into
the repository.
Expand Down Expand Up @@ -99,3 +101,5 @@ described in [this message from SQLite Forum][12]:
[17]: https://sqlite.org/contrib/
[18]: https://sqlite.org/contrib//download/extension-functions.c?get=25
[19]: https://github.com/lana-k/sqliteviz/blob/master/tests/lib/database/sqliteExtensions.spec.js
[20]: https://github.com/mrwilson/squib/blob/master/pearson.c
[21]: https://github.com/nalgeon/sqlean/blob/incubator/src/pearson.c
35 changes: 23 additions & 12 deletions lib/sql-js/benchmark/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
# SQLite WebAssembly build micro-benchmark

This directory contains a micro-benchmark for evaluating SQLite
WebAssembly builds performance on typical SQL queries, run from
`make.sh` script. It can also serve as a smoke test.

The benchmark operates on a set of SQLite WebAssembly builds expected
in `lib/build-$NAME` directories each containing `sql-wasm.js` and
`sql-wasm.wasm`. Then it creates a Docker image for each, and runs
the benchmark in Firefox and Chromium using Karma in the container.

After successful run, the benchmark result of each build is contained
in `build-$NAME-result.json`. The JSON result files can be analysed
using `result-analysis.ipynb` Jupyter notebook.
This directory contains a micro-benchmark for evaluating SQLite WebAssembly
builds performance on read and write SQL queries, run from `make.sh` script. If
the script has permission to `nice` processes and [Procpath][1] is installed,
e.g. it is run with `sudo -E env PATH=$PATH ./make.sh`, it'll `renice` all
processes running inside the benchmark containers. It can also serve as a smoke
test (e.g. for memory leaks).

The benchmark operates on a set of SQLite WebAssembly builds expected in
`lib/build-$NAME` directories each containing `sql-wasm.js` and
`sql-wasm.wasm`. Then it creates a Docker image for each, and runs the
benchmark in Firefox and Chromium using Karma in the container.

After successful run, the benchmark produces the following per each build:

- `build-$NAME-result.json`
- `build-$NAME.sqlite` (if Procpath is installed)
- `build-$NAME.svg` (if Procpath is installed)

These files can be analysed using `result-analysis.ipynb` Jupyter notebook.
The SVG is a chart with CPU and RSS usage of each test container (i.e. Chromium
run, then Firefox run per container).

[1]: https://pypi.org/project/Procpath/
49 changes: 26 additions & 23 deletions lib/sql-js/benchmark/make.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/bash -e

cleanup () {
rm -rf lib/dist $flag_file
rm -rf lib/dist "$renice_flag_file"
docker rm -f sqljs-benchmark-run 2> /dev/null || true
}
trap cleanup EXIT

Expand All @@ -11,34 +12,36 @@ if [ ! -f sample.csv ]; then
| gunzip -c > sample.csv
fi

PLAYBOOK=procpath/karma_docker.procpath

# for renice to work run like "sudo -E env PATH=$PATH ./make.sh"
test_ni=$(nice -n -1 nice)
if [ $test_ni == -1 ]; then
flag_file=$(mktemp)
test_ni=$(nice -n -5 nice)
if [ $test_ni == -5 ]; then
renice_flag_file=$(mktemp)
fi
(
while [ -f $flag_file ]; do
root_pid=$(
docker ps -f status=running -f name='^sqljs-benchmark-' -q \
| xargs -r -I{} -- docker inspect -f '{{.State.Pid}}' {}
)
if [ ! -z $root_pid ]; then
procpath query -d $'\n' "$..children[?(@.stat.pid == $root_pid)]..pid" \
| xargs -I{} -- renice -n -1 -p {} > /dev/null
fi
sleep 1
done &
)
{
while [ -f $renice_flag_file ]; do
procpath --logging-level ERROR play -f $PLAYBOOK renice:watch
done
} &

shopt -s nullglob
for d in lib/build-* ; do
rm -rf lib/dist
cp -r $d lib/dist
sample_name=$(basename $d)

docker build -t sqliteviz/sqljs-benchmark .
docker rm sqljs-benchmark-run 2> /dev/null || true
docker run -d -it --cpus 2 --name sqljs-benchmark-run sqliteviz/sqljs-benchmark
{
rm -f ${sample_name}.sqlite
procpath play -f $PLAYBOOK -o database_file=${sample_name}.sqlite track:record
procpath play -f $PLAYBOOK -o database_file=${sample_name}.sqlite \
-o plot_file=${sample_name}.svg track:plot
} &

name=$(basename $d)
docker build -t sqliteviz/sqljs-benchmark:$name .
docker rm sqljs-benchmark-$name 2> /dev/null || true
docker run -it --cpus 2 --name sqljs-benchmark-$name sqliteviz/sqljs-benchmark:$name
docker cp sqljs-benchmark-$name:/tmp/build/suite-result.json ${name}-result.json
docker rm sqljs-benchmark-$name
docker attach sqljs-benchmark-run
docker cp sqljs-benchmark-run:/tmp/build/suite-result.json ${sample_name}-result.json
docker rm sqljs-benchmark-run
done
28 changes: 28 additions & 0 deletions lib/sql-js/benchmark/procpath/karma_docker.procpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This command may run when "sqljs-benchmark-run" does not yet exist or run
[renice:watch]
interval: 2
repeat: 30
environment:
ROOT_PID=docker inspect -f "{{.State.Pid}}" sqljs-benchmark-run 2> /dev/null || true
query:
PIDS=$..children[?(@.stat.pid in [$ROOT_PID])]..pid
command:
echo $PIDS | tr , '\n' | xargs --no-run-if-empty -I{} -- renice -n -5 -p {}

# Expected input arguments: database_file
[track:record]
interval: 1
stop_without_result: 1
environment:
ROOT_PID=docker inspect -f "{{.State.Pid}}" sqljs-benchmark-run
query:
$..children[?(@.stat.pid == $ROOT_PID)]
pid_list: $ROOT_PID

# Expected input arguments: database_file, plot_file
[track:plot]
moving_average_window: 5
title: Chromium vs Firefox (№1 RSS, №2 CPU)
custom_query_file:
procpath/top2_rss.sql
procpath/top2_cpu.sql
29 changes: 29 additions & 0 deletions lib/sql-js/benchmark/procpath/top2_cpu.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
WITH diff_all AS (
SELECT
record_id,
ts,
stat_pid,
stat_utime + stat_stime - LAG(stat_utime + stat_stime) OVER (
PARTITION BY stat_pid
ORDER BY record_id
) tick_diff,
ts - LAG(ts) OVER (
PARTITION BY stat_pid
ORDER BY record_id
) ts_diff
FROM record
), diff AS (
SELECT * FROM diff_all WHERE tick_diff IS NOT NULL
), one_time_pid_condition AS (
SELECT stat_pid
FROM record
GROUP BY 1
ORDER BY SUM(stat_utime + stat_stime) DESC
LIMIT 2
)
SELECT
ts,
stat_pid pid,
100.0 * tick_diff / (SELECT value FROM meta WHERE key = 'clock_ticks') / ts_diff value
FROM diff
JOIN one_time_pid_condition USING(stat_pid)
13 changes: 13 additions & 0 deletions lib/sql-js/benchmark/procpath/top2_rss.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
WITH one_time_pid_condition AS (
SELECT stat_pid
FROM record
GROUP BY 1
ORDER BY SUM(stat_rss) DESC
LIMIT 2
)
SELECT
ts,
stat_pid pid,
stat_rss / 1024.0 / 1024 * (SELECT value FROM meta WHERE key = 'page_size') value
FROM record
JOIN one_time_pid_condition USING(stat_pid)
398 changes: 198 additions & 200 deletions lib/sql-js/benchmark/result-analysis.ipynb

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions lib/sql-js/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import subprocess
from pathlib import Path


# See the setting descriptions on these pages:
# - https://emscripten.org/docs/optimizing/Optimizing-Code.html
# - https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
cflags = (
'-O2',
# SQLite configuration
'-DSQLITE_DEFAULT_CACHE_SIZE=-65536', # 64 MiB
'-DSQLITE_DEFAULT_MEMSTATUS=0',
'-DSQLITE_DEFAULT_SYNCHRONOUS=0',
Expand All @@ -13,26 +15,26 @@
'-DSQLITE_ENABLE_FTS3',
'-DSQLITE_ENABLE_FTS3_PARENTHESIS',
'-DSQLITE_ENABLE_FTS5',
'-DSQLITE_ENABLE_JSON1',
'-DSQLITE_ENABLE_NORMALIZE',
'-DSQLITE_EXTRA_INIT=extra_init',
'-DSQLITE_OMIT_DEPRECATED',
'-DSQLITE_OMIT_LOAD_EXTENSION',
'-DSQLITE_OMIT_SHARED_CACHE',
'-DSQLITE_THREADSAFE=0',
# Compile-time optimisation
'-Os', # reduces the code size about in half comparing to -O2
'-flto',
)
emflags = (
# Base
'--memory-init-file', '0',
'-s', 'RESERVED_FUNCTION_POINTERS=64',
'-s', 'ALLOW_TABLE_GROWTH=1',
'-s', 'SINGLE_FILE=0',
# WASM
'-s', 'WASM=1',
'-s', 'ALLOW_MEMORY_GROWTH=1',
# Optimisation
'-s', 'INLINING_LIMIT=50',
'-O3',
'-s', 'ENVIRONMENT=web,worker',
# Link-time optimisation
'-Os',
'-flto',
# sql.js
'-s', 'EXPORTED_FUNCTIONS=@src/sqljs/exported_functions.json',
Expand All @@ -50,22 +52,22 @@ def build(src: Path, dst: Path):
'emcc',
*cflags,
'-c', src / 'sqlite3.c',
'-o', out / 'sqlite3.bc',
'-o', out / 'sqlite3.o',
])
logging.info('Building LLVM bitcode for extension-functions.c')
subprocess.check_call([
'emcc',
*cflags,
'-c', src / 'extension-functions.c',
'-o', out / 'extension-functions.bc',
'-o', out / 'extension-functions.o',
])

logging.info('Building WASM from bitcode')
subprocess.check_call([
'emcc',
*emflags,
out / 'sqlite3.bc',
out / 'extension-functions.bc',
out / 'sqlite3.o',
out / 'extension-functions.o',
'-o', out / 'sql-wasm.js',
])

Expand Down
7 changes: 4 additions & 3 deletions lib/sql-js/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from urllib import request


amalgamation_url = 'https://sqlite.org/2022/sqlite-amalgamation-3390000.zip'
amalgamation_url = 'https://sqlite.org/2023/sqlite-amalgamation-3410000.zip'

# Extension-functions
# ===================
Expand All @@ -28,10 +28,11 @@
('https://sqlite.org/src/raw/09f967dc?at=decimal.c', 'sqlite3_decimal_init'),
# Third-party extension
# =====================
('https://github.com/jakethaw/pivot_vtab/raw/08ab0797/pivot_vtab.c', 'sqlite3_pivotvtab_init'),
('https://github.com/jakethaw/pivot_vtab/raw/9323ef93/pivot_vtab.c', 'sqlite3_pivotvtab_init'),
('https://github.com/nalgeon/sqlean/raw/95e8d21a/src/pearson.c', 'sqlite3_pearson_init'),
)

sqljs_url = 'https://github.com/sql-js/sql.js/archive/refs/tags/v1.5.0.zip'
sqljs_url = 'https://github.com/sql-js/sql.js/archive/refs/tags/v1.7.0.zip'


def _generate_extra_init_c_function(init_function_names):
Expand Down
2 changes: 1 addition & 1 deletion lib/sql-js/dist/sql-wasm.js

Large diffs are not rendered by default.

Binary file modified lib/sql-js/dist/sql-wasm.wasm
Binary file not shown.

0 comments on commit db3dbdf

Please sign in to comment.