Skip to content

Commit

Permalink
Implement format_human and required callbacks for all units
Browse files Browse the repository at this point in the history
  • Loading branch information
PragTob committed Dec 22, 2023
1 parent e7c178a commit bdb7599
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 39 deletions.
33 changes: 29 additions & 4 deletions lib/benchee/conversion/count.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule Benchee.Conversion.Count do
@one_million 1_000_000
@one_thousand 1_000

@units %{
@units_map %{
billion: %Unit{
name: :billion,
magnitude: @one_billion,
Expand All @@ -41,6 +41,8 @@ defmodule Benchee.Conversion.Count do
}
}

@units Map.values(@units_map)

@type unit_atoms :: :one | :thousand | :million | :billion
@type units :: unit_atoms | Unit.t()

Expand Down Expand Up @@ -111,7 +113,11 @@ defmodule Benchee.Conversion.Count do
}
"""
def unit_for(unit) do
Scale.unit_for(@units, unit)
Scale.unit_for(@units_map, unit)
end

def units do
@units
end

@doc """
Expand Down Expand Up @@ -191,8 +197,9 @@ defmodule Benchee.Conversion.Count do
def base_unit, do: unit_for(:one)

@doc """
Formats a number as a string, with a unit label. To specify the unit, pass
a tuple of `{value, unit_atom}` like `{1_234, :million}`
Formats a number as a string, with a unit label.
To specify the unit, pass a tuple of `{value, unit_atom}` like `{1_234, :million}`
## Examples
Expand All @@ -211,4 +218,22 @@ defmodule Benchee.Conversion.Count do
def format(count) do
Format.format(count, __MODULE__)
end

@doc """
Formats in a more "human" way separating by units.
## Examples
iex> format_human(45_678.9)
"45 K 678.90"
iex> format_human(1_000_000)
"1 M"
iex> format_human(1_001_000)
"1 M 1 K"
"""
def format_human(count) do
Format.format_human(count, __MODULE__)
end
end
21 changes: 18 additions & 3 deletions lib/benchee/conversion/deviation_percent.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ defmodule Benchee.Conversion.DeviationPercent do
@behaviour Format

@doc """
Formats the standard deviation ratio to an equivalent percent number
including special signs. The ± is an important part of it as it shows that
the deviation might be up but also might be down.
Formats the standard deviation ratio to an equivalent percent number including special signs.
The ± is an important part of it as it shows that the deviation might be up but also might be
down.
## Examples
Expand All @@ -28,4 +29,18 @@ defmodule Benchee.Conversion.DeviationPercent do
|> :io_lib.format(["±", std_dev_ratio * 100.0])
|> to_string
end

@doc """
Formats standard deviation percent, same as `format/1`.
Implemented for consistency.
## Examples
iex> format_human(0.1)
"±10.00%"
"""
def format_human(std_dev_ratio) do
format(std_dev_ratio)
end
end
30 changes: 18 additions & 12 deletions lib/benchee/conversion/duration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ defmodule Benchee.Conversion.Duration do
@nanoseconds_per_minute @nanoseconds_per_second * @seconds_per_minute
@nanoseconds_per_hour @nanoseconds_per_minute * @minutes_per_hour

@units %{
@units_map %{
hour: %Unit{
name: :hour,
magnitude: @nanoseconds_per_hour,
Expand Down Expand Up @@ -60,6 +60,8 @@ defmodule Benchee.Conversion.Duration do
}
}

@units Map.values(@units_map)

@doc """
Scales a duration value in nanoseconds into a larger unit if appropriate
Expand Down Expand Up @@ -140,7 +142,7 @@ defmodule Benchee.Conversion.Duration do
}
"""
def unit_for(unit) do
Scale.unit_for(@units, unit)
Scale.unit_for(@units_map, unit)
end

def units do
Expand Down Expand Up @@ -268,20 +270,24 @@ defmodule Benchee.Conversion.Duration do
end

@doc """
iex> format_human(5_400_000_000_000)
"1 h 30 min"
Formats in a more "human" way - 1h 30min instead of 1.5h.
## Examples
iex> format_human(5_400_000_000_000)
"1 h 30 min"
iex> format_human(12.5)
"12.50 ns"
iex> format_human(12.5)
"12.50 ns"
iex> format_human(1000.555)
"1 μs 0.55 ns"
iex> format_human(1000.555)
"1 μs 0.55 ns"
iex> format_human(3_660_001_001_000)
"1 h 1 min 1 ms 1 μs"
iex> format_human(3_660_001_001_000)
"1 h 1 min 1 ms 1 μs"
iex> format_human(0)
"0 ns"
iex> format_human(0)
"0 ns"
"""
def format_human(duration) do
Format.format_human(duration, __MODULE__)
Expand Down
37 changes: 21 additions & 16 deletions lib/benchee/conversion/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,31 @@ defmodule Benchee.Conversion.Format do
"""
@callback format(number) :: String.t()

@doc """
Formats in a more "human" way, one biggest unit at a time.
So instead of 1.5h it says 1h 30min
"""
@callback format_human(number) :: String.t()

# Generic formatting functions

@doc """
Formats a unit value with specified label and separator
"""
def format(count, label, separator) do
def format(number, label, separator) do
separator = separator(label, separator)
"#{number_format(count)}#{separator}#{label}"
"#{number_format(number)}#{separator}#{label}"
end

defp number_format(count) when is_float(count) do
count
|> :erlang.float_to_list(decimals: float_precision(count))
defp number_format(number) when is_float(number) do
number
|> :erlang.float_to_list(decimals: float_precision(number))
|> to_string
end

defp number_format(count) when is_integer(count) do
to_string(count)
defp number_format(number) when is_integer(number) do
to_string(number)
end

@doc """
Expand All @@ -49,16 +56,16 @@ defmodule Benchee.Conversion.Format do
"1 KB"
"""
def format({count, unit = %Unit{}}) do
format(count, label(unit), separator())
def format({number, unit = %Unit{}}) do
format(number, label(unit), separator())
end

def format({count, unit = %Unit{}}, _module) do
format({count, unit})
def format({number, unit = %Unit{}}, _module) do
format({number, unit})
end

def format({count, unit_atom}, module) do
format({count, module.unit_for(unit_atom)})
def format({number, unit_atom}, module) do
format({number, module.unit_for(unit_atom)})
end

def format(number, module) when is_number(number) do
Expand Down Expand Up @@ -96,9 +103,7 @@ defmodule Benchee.Conversion.Format do
end

defp units_descending(module) do
module.units()
|> Map.values()
|> Enum.sort(&(&1.magnitude >= &2.magnitude))
Enum.sort(module.units(), &(&1.magnitude >= &2.magnitude))
end

@spec place_values(number, [Unit.t()]) :: [{number, Unit.t()}]
Expand Down
30 changes: 26 additions & 4 deletions lib/benchee/conversion/memory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule Benchee.Conversion.Memory do
@bytes_per_gigabyte @bytes_per_megabyte * @bytes_per_kilobyte
@bytes_per_terabyte @bytes_per_gigabyte * @bytes_per_kilobyte

@units %{
@units_map %{
terabyte: %Unit{
name: :terabyte,
magnitude: @bytes_per_terabyte,
Expand Down Expand Up @@ -48,6 +48,8 @@ defmodule Benchee.Conversion.Memory do
}
}

@units Map.values(@units_map)

@type unit_atom :: :byte | :kilobyte | :megabyte | :gigabyte | :terabyte
@type any_unit :: unit_atom | Unit.t()

Expand Down Expand Up @@ -162,7 +164,11 @@ defmodule Benchee.Conversion.Memory do
}
"""
def unit_for(unit) do
Scale.unit_for(@units, unit)
Scale.unit_for(@units_map, unit)
end

def units do
@units
end

@doc """
Expand Down Expand Up @@ -225,8 +231,9 @@ defmodule Benchee.Conversion.Memory do
def base_unit, do: unit_for(:byte)

@doc """
Formats a number as a string, with a unit label. To specify the unit, pass
a tuple of `{value, unit_atom}` like `{1_234, :kilobyte}`
Formats a memory as a string, with a unit label.
To specify the unit, pass a tuple of `{value, unit_atom}` like `{1_234, :kilobyte}`.
## Examples
Expand All @@ -249,4 +256,19 @@ defmodule Benchee.Conversion.Memory do
def format(memory) do
Format.format(memory, __MODULE__)
end

@doc """
Formats in a more human way, where multiple units are used.
## Examples
iex> format_human(45_678.9)
"44 KB 622.90 B"
iex> format_human(1024 * 1024 * 1024)
"1 GB"
"""
def format_human(memory) do
Format.format_human(memory, __MODULE__)
end
end
5 changes: 5 additions & 0 deletions lib/benchee/conversion/scale.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ defmodule Benchee.Conversion.Scale do
"""
@callback unit_for(any_unit) :: unit

@doc """
List of all the units supported by this type.
"""
@callback units :: [unit]

@doc """
Takes a tuple of a number and a unit and a unit to be converted to, returning
the the number scaled to the new unit and the new unit.
Expand Down

0 comments on commit bdb7599

Please sign in to comment.