Current section

Files

Jump to
viva_tensor src viva_tensor@examples@backend.erl
Raw

src/viva_tensor@examples@backend.erl

-module(viva_tensor@examples@backend).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/viva_tensor/examples/backend.gleam").
-export([main/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/viva_tensor/examples/backend.gleam", 261).
?DOC(false).
-spec float_to_str(float()) -> binary().
float_to_str(F) ->
Rounded = begin
_pipe = erlang:round(F * 100.0),
erlang:float(_pipe)
end,
Result = Rounded / 100.0,
gleam_stdlib:float_to_string(Result).
-file("src/viva_tensor/examples/backend.gleam", 249).
?DOC(false).
-spec format_time(float()) -> binary().
format_time(Ms) ->
case Ms < 1.0 of
true ->
<<(float_to_str(Ms * 1000.0))/binary, " μs"/utf8>>;
false ->
case Ms < 1000.0 of
true ->
<<(float_to_str(Ms))/binary, " ms"/utf8>>;
false ->
<<(float_to_str(Ms / 1000.0))/binary, " s"/utf8>>
end
end.
-file("src/viva_tensor/examples/backend.gleam", 244).
?DOC(false).
-spec random_floats(integer()) -> list(float()).
random_floats(N) ->
_pipe = gleam@list:range(0, N - 1),
gleam@list:map(_pipe, fun(_) -> viva_tensor@core@ffi:random_uniform() end).
-file("src/viva_tensor/examples/backend.gleam", 276).
?DOC(false).
-spec repeat_string(binary(), integer()) -> binary().
repeat_string(S, N) ->
case N =< 0 of
true ->
<<""/utf8>>;
false ->
<<S/binary, (repeat_string(S, N - 1))/binary>>
end.
-file("src/viva_tensor/examples/backend.gleam", 267).
?DOC(false).
-spec pad_right(binary(), integer()) -> binary().
pad_right(S, Width) ->
Len = string:length(S),
Padding = Width - Len,
case Padding > 0 of
true ->
<<S/binary, (repeat_string(<<" "/utf8>>, Padding))/binary>>;
false ->
S
end.
-file("src/viva_tensor/examples/backend.gleam", 224).
?DOC(false).
-spec print_backend_row(binary(), float(), boolean()) -> nil.
print_backend_row(Name, Time, Ok) ->
Time_str = case Time > +0.0 of
true ->
format_time(Time);
false ->
<<"N/A"/utf8>>
end,
Result_str = case Ok of
true ->
<<"✓ OK"/utf8>>;
false ->
<<"✗ Error/N/A"/utf8>>
end,
gleam_stdlib:println(
<<<<<<<<<<<<" │ "/utf8, (pad_right(Name, 18))/binary>>/binary,
" │ "/utf8>>/binary,
(pad_right(Time_str, 12))/binary>>/binary,
" │ "/utf8>>/binary,
(pad_right(Result_str, 12))/binary>>/binary,
" │"/utf8>>
).
-file("src/viva_tensor/examples/backend.gleam", 208).
?DOC(false).
-spec benchmark_backend(
viva_tensor@backend@protocol:backend(),
list(float()),
list(float()),
integer(),
integer(),
integer()
) -> {float(), boolean()}.
benchmark_backend(B, A, B_data, M, N, K) ->
Start = viva_tensor@core@ffi:now_microseconds(),
Result = viva_tensor@backend@protocol:matmul(B, A, B_data, M, N, K),
End = viva_tensor@core@ffi:now_microseconds(),
Time = erlang:float(End - Start) / 1000.0,
{Time, gleam@result:is_ok(Result)}.
-file("src/viva_tensor/examples/backend.gleam", 22).
?DOC(false).
-spec main() -> nil.
main() ->
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(
<<"╔═══════════════════════════════════════════════════════════════════════════╗"/utf8>>
),
gleam_stdlib:println(
<<"║ viva_tensor - BACKEND PROTOCOL DEMO ║"/utf8>>
),
gleam_stdlib:println(
<<"║ Pluggable computation backends for BEAM ║"/utf8>>
),
gleam_stdlib:println(
<<"╚═══════════════════════════════════════════════════════════════════════════╝"/utf8>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"━━━ AVAILABLE BACKENDS ━━━"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
Backends = [pure, accelerate, zig, {distributed, []}],
gleam@list:each(
Backends,
fun(B) ->
Status = case viva_tensor@backend@protocol:is_available(B) of
true ->
<<"✓ Available"/utf8>>;
false ->
<<"✗ Not available"/utf8>>
end,
gleam_stdlib:println(
<<<<<<" "/utf8, (viva_tensor@backend@protocol:name(B))/binary>>/binary,
": "/utf8>>/binary,
Status/binary>>
),
case viva_tensor@backend@protocol:is_available(B) of
true ->
gleam_stdlib:println(
<<" └─ "/utf8,
(viva_tensor@backend@protocol:info(B))/binary>>
);
false ->
nil
end
end
),
gleam_stdlib:println(<<""/utf8>>),
Best = viva_tensor@backend@protocol:auto_select(),
gleam_stdlib:println(<<"━━━ AUTO-SELECTED BACKEND ━━━"/utf8>>),
gleam_stdlib:println(
<<" Best available: "/utf8,
(viva_tensor@backend@protocol:name(Best))/binary>>
),
gleam_stdlib:println(
<<" Info: "/utf8, (viva_tensor@backend@protocol:info(Best))/binary>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"━━━ MATRIX MULTIPLICATION DEMO ━━━"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
M = 64,
N = 64,
K = 64,
Size_str = <<<<<<<<<<<<(erlang:integer_to_binary(M))/binary, "x"/utf8>>/binary,
(erlang:integer_to_binary(K))/binary>>/binary,
" @ "/utf8>>/binary,
(erlang:integer_to_binary(K))/binary>>/binary,
"x"/utf8>>/binary,
(erlang:integer_to_binary(N))/binary>>,
gleam_stdlib:println(<<" Matrix size: "/utf8, Size_str/binary>>),
gleam_stdlib:println(<<""/utf8>>),
A = random_floats(M * K),
B@1 = random_floats(K * N),
gleam_stdlib:println(
<<" ┌────────────────────┬──────────────┬──────────────┐"/utf8>>
),
gleam_stdlib:println(
<<" │ Backend │ Time │ Result │"/utf8>>
),
gleam_stdlib:println(
<<" ├────────────────────┼──────────────┼──────────────┤"/utf8>>
),
{Pure_time, Pure_ok} = benchmark_backend(pure, A, B@1, M, N, K),
print_backend_row(<<"Pure Erlang"/utf8>>, Pure_time, Pure_ok),
case viva_tensor@backend@protocol:is_available(accelerate) of
true ->
{Acc_time, Acc_ok} = benchmark_backend(accelerate, A, B@1, M, N, K),
print_backend_row(<<"Apple Accelerate"/utf8>>, Acc_time, Acc_ok);
false ->
print_backend_row(<<"Apple Accelerate"/utf8>>, +0.0, false)
end,
case viva_tensor@backend@protocol:is_available(zig) of
true ->
{Zig_time, Zig_ok} = benchmark_backend(zig, A, B@1, M, N, K),
print_backend_row(<<"Zig SIMD"/utf8>>, Zig_time, Zig_ok);
false ->
print_backend_row(<<"Zig SIMD"/utf8>>, +0.0, false)
end,
gleam_stdlib:println(
<<" └────────────────────┴──────────────┴──────────────┘"/utf8>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"━━━ DOT PRODUCT DEMO ━━━"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
Vec_size = 10000,
Vec_a = random_floats(Vec_size),
Vec_b = random_floats(Vec_size),
gleam_stdlib:println(
<<" Vector size: "/utf8, (erlang:integer_to_binary(Vec_size))/binary>>
),
gleam_stdlib:println(<<""/utf8>>),
Dot_start = viva_tensor@core@ffi:now_microseconds(),
Dot_result = viva_tensor@backend@protocol:dot(Best, Vec_a, Vec_b),
Dot_end = viva_tensor@core@ffi:now_microseconds(),
Dot_time = erlang:float(Dot_end - Dot_start) / 1000.0,
case Dot_result of
{ok, Value} ->
gleam_stdlib:println(
<<<<<<<<<<<<" Backend: "/utf8,
(viva_tensor@backend@protocol:name(Best))/binary>>/binary,
" → "/utf8>>/binary,
(float_to_str(Value))/binary>>/binary,
" ("/utf8>>/binary,
(format_time(Dot_time))/binary>>/binary,
")"/utf8>>
);
{error, _} ->
gleam_stdlib:println(<<" Error computing dot product"/utf8>>)
end,
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"━━━ REDUCTION OPERATIONS ━━━"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
Data = random_floats(100000),
gleam_stdlib:println(<<" Data size: 100,000 elements"/utf8>>),
gleam_stdlib:println(<<""/utf8>>),
Sum_start = viva_tensor@core@ffi:now_microseconds(),
Sum_result = viva_tensor@backend@protocol:sum(Best, Data),
Sum_end = viva_tensor@core@ffi:now_microseconds(),
Sum_time = erlang:float(Sum_end - Sum_start) / 1000.0,
case Sum_result of
{ok, Value@1} ->
gleam_stdlib:println(
<<<<<<<<" Sum: "/utf8, (float_to_str(Value@1))/binary>>/binary,
" ("/utf8>>/binary,
(format_time(Sum_time))/binary>>/binary,
")"/utf8>>
);
{error, _} ->
gleam_stdlib:println(<<" Error computing sum"/utf8>>)
end,
Scale_start = viva_tensor@core@ffi:now_microseconds(),
Scale_result = viva_tensor@backend@protocol:scale(
Best,
gleam@list:take(Data, 1000),
2.0
),
Scale_end = viva_tensor@core@ffi:now_microseconds(),
Scale_time = erlang:float(Scale_end - Scale_start) / 1000.0,
case Scale_result of
{ok, _} ->
gleam_stdlib:println(
<<" Scale (×2.0, 1000 elements): "/utf8,
(format_time(Scale_time))/binary>>
);
{error, _} ->
gleam_stdlib:println(<<" Error computing scale"/utf8>>)
end,
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(
<<"═══════════════════════════════════════════════════════════════════════════"/utf8>>
),
gleam_stdlib:println(<<" DEMO COMPLETE!"/utf8>>),
gleam_stdlib:println(
<<"═══════════════════════════════════════════════════════════════════════════"/utf8>>
).