Packages

A high-performance, lossless compression library for time series data implementing Facebook's Gorilla compression algorithm.

Current section

Files

Jump to
gorilla_stream lib mix tasks vm_benchmark.ex
Raw

lib/mix/tasks/vm_benchmark.ex

defmodule Mix.Tasks.GorillaStream.VmBenchmark do
use Mix.Task
@shortdoc "Compare Gorilla, VM preprocessing, zlib, and combined variants across patterns"
@moduledoc """
Benchmarks compression variants on representative datasets:
- Gorilla only
- Gorilla + VictoriaMetrics preprocessing (auto and fixed decimals)
- zlib only (on raw binary)
- Gorilla -> zlib
- Gorilla+VM -> zlib
Examples:
mix gorilla_stream.vm_benchmark 10000
LOG_LEVEL=info mix gorilla_stream.vm_benchmark 50000
"""
require Logger
alias GorillaStream.Compression.Gorilla
@impl true
def run(args) do
Mix.Task.run("app.start")
count =
case args do
[n] -> String.to_integer(n)
_ -> 10_000
end
datasets = [
{generate_identical(count), "Identical values"},
{generate_step(count), "Step function"},
{generate_gauge_2dp(count), "Gauge (2dp, smooth)"},
{generate_counter_2dp(count), "Counter (2dp, small increments)"}
]
Enum.each(datasets, fn {data, label} ->
bench_dataset(data, label)
end)
Logger.info("VM benchmark complete for #{count} points per dataset")
end
defp bench_dataset(data, label) do
orig_bin = :erlang.term_to_binary(data)
orig_size = byte_size(orig_bin)
ratio = fn sz -> Float.round(sz / orig_size, 4) end
pct = fn r -> Float.round((1.0 - r) * 100.0, 1) end
# Gorilla only
{t_g, {:ok, g_bin}} =
:timer.tc(fn -> Gorilla.compress(data, zlib: false, victoria_metrics: false) end)
g_sz = byte_size(g_bin)
# VM auto (gauge path)
{t_vm_auto, {:ok, vm_auto_bin}} =
:timer.tc(fn ->
Gorilla.compress(data,
zlib: false,
victoria_metrics: true,
is_counter: false,
scale_decimals: :auto
)
end)
vm_auto_sz = byte_size(vm_auto_bin)
# VM 2dp (gauge path)
{t_vm_2dp, {:ok, vm_2dp_bin}} =
:timer.tc(fn ->
Gorilla.compress(data,
zlib: false,
victoria_metrics: true,
is_counter: false,
scale_decimals: 2
)
end)
vm_2dp_sz = byte_size(vm_2dp_bin)
# zlib only on raw data
{t_z, z_bin} = :timer.tc(fn -> :zlib.compress(orig_bin) end)
z_sz = byte_size(z_bin)
# Combined: Gorilla -> zlib
{t_gz, gz_bin} = :timer.tc(fn -> :zlib.compress(g_bin) end)
gz_sz = byte_size(gz_bin)
# Combined: Gorilla+VM(2dp) -> zlib
{t_vmz, vmz_bin} = :timer.tc(fn -> :zlib.compress(vm_2dp_bin) end)
vmz_sz = byte_size(vmz_bin)
Logger.info("\n=== #{label} ===")
Logger.info("Original: #{orig_size} bytes")
Logger.info(
"Gorilla only : #{g_sz} bytes (ratio=#{ratio.(g_sz)}, saved=#{pct.(ratio.(g_sz))}% , enc_us=#{t_g})"
)
Logger.info(
"Gorilla+VM auto : #{vm_auto_sz} bytes (ratio=#{ratio.(vm_auto_sz)}, saved=#{pct.(ratio.(vm_auto_sz))}% , enc_us=#{t_vm_auto})"
)
Logger.info(
"Gorilla+VM 2dp : #{vm_2dp_sz} bytes (ratio=#{ratio.(vm_2dp_sz)}, saved=#{pct.(ratio.(vm_2dp_sz))}% , enc_us=#{t_vm_2dp})"
)
Logger.info(
"zlib only : #{z_sz} bytes (ratio=#{ratio.(z_sz)}, saved=#{pct.(ratio.(z_sz))}% , enc_us=#{t_z})"
)
Logger.info(
"Gorilla -> zlib : #{gz_sz} bytes (ratio=#{ratio.(gz_sz)}, saved=#{pct.(ratio.(gz_sz))}% , enc_us=#{t_g + t_gz})"
)
Logger.info(
"Gorilla+VM2dp->zlb: #{vmz_sz} bytes (ratio=#{ratio.(vmz_sz)}, saved=#{pct.(ratio.(vmz_sz))}% , enc_us=#{t_vm_2dp + t_vmz})"
)
# Validate that VM paths round-trip
{:ok, _} = Gorilla.decompress(vm_auto_bin)
{:ok, _} = Gorilla.decompress(vm_2dp_bin)
end
# Data generators
defp generate_identical(n) do
base = 1_700_000_000
for i <- 0..(n - 1), do: {base + i, 42.0}
end
defp generate_step(n) do
base = 1_700_000_000
step = max(1, div(n, 10))
for i <- 0..(n - 1) do
level = div(i, step)
{base + i, level * 1.0}
end
end
defp generate_gauge_2dp(n) do
base = 1_700_000_000
for i <- 0..(n - 1) do
v = 100.0 + 0.01 * i + :math.sin(i / 50) * 0.1
{base + i, Float.round(v, 2)}
end
end
defp generate_counter_2dp(n) do
base = 1_700_000_000
increments = Stream.repeatedly(fn -> :rand.uniform(5) - 1 end) |> Enum.take(n)
{vals, _} =
Enum.map_reduce(increments, 1000.0, fn inc, acc ->
v = acc + inc
{v, v}
end)
for {v, i} <- Enum.with_index(vals), do: {base + i, Float.round(v + 0.01, 2)}
end
end