-module(libsql_benchmark).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libsql_benchmark.gleam").
-export([main/0]).
-file("src/libsql_benchmark.gleam", 42).
-spec print_result(binary(), integer(), integer()) -> nil.
print_result(Label, Iterations, Elapsed) ->
Qps = case Elapsed of
0 ->
0;
_ ->
case Elapsed of
0 -> 0;
Gleam@denominator -> (Iterations * 1000) div Gleam@denominator
end
end,
gleam_stdlib:println(
<<<<<<<<<<<<<<Label/binary, ": "/utf8>>/binary,
(erlang:integer_to_binary(Iterations))/binary>>/binary,
" in "/utf8>>/binary,
(erlang:integer_to_binary(Elapsed))/binary>>/binary,
"ms ("/utf8>>/binary,
(erlang:integer_to_binary(Qps))/binary>>/binary,
" qps)"/utf8>>
).
-file("src/libsql_benchmark.gleam", 381).
-spec now_ms() -> integer().
now_ms() ->
Time = erlang:monotonic_time(),
erlang:convert_time_unit(Time, 1000000000, 1000).
-file("src/libsql_benchmark.gleam", 365).
-spec run_times(integer(), fun((integer()) -> any())) -> nil.
run_times(N, F) ->
case N of
0 ->
nil;
_ ->
_ = F(N),
run_times(N - 1, F)
end.
-file("src/libsql_benchmark.gleam", 353).
-spec benchmark_synced_push(libsql:connection()) -> nil.
benchmark_synced_push(Conn) ->
Iterations = 3,
Start = now_ms(),
_ = run_times(Iterations, fun(_) -> libsql:sync(Conn) end),
Elapsed = now_ms() - Start,
print_result(<<"synced push"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 336).
-spec benchmark_synced_local_query(libsql:connection()) -> nil.
benchmark_synced_local_query(Conn) ->
Iterations = 500,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) ->
libsql:'query'(
<<"select name from bench_synced where id = ?"/utf8>>,
Conn,
[libsql:int(500)],
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun gleam@dynamic@decode:success/1
)
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"synced local query"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 321).
-spec benchmark_synced_local_insert(libsql:connection()) -> nil.
benchmark_synced_local_insert(Conn) ->
case libsql:exec(<<"drop table if exists bench_synced"/utf8>>, Conn) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_synced_local_insert"/utf8>>,
line => 322,
value => _assert_fail,
start => 8586,
'end' => 8659,
pattern_start => 8597,
pattern_end => 8602})
end,
case libsql:exec(
<<"create table bench_synced (id integer primary key, name text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_synced_local_insert"/utf8>>,
line => 323,
value => _assert_fail@1,
start => 8662,
'end' => 8763,
pattern_start => 8673,
pattern_end => 8678})
end,
Iterations = 1000,
Start = now_ms(),
_ = run_times(
Iterations,
fun(I) ->
libsql:exec(
<<<<"insert into bench_synced (name) values ('name_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"')"/utf8>>,
Conn
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"synced local insert"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 293).
-spec benchmark_synced_operations() -> {ok, nil} | {error, libsql:error()}.
benchmark_synced_operations() ->
gleam_stdlib:println(<<"--- Synced Database Benchmarks ---"/utf8>>),
Url = <<"libsql://test-rednithin.aws-ap-south-1.turso.io"/utf8>>,
Token = <<"DUMMY_TOKEN"/utf8>>,
Db_path = <<"/tmp/libsql_benchmark_synced.db"/utf8>>,
case libsql:open_synced_database(Db_path, Url, Token) of
{ok, Conn} ->
_ = libsql:sync(Conn),
_ = benchmark_synced_local_insert(Conn),
_ = benchmark_synced_local_query(Conn),
_ = benchmark_synced_push(Conn),
_ = libsql:exec(<<"drop table if exists bench_synced"/utf8>>, Conn),
_ = libsql:close(Conn),
{ok, nil};
{error, Err} ->
gleam_stdlib:println(
<<"Synced benchmark skipped: "/utf8,
(erlang:element(3, Err))/binary>>
),
{error, Err}
end.
-file("src/libsql_benchmark.gleam", 274).
-spec benchmark_replica_local_query(libsql:connection()) -> nil.
benchmark_replica_local_query(Conn) ->
_ = libsql:sync(Conn),
Iterations = 500,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) ->
libsql:'query'(
<<"select 1"/utf8>>,
Conn,
[],
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun gleam@dynamic@decode:success/1
)
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"replica local query"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 262).
-spec benchmark_replica_sync(libsql:connection()) -> nil.
benchmark_replica_sync(Conn) ->
Iterations = 1,
Start = now_ms(),
_ = run_times(Iterations, fun(_) -> libsql:sync(Conn) end),
Elapsed = now_ms() - Start,
print_result(<<"replica sync"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 241).
-spec benchmark_replica_operations() -> {ok, nil} | {error, libsql:error()}.
benchmark_replica_operations() ->
gleam_stdlib:println(<<"--- Replica Database Benchmarks ---"/utf8>>),
Url = <<"libsql://test-rednithin.aws-ap-south-1.turso.io"/utf8>>,
Token = <<"DUMMY_TOKEN"/utf8>>,
Db_path = <<"/tmp/libsql_benchmark_replica.db"/utf8>>,
case libsql:open_replica(Db_path, Url, Token) of
{ok, Conn} ->
_ = benchmark_replica_sync(Conn),
_ = benchmark_replica_local_query(Conn),
_ = libsql:close(Conn),
{ok, nil};
{error, Err} ->
gleam_stdlib:println(
<<"Replica benchmark skipped: "/utf8,
(erlang:element(3, Err))/binary>>
),
{error, Err}
end.
-file("src/libsql_benchmark.gleam", 216).
-spec benchmark_remote_select(libsql:connection()) -> {ok, nil} |
{error, libsql:error()}.
benchmark_remote_select(Conn) ->
case libsql:exec(<<"drop table if exists bench_remote"/utf8>>, Conn) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_remote_select"/utf8>>,
line => 217,
value => _assert_fail,
start => 5872,
'end' => 5945,
pattern_start => 5883,
pattern_end => 5888})
end,
case libsql:exec(
<<"create table bench_remote (id integer primary key, value text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_remote_select"/utf8>>,
line => 218,
value => _assert_fail@1,
start => 5948,
'end' => 6050,
pattern_start => 5959,
pattern_end => 5964})
end,
_ = run_times(
10,
fun(I) ->
libsql:exec(
<<<<"insert into bench_remote (value) values ('row_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"')"/utf8>>,
Conn
)
end
),
Iterations = 20,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) ->
libsql:'query'(
<<"select value from bench_remote where id = ?"/utf8>>,
Conn,
[libsql:int(5)],
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun gleam@dynamic@decode:success/1
)
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"remote select"/utf8>>, Iterations, Elapsed),
_assert_subject = libsql:exec(<<"drop table bench_remote"/utf8>>, Conn),
case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_remote_select"/utf8>>,
line => 238,
value => _assert_fail@2,
start => 6536,
'end' => 6599,
pattern_start => 6547,
pattern_end => 6552})
end.
-file("src/libsql_benchmark.gleam", 204).
-spec benchmark_remote_exec(libsql:connection()) -> nil.
benchmark_remote_exec(Conn) ->
Iterations = 10,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) -> libsql:exec(<<"select 1"/utf8>>, Conn) end
),
Elapsed = now_ms() - Start,
print_result(<<"remote exec('select 1')"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 180).
-spec benchmark_remote_operations() -> {ok, nil} | {error, libsql:error()}.
benchmark_remote_operations() ->
gleam_stdlib:println(<<"--- Remote Database Benchmarks ---"/utf8>>),
Url = <<"libsql://test-rednithin.aws-ap-south-1.turso.io"/utf8>>,
Token = <<"DUMMY_TOKEN"/utf8>>,
case libsql:open_remote(Url, Token) of
{ok, Conn} ->
_ = libsql:exec(<<"drop table if exists bench_remote"/utf8>>, Conn),
_ = libsql:exec(<<"drop table if exists bench_synced"/utf8>>, Conn),
_ = benchmark_remote_exec(Conn),
_ = benchmark_remote_select(Conn),
_ = libsql:close(Conn),
{ok, nil};
{error, Err} ->
gleam_stdlib:println(
<<"Remote benchmark skipped: "/utf8,
(erlang:element(3, Err))/binary>>
),
{error, Err}
end.
-file("src/libsql_benchmark.gleam", 161).
-spec benchmark_transactions(libsql:connection()) -> nil.
benchmark_transactions(Conn) ->
case libsql:exec(
<<"create table bench_tx (id integer primary key, name text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_transactions"/utf8>>,
line => 162,
value => _assert_fail,
start => 4175,
'end' => 4272,
pattern_start => 4186,
pattern_end => 4191})
end,
Iterations = 100,
Start = now_ms(),
_ = run_times(
Iterations,
fun(I) ->
libsql:transaction(
Conn,
fun() ->
gleam@result:'try'(
libsql:exec(
<<<<"insert into bench_tx (name) values ('tx_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"_1')"/utf8>>,
Conn
),
fun(_) ->
gleam@result:'try'(
libsql:exec(
<<<<"insert into bench_tx (name) values ('tx_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"_2')"/utf8>>,
Conn
),
fun(_) ->
gleam@result:'try'(
libsql:exec(
<<<<"insert into bench_tx (name) values ('tx_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"_3')"/utf8>>,
Conn
),
fun(_) -> {ok, nil} end
)
end
)
end
)
end
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"transaction (3 inserts)"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 143).
-spec benchmark_prepared_statements(libsql:connection()) -> nil.
benchmark_prepared_statements(Conn) ->
case libsql:exec(
<<"create table bench_prepared (id integer primary key, name text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_prepared_statements"/utf8>>,
line => 144,
value => _assert_fail,
start => 3647,
'end' => 3750,
pattern_start => 3658,
pattern_end => 3663})
end,
Stmt@1 = case libsql:prepare(
<<"insert into bench_prepared (name) values (?)"/utf8>>,
Conn
) of
{ok, Stmt} -> Stmt;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_prepared_statements"/utf8>>,
line => 146,
value => _assert_fail@1,
start => 3754,
'end' => 3844,
pattern_start => 3765,
pattern_end => 3773})
end,
Iterations = 5000,
Start = now_ms(),
_ = run_times(
Iterations,
fun(I) ->
libsql:exec_prepared(
Stmt@1,
[libsql:text(
<<"name_"/utf8, (erlang:integer_to_binary(I))/binary>>
)]
)
end
),
_ = libsql:finalize(Stmt@1),
Elapsed = now_ms() - Start,
print_result(<<"prepared insert"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 50).
-spec print_result_rows(binary(), integer(), integer()) -> nil.
print_result_rows(Label, Rows, Elapsed) ->
Qps = case Elapsed of
0 ->
0;
_ ->
case Elapsed of
0 -> 0;
Gleam@denominator -> (Rows * 1000) div Gleam@denominator
end
end,
gleam_stdlib:println(
<<<<<<<<<<<<<<Label/binary, ": "/utf8>>/binary,
(erlang:integer_to_binary(Rows))/binary>>/binary,
" rows in "/utf8>>/binary,
(erlang:integer_to_binary(Elapsed))/binary>>/binary,
"ms ("/utf8>>/binary,
(erlang:integer_to_binary(Qps))/binary>>/binary,
" rows/sec)"/utf8>>
).
-file("src/libsql_benchmark.gleam", 133).
-spec generate_batches_loop(integer(), list(list(libsql:value()))) -> list(list(libsql:value())).
generate_batches_loop(N, Acc) ->
case N of
0 ->
Acc;
_ ->
Batch = [libsql:text(
<<"name_"/utf8, (erlang:integer_to_binary(N))/binary>>
),
libsql:float(erlang:float(N))],
generate_batches_loop(N - 1, [Batch | Acc])
end.
-file("src/libsql_benchmark.gleam", 129).
-spec generate_batches(integer()) -> list(list(libsql:value())).
generate_batches(Count) ->
generate_batches_loop(Count, []).
-file("src/libsql_benchmark.gleam", 109).
-spec benchmark_batch_insert(libsql:connection()) -> nil.
benchmark_batch_insert(Conn) ->
case libsql:exec(
<<"create table bench_batch (id integer primary key, name text, score real)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_batch_insert"/utf8>>,
line => 110,
value => _assert_fail,
start => 2727,
'end' => 2839,
pattern_start => 2738,
pattern_end => 2743})
end,
Batches = generate_batches(1000),
Iterations = 10,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) ->
libsql:exec_batch(
<<"insert into bench_batch (name, score) values (?, ?)"/utf8>>,
Conn,
Batches
)
end
),
Elapsed = now_ms() - Start,
Total_rows = Iterations * 1000,
print_result_rows(<<"batch insert"/utf8>>, Total_rows, Elapsed).
-file("src/libsql_benchmark.gleam", 85).
-spec benchmark_select(libsql:connection()) -> nil.
benchmark_select(Conn) ->
case libsql:exec(
<<"create table bench_select (id integer primary key, value text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_select"/utf8>>,
line => 86,
value => _assert_fail,
start => 2075,
'end' => 2177,
pattern_start => 2086,
pattern_end => 2091})
end,
_ = run_times(
1000,
fun(I) ->
Sql = <<<<"insert into bench_select (value) values ('row_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"')"/utf8>>,
libsql:exec(Sql, Conn)
end
),
Iterations = 500,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) ->
libsql:'query'(
<<"select value from bench_select where id = ?"/utf8>>,
Conn,
[libsql:int(500)],
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun gleam@dynamic@decode:success/1
)
)
end
),
Elapsed = now_ms() - Start,
print_result(<<"select with param"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 70).
-spec benchmark_insert(libsql:connection()) -> nil.
benchmark_insert(Conn) ->
case libsql:exec(
<<"create table bench_insert (id integer primary key, value text)"/utf8>>,
Conn
) of
{ok, _} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_insert"/utf8>>,
line => 71,
value => _assert_fail,
start => 1647,
'end' => 1749,
pattern_start => 1658,
pattern_end => 1663})
end,
Iterations = 5000,
Start = now_ms(),
_ = run_times(
Iterations,
fun(I) ->
Sql = <<<<"insert into bench_insert (value) values ('row_"/utf8,
(erlang:integer_to_binary(I))/binary>>/binary,
"')"/utf8>>,
libsql:exec(Sql, Conn)
end
),
Elapsed = now_ms() - Start,
print_result(<<"insert"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 58).
-spec benchmark_exec(libsql:connection()) -> nil.
benchmark_exec(Conn) ->
Iterations = 1000,
Start = now_ms(),
_ = run_times(
Iterations,
fun(_) -> libsql:exec(<<"select 1"/utf8>>, Conn) end
),
Elapsed = now_ms() - Start,
print_result(<<"exec('select 1')"/utf8>>, Iterations, Elapsed).
-file("src/libsql_benchmark.gleam", 27).
-spec benchmark_local_operations() -> {ok, nil} | {error, libsql:error()}.
benchmark_local_operations() ->
gleam_stdlib:println(<<"--- Local Database Benchmarks ---"/utf8>>),
Conn@1 = case libsql:open(<<":memory:"/utf8>>) of
{ok, Conn} -> Conn;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_local_operations"/utf8>>,
line => 30,
value => _assert_fail,
start => 542,
'end' => 587,
pattern_start => 553,
pattern_end => 561})
end,
benchmark_exec(Conn@1),
benchmark_insert(Conn@1),
benchmark_select(Conn@1),
benchmark_batch_insert(Conn@1),
benchmark_prepared_statements(Conn@1),
benchmark_transactions(Conn@1),
_assert_subject = libsql:close(Conn@1),
case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"libsql_benchmark"/utf8>>,
function => <<"benchmark_local_operations"/utf8>>,
line => 39,
value => _assert_fail@1,
start => 765,
'end' => 802,
pattern_start => 776,
pattern_end => 781})
end.
-file("src/libsql_benchmark.gleam", 7).
-spec main() -> nil.
main() ->
gleam_stdlib:println(<<"=== LibSQL Benchmark ==="/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
_ = benchmark_local_operations(),
gleam_stdlib:println(<<""/utf8>>),
_ = benchmark_remote_operations(),
gleam_stdlib:println(<<""/utf8>>),
_ = benchmark_replica_operations(),
gleam_stdlib:println(<<""/utf8>>),
_ = benchmark_synced_operations(),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"=== Benchmark Complete ==="/utf8>>),
nil.