zachdaniel

zachdaniel

Creator of Ash

Recent Spark performance improvements should have significant positive effects on Ash application performance

Hey folks, made some recent performance improvements to spark, the tool underlying all of our DSLs. GitHub - ash-project/spark: Tooling for building DSLs in Elixir

It should make code that accesses DSL options significantly faster. If people can try it out with mix deps.update spark that would be great :slight_smile: Bonus points to anyone who has some level of performance measuring, if you could show how its impacted things for you, that would be great :heart:

Some technical context around what was actually done:

Modules that use the DSL built by spark create a data structure under the hood, that looks like this:

%{
  persisted: %{...explicitly cached things that are used often},
  [:attributes] => %{entities: [...], options: [...]},
  [:json_api, :routes] => %{entities: [...], options: [...]},
  ... and so on
}

This data structure groups everything by section. However, when accessing DSL information, you always go through a set of functions provided by spark, for example Spark.Dsl.Extension.get_opt and Spark.Dsl.entities. We did this on purpose to allow us to optimize the underlying storage mechanisms and access patterns. While doing some recent benchmarking, we saw that the current naive implementations were taking quite a bit of time during the execution of Ash actions. The implementation would be something like dsl |> Map.get(path) |> Map.get(:options) |> Keyword.get(option_name). We would do similar things with entities.

What we’ve instead done is defined functions under the hood for each section path and option, that pattern matches and returns the value. It looks like this:

        for {path, %{opts: opts}} <- @spark_dsl_config, is_list(path) do
          for {key, value} <- opts do
            def fetch_opt(unquote(path), unquote(key)) do
              {:ok, unquote(Macro.escape(value))}
            end
          end
        end

        def fetch_opt(_, _), do: :error

Then we updated Extension.get_opt to call this generated function instead of getting the big DSL map and pulling out values. Measurements so far show significant performance improvements (especially in bulk creates, which s what sparked this recent investigation into unnecessary slowness).

Aside from this, we also leveraged the persist key to optimize a bunch of commonly accessed Ash DSL items.

Please give it a try! Bonus points to anyone who has some level of performance measuring, if you could show how its impacted things for you, that would be great :heart:

Most Liked

frankdugan3

frankdugan3

I have an ERP app (82,528 lines of Elixir) with over 80 resources that heavily leverage Ash extensions, and it seems like these improvements also vastly improve compile time, cutting it down to less than half for me!

With spark 1.1.46:

hsm on  graphql-api-tokens [!?] via  v1.14.5 (OTP 25) mix compile --force
Compiling 499 files (.ex)
Generated hsm app
Compiling golang module :gopcua_bridge (native/gopcua_bridge)...
hsm on  graphql-api-tokens [!?] via  v1.14.5 (OTP 25) took 1m26s

With spark 1.1.48:

hsm on  graphql-api-tokens [!?] via  v1.14.5 (OTP 25)

ᕕ(ᐛ)ᕗ mix compile --force
Compiling 499 files (.ex)
Generated hsm app
Compiling golang module :gopcua_bridge (native/gopcua_bridge)...
hsm on  graphql-api-tokens [!?] via  v1.14.5 (OTP 25) took 41s
15
Post #2

Where Next?

Popular in News & Updates Top

mobileoverlord
New versions of the Kiosk systems are out. These systems update official Nerves systems with a local web browser for rendering user inter...
New
zachdaniel
First two Ash cookbooks are live! We’re still refining the format, so please give us your feedback, good or bad! The first two are: optim...
New
zachdaniel
Working with nested forms in Ash was already great, but it’s even better now with a the new features that will be in the next release of ...
New
mat-hek
Hi everyone, I’d like to share with you a new library from the Membrane team - Boombox. It’s a simple streaming tool built on top of Mem...
New
zachdaniel
Hey everyone! Work is progressing nicely on bulk updates &amp; destroys, which are the primary missing features before I switch to focus ...
New
zachdaniel
Hey folks! We’re starting a new weekly newsletter with the goings on of the various Ash packages and other interesting news from myself a...
New
DominikWolek
Hey everyone! The Membrane Framework has a new website! It contains tutorials, blog posts, and other resources you’ll find handy while u...
New
jjcarstens
Hey friends! :wave: With NervesConf 2024 around the corner, Frank, myself, and the greater Nerves team wanted to share a survey we’ve pu...
New
zachdaniel
We recently launched atomic updates, which look like this: update :update do change atomic_update(:score, expr(score + 1)) end # or w...
New
fhunleth
Circuits.GPIO lets you read and write to I/O pins on embedded hardware like that used by Nerves. The new v2.0 version makes it possible t...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29305 241
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52238 488
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New

We're in Beta

About us Mission Statement