-module(viva_tensor@telemetry). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/viva_tensor/telemetry.gleam"). -export([default_config/0, init/0, init_with_json/1, init_with_config/1, op_counter/1, matmul_histogram/0, op_histogram/0, backward_histogram/0, backend_counter/1, memory_gauge/0, quant_counter/1, log_backend/2, log_backward/2, log_error/2, record_op/2, record_dot/3, record_backward/2, report_memory/0, prometheus/0, benchmark/2, benchmark_with_config/4, benchmark_all/1, benchmark_compare/2, benchmark_print/1, benchmark_print_comparison/1, benchmark_to_markdown/1, benchmark_table/1, log_op/2, log_matmul/5, log_quantize/2, record_matmul/5, record_quantize/2]). -export_type([config/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( " Observability for viva_tensor.\n" "\n" " Structured logging, metrics collection, and statistical benchmarking\n" " powered by viva_telemetry. Gives you full visibility into tensor\n" " operations, backend selection, memory usage, and gradient computation.\n" "\n" " ## Quick Start\n" "\n" " ```gleam\n" " import viva_tensor/telemetry\n" "\n" " // Console logging at Info level + all metrics\n" " telemetry.init()\n" "\n" " // With JSON file output for production\n" " telemetry.init_with_json(\"logs/viva_tensor.json\")\n" "\n" " // Full custom config\n" " telemetry.init_with_config(telemetry.Config(\n" " log_level: level.Debug,\n" " json_path: option.Some(\"logs/tensor.json\"),\n" " ))\n" " ```\n" "\n" " ## Prometheus Metrics\n" "\n" " ```gleam\n" " let metrics_text = telemetry.prometheus()\n" " // Returns all metrics in Prometheus exposition format\n" " ```\n" "\n" " ## Benchmarking\n" "\n" " ```gleam\n" " let result = telemetry.benchmark(\"matmul_100x100\", fn() {\n" " ops.matmul_auto(a, b)\n" " })\n" " telemetry.benchmark_print(result)\n" " ```\n" ). -type config() :: {config, viva_telemetry@log@level:level(), gleam@option:option(binary())}. -file("src/viva_tensor/telemetry.gleam", 62). ?DOC(" Default configuration: Info level, console only.\n"). -spec default_config() -> config(). default_config() -> {config, info, none}. -file("src/viva_tensor/telemetry.gleam", 70). ?DOC( " Initialize telemetry with sensible defaults.\n" " Console logging at Info level, all metrics enabled.\n" ). -spec init() -> nil. init() -> viva_telemetry@log:configure_console(info), nil. -file("src/viva_tensor/telemetry.gleam", 77). ?DOC( " Initialize with console + JSON file logging.\n" " JSON file gets all levels for post-mortem analysis.\n" ). -spec init_with_json(binary()) -> nil. init_with_json(Path) -> viva_telemetry@log:configure_full(info, Path, debug), nil. -file("src/viva_tensor/telemetry.gleam", 83). ?DOC(" Initialize with full custom configuration.\n"). -spec init_with_config(config()) -> nil. init_with_config(Config) -> case erlang:element(3, Config) of {some, Path} -> viva_telemetry@log:configure_full( erlang:element(2, Config), Path, erlang:element(2, Config) ); none -> viva_telemetry@log:configure_console(erlang:element(2, Config)) end, nil. -file("src/viva_tensor/telemetry.gleam", 96). ?DOC(" Counter for tensor operations by name.\n"). -spec op_counter(binary()) -> viva_telemetry@metrics:counter(). op_counter(Op) -> viva_telemetry@metrics:counter_with_labels( <<"vt_ops_total"/utf8>>, [{<<"op"/utf8>>, Op}] ). -file("src/viva_tensor/telemetry.gleam", 101). ?DOC(" Histogram for matmul latency in microseconds.\n"). -spec matmul_histogram() -> viva_telemetry@metrics:histogram(). matmul_histogram() -> viva_telemetry@metrics:histogram( <<"vt_matmul_duration_us"/utf8>>, [10.0, 50.0, 100.0, 500.0, 1000.0, 5000.0, 10000.0, 50000.0, 100000.0] ). -file("src/viva_tensor/telemetry.gleam", 108). ?DOC(" Histogram for general operation latency in microseconds.\n"). -spec op_histogram() -> viva_telemetry@metrics:histogram(). op_histogram() -> viva_telemetry@metrics:histogram( <<"vt_op_duration_us"/utf8>>, [1.0, 5.0, 10.0, 50.0, 100.0, 500.0, 1000.0, 5000.0, 10000.0] ). -file("src/viva_tensor/telemetry.gleam", 115). ?DOC(" Histogram for backward pass latency in microseconds.\n"). -spec backward_histogram() -> viva_telemetry@metrics:histogram(). backward_histogram() -> viva_telemetry@metrics:histogram( <<"vt_backward_duration_us"/utf8>>, [100.0, 500.0, 1000.0, 5000.0, 10000.0, 50000.0, 100000.0] ). -file("src/viva_tensor/telemetry.gleam", 122). ?DOC(" Counter for backend selections (accelerate, zig, erlang).\n"). -spec backend_counter(binary()) -> viva_telemetry@metrics:counter(). backend_counter(Backend) -> viva_telemetry@metrics:counter_with_labels( <<"vt_backend_total"/utf8>>, [{<<"backend"/utf8>>, Backend}] ). -file("src/viva_tensor/telemetry.gleam", 127). ?DOC(" Gauge for BEAM process memory in bytes.\n"). -spec memory_gauge() -> viva_telemetry@metrics:gauge(). memory_gauge() -> viva_telemetry@metrics:gauge(<<"vt_memory_bytes"/utf8>>). -file("src/viva_tensor/telemetry.gleam", 132). ?DOC(" Counter for quantization operations by format.\n"). -spec quant_counter(binary()) -> viva_telemetry@metrics:counter(). quant_counter(Format) -> viva_telemetry@metrics:counter_with_labels( <<"vt_quant_ops_total"/utf8>>, [{<<"format"/utf8>>, Format}] ). -file("src/viva_tensor/telemetry.gleam", 175). ?DOC(" Log backend selection at debug level.\n"). -spec log_backend(binary(), binary()) -> nil. log_backend(Backend, Op) -> viva_telemetry@log:debug( <<"backend selected"/utf8>>, [{<<"backend"/utf8>>, Backend}, {<<"op"/utf8>>, Op}] ). -file("src/viva_tensor/telemetry.gleam", 180). ?DOC(" Log backward pass completion.\n"). -spec log_backward(integer(), integer()) -> nil. log_backward(Num_nodes, Duration_us) -> viva_telemetry@log:info( <<"backward"/utf8>>, [{<<"nodes"/utf8>>, erlang:integer_to_binary(Num_nodes)}, {<<"duration_us"/utf8>>, erlang:integer_to_binary(Duration_us)}] ). -file("src/viva_tensor/telemetry.gleam", 196). ?DOC(" Log a tensor error.\n"). -spec log_error(binary(), binary()) -> nil. log_error(Op, Reason) -> viva_telemetry@log:error( <<"tensor error"/utf8>>, [{<<"op"/utf8>>, Op}, {<<"reason"/utf8>>, Reason}] ). -file("src/viva_tensor/telemetry.gleam", 203). ?DOC(" Record a generic tensor operation with timing.\n"). -spec record_op(binary(), integer()) -> nil. record_op(Op, Duration_us) -> viva_telemetry@metrics:inc(op_counter(Op)), viva_telemetry@metrics:observe(op_histogram(), erlang:float(Duration_us)). -file("src/viva_tensor/telemetry.gleam", 223). ?DOC(" Record a dot product operation.\n"). -spec record_dot(integer(), integer(), binary()) -> nil. record_dot(Size, Duration_us, Backend) -> viva_telemetry@metrics:inc(op_counter(<<"dot"/utf8>>)), viva_telemetry@metrics:observe(op_histogram(), erlang:float(Duration_us)), viva_telemetry@metrics:inc(backend_counter(Backend)), viva_telemetry@log:debug( <<"dot"/utf8>>, [{<<"size"/utf8>>, erlang:integer_to_binary(Size)}, {<<"backend"/utf8>>, Backend}, {<<"duration_us"/utf8>>, erlang:integer_to_binary(Duration_us)}] ). -file("src/viva_tensor/telemetry.gleam", 235). ?DOC(" Record a backward pass.\n"). -spec record_backward(integer(), integer()) -> nil. record_backward(Num_nodes, Duration_us) -> viva_telemetry@metrics:observe( backward_histogram(), erlang:float(Duration_us) ), log_backward(Num_nodes, Duration_us). -file("src/viva_tensor/telemetry.gleam", 249). ?DOC(" Report BEAM memory usage. Logs and records gauge.\n"). -spec report_memory() -> viva_telemetry@metrics:beam_memory(). report_memory() -> Mem = viva_telemetry@metrics:beam_memory(), viva_telemetry@metrics:set( memory_gauge(), erlang:float(erlang:element(2, Mem)) ), viva_telemetry@log:info( <<"beam memory"/utf8>>, [{<<"total_mb"/utf8>>, erlang:integer_to_binary(erlang:element(2, Mem) div 1048576)}, {<<"processes_mb"/utf8>>, erlang:integer_to_binary(erlang:element(3, Mem) div 1048576)}, {<<"binary_mb"/utf8>>, erlang:integer_to_binary(erlang:element(8, Mem) div 1048576)}, {<<"ets_mb"/utf8>>, erlang:integer_to_binary(erlang:element(10, Mem) div 1048576)}] ), Mem. -file("src/viva_tensor/telemetry.gleam", 264). ?DOC(" Export all collected metrics in Prometheus text format.\n"). -spec prometheus() -> binary(). prometheus() -> viva_telemetry@metrics:to_prometheus(). -file("src/viva_tensor/telemetry.gleam", 272). ?DOC(" Run a benchmark with default config (100 warmup, 1000 iterations).\n"). -spec benchmark(binary(), fun(() -> any())) -> viva_telemetry@bench:bench_result(). benchmark(Name, F) -> viva_telemetry@bench:run(Name, F). -file("src/viva_tensor/telemetry.gleam", 277). ?DOC(" Run a benchmark with custom iterations.\n"). -spec benchmark_with_config(binary(), fun(() -> any()), integer(), integer()) -> viva_telemetry@bench:bench_result(). benchmark_with_config(Name, F, Warmup, Iterations) -> viva_telemetry@bench:run_with_config( Name, F, viva_telemetry@bench:config(Warmup, Iterations) ). -file("src/viva_tensor/telemetry.gleam", 287). ?DOC(" Run multiple benchmarks and return all results.\n"). -spec benchmark_all(list({binary(), fun(() -> any())})) -> list(viva_telemetry@bench:bench_result()). benchmark_all(Benchmarks) -> viva_telemetry@bench:run_all( Benchmarks, viva_telemetry@bench:default_config() ). -file("src/viva_tensor/telemetry.gleam", 294). ?DOC(" Compare two benchmark results. Returns speedup and significance.\n"). -spec benchmark_compare( viva_telemetry@bench:bench_result(), viva_telemetry@bench:bench_result() ) -> viva_telemetry@bench:comparison(). benchmark_compare(Baseline, Target) -> viva_telemetry@bench:compare(Baseline, Target). -file("src/viva_tensor/telemetry.gleam", 302). ?DOC(" Print benchmark result to stdout.\n"). -spec benchmark_print(viva_telemetry@bench:bench_result()) -> nil. benchmark_print(Result) -> viva_telemetry@bench:print(Result). -file("src/viva_tensor/telemetry.gleam", 307). ?DOC(" Print comparison to stdout.\n"). -spec benchmark_print_comparison(viva_telemetry@bench:comparison()) -> nil. benchmark_print_comparison(Comparison) -> viva_telemetry@bench:print_comparison(Comparison). -file("src/viva_tensor/telemetry.gleam", 312). ?DOC(" Convert benchmark result to markdown.\n"). -spec benchmark_to_markdown(viva_telemetry@bench:bench_result()) -> binary(). benchmark_to_markdown(Result) -> viva_telemetry@bench:to_markdown(Result). -file("src/viva_tensor/telemetry.gleam", 317). ?DOC(" Convert multiple results to a markdown comparison table.\n"). -spec benchmark_table(list(viva_telemetry@bench:bench_result())) -> binary(). benchmark_table(Results) -> viva_telemetry@bench:to_markdown_table(Results). -file("src/viva_tensor/telemetry.gleam", 323). -spec format_shape(list(integer())) -> binary(). format_shape(Shape) -> <<<<"["/utf8, (gleam@string:join( gleam@list:map(Shape, fun erlang:integer_to_binary/1), <<", "/utf8>> ))/binary>>/binary, "]"/utf8>>. -file("src/viva_tensor/telemetry.gleam", 139). ?DOC(" Log a tensor operation at debug level.\n"). -spec log_op(binary(), list(integer())) -> nil. log_op(Op, Shape) -> viva_telemetry@log:debug( <<"tensor op"/utf8>>, [{<<"op"/utf8>>, Op}, {<<"shape"/utf8>>, format_shape(Shape)}] ). -file("src/viva_tensor/telemetry.gleam", 327). -spec format_float(float()) -> binary(). format_float(F) -> Rounded = erlang:round(F * 100.0), gleam_stdlib:float_to_string(erlang:float(Rounded) / 100.0). -file("src/viva_tensor/telemetry.gleam", 144). ?DOC(" Log matmul execution with performance details.\n"). -spec log_matmul(integer(), integer(), integer(), binary(), integer()) -> nil. log_matmul(M, K, N, Backend, Duration_us) -> Flops = ((2 * M) * K) * N, Gflops = case Duration_us > 0 of true -> format_float((case erlang:float(Duration_us) of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> erlang:float(Flops) / Gleam@denominator end) / 1000.0); false -> <<"inf"/utf8>> end, viva_telemetry@log:info( <<"matmul"/utf8>>, [{<<"dims"/utf8>>, <<<<<<<<<<<<(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>>}, {<<"backend"/utf8>>, Backend}, {<<"duration_us"/utf8>>, erlang:integer_to_binary(Duration_us)}, {<<"gflops"/utf8>>, Gflops}] ). -file("src/viva_tensor/telemetry.gleam", 188). ?DOC(" Log quantization operation.\n"). -spec log_quantize(binary(), float()) -> nil. log_quantize(Format, Ratio) -> viva_telemetry@log:info( <<"quantize"/utf8>>, [{<<"format"/utf8>>, Format}, {<<"ratio"/utf8>>, <<(format_float(Ratio))/binary, "x"/utf8>>}] ). -file("src/viva_tensor/telemetry.gleam", 209). ?DOC(" Record a matmul operation with full details.\n"). -spec record_matmul(integer(), integer(), integer(), integer(), binary()) -> nil. record_matmul(M, N, K, Duration_us, Backend) -> viva_telemetry@metrics:inc(op_counter(<<"matmul"/utf8>>)), viva_telemetry@metrics:observe( matmul_histogram(), erlang:float(Duration_us) ), viva_telemetry@metrics:inc(backend_counter(Backend)), log_matmul(M, K, N, Backend, Duration_us). -file("src/viva_tensor/telemetry.gleam", 241). ?DOC(" Record a quantization operation.\n"). -spec record_quantize(binary(), float()) -> nil. record_quantize(Format, Ratio) -> viva_telemetry@metrics:inc(quant_counter(Format)), log_quantize(Format, Ratio).