Skip to content

Commit

Permalink
[feat] Massively sped up versions checks
Browse files Browse the repository at this point in the history
The version of elixir and erlang won't change while the VM is running,
so they're a perfect example of what should be cached in
persistent_term.
  • Loading branch information
scohen committed Feb 17, 2025
1 parent fa81714 commit 47f3564
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 29 deletions.
10 changes: 5 additions & 5 deletions apps/common/lib/elixir/features.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ defmodule Elixir.Features do
end

def compile_keeps_current_directory? do
Version.match?(System.version(), ">= 1.15.0")
Versions.current_elixir_matches?(">= 1.15.0")
end

def after_verify? do
Version.match?(System.version(), ">= 1.14.0")
Versions.current_elixir_matches?(">= 1.14.0")
end

def details_in_context? do
Version.match?(System.version(), ">= 1.16.0")
Versions.current_elixir_matches?(">= 1.16.0")
end

def span_in_diagnostic? do
Version.match?(System.version(), ">= 1.16.0")
Versions.current_elixir_matches?(">= 1.16.0")
end

def contains_set_theoretic_types? do
Version.match?(System.version(), ">= 1.17.0")
Versions.current_elixir_matches?(">= 1.17.0")
end

@doc """
Expand Down
59 changes: 36 additions & 23 deletions apps/common/lib/lexical/vm/versions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ defmodule Lexical.VM.Versions do
@type t :: %{elixir: version_string(), erlang: version_string()}
@type versioned_t :: %{elixir: Version.t(), erlang: Version.t()}

defmacrop cache_in_persistent_term(key, do: materializer) do
quote do
with :not_found <- :persistent_term.get(unquote(key), :not_found) do
result = unquote(materializer)
:persistent_term.put(unquote(key), result)
result
end
end
end

@doc """
Returns the versions of elixir and erlang in the currently running VM
"""
Expand All @@ -27,6 +37,15 @@ defmodule Lexical.VM.Versions do
}
end

@doc """
Returns true if the current version of elixir matches the requirement
"""
def current_elixir_matches?(requirement) do
cache_in_persistent_term {:current_elixir_matches?, requirement} do
Version.match?(elixir_version(), requirement)
end
end

@doc """
Returns the compiled-in versions of elixir and erlang.
Expand Down Expand Up @@ -138,32 +157,26 @@ defmodule Lexical.VM.Versions do
end

defp elixir_version do
System.version()
cache_in_persistent_term {__MODULE__, :current_elixir} do
System.version()
end
end

defp erlang_version do
case :persistent_term.get({__MODULE__, :current_erlang}, :not_found) do
:not_found ->
major = :otp_release |> :erlang.system_info() |> List.to_string()
version_file = Path.join([:code.root_dir(), "releases", major, "OTP_VERSION"])

erlang_version =
try do
{:ok, contents} = read_file(version_file)
String.split(contents, "\n", trim: true)
else
[full] -> full
_ -> major
catch
:error ->
major
end

:persistent_term.put({__MODULE__, :current_erlang}, erlang_version)
erlang_version()

erlang_version ->
erlang_version
cache_in_persistent_term {__MODULE__, :current_erlang} do
major = :otp_release |> :erlang.system_info() |> List.to_string()
version_file = Path.join([:code.root_dir(), "releases", major, "OTP_VERSION"])

try do
{:ok, contents} = read_file(version_file)
String.split(contents, "\n", trim: true)
else
[full] -> full
_ -> major
catch
:error ->
major
end
end
end

Expand Down
10 changes: 10 additions & 0 deletions apps/remote_control/benchmarks/versions_bench.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
alias Lexical.VM.Versions

Benchee.run(%{
"versions" => fn ->
Version.match?(Versions.current().elixir, ">=1.15.0")
end,
"current_versions_matches" => fn ->
Versions.current_elixir_matches?(">=1.15.0")
end
})
2 changes: 1 addition & 1 deletion projects/lexical_shared/lib/lexical/debug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ defmodule Lexical.Logging do
@debug_enabled? not is_nil(System.get_env("TIMINGS_ENABLED"))

defp enabled? do
@debug_enabled?
true
end
end

0 comments on commit 47f3564

Please sign in to comment.