hst337

hst337

Tria

https://github.com/hissssst/tria

An optimizing compiler for Elixir language

Public and alpha :tada:

I’ve made this repository public to finally get some rest and find other developers who may be interested in participating in this project (it sounds so naive when I write it) before getting hands on the second iteration.

Current state

!!!Unstable!!!

Tria passes most of the tests in Phoenix, Ecto, Plug and other projects, while it may fail to compile other projects. You’re welcome to compile projects using Tria and fill an issue if something fails. This kind of help would be heavily appreciated.

Even without considering this, Tria compiler lacks some important features like incremental compilation, warning handling and stuff.

However, you can expect the stable version during 2023-ish

Current features

  1. Compile-time evaluation.
    Yes, as simple as it sounds, Elixir and Erlang were incapable of doing this, since they support runtime recompilation. Ahead-of-time nature of Tria allowed to evaluate pure statement in compile time

  2. Enum fusion
    Join multiple Enum.maps, optimize for loops to finally be efficient and other magic.

I haven’t benchmarked these yet, but these optimizations actually work and (more importantly) work correctly in most cases

Planned features

  1. Broad documentation (like pathex has)
  2. Inlining
  3. Hot-reloading support
  4. Peephole optimizations for common suboptimal code.
  5. map.field handling (did you know that it is 2-3 times slower than Map.fetch!(map, :field)?)
  6. Type-checker integration

Help wanted

If you’re interested in optimizing compiler development, you’re welcome to take a look around, poke some things, check some stuff. I know that some Brazilian universities are working in Elixir-related compiler development, and I hope we can collaborate on Tria someday

PS: Questions are appreciated


UPD: License is going to change in a near future

Showing Posts 1 to 10

sergio

sergio

I’m still a little confused what this project is/does.

Can you try to restate what it is and what it does in simpler terms?

hst337

hst337 OP

“Optimizer” means a thing which makes something more efficient.

So is Tria. It simply makes your code more efficient in terms of time and memory when you add it to your project as a dependency (and a list of compilers). It makes Enum calls and for loops faster, it removes unnecessary calls, it evaluates some stuff in compile time

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

This is very exciting! Looking forward to testing this on some projects.

Tiny question: In the install guide you add {:tria, github: "hissssst/tria"} to the deps, presumably this could be runtime: false or does it need to exist when the app runs too?

hst337

hst337 OP

No, Tria is not called in runtime, though I haven’t testing it with this flag yet. To be honest, I’ve only tested it with path: "../tria" during development :sweat_smile:

Eiji

Eiji

Ahh, so bad we can’t set compilers via Mix.install/2 (we can only turn off consolidated protocols) … Is there any particular reason why thee is no support for it?

hst337

hst337 OP

I think we can create a proposal for the language. I don’t see any boundaries why this shouldn’t be implemented there

Eiji

Eiji

I was thinking the same, but your comment made me sure about it. Here is in issue:
https://github.com/elixir-lang/elixir/issues/12349

As wrote in it once there would be a support for it at least in main branch I would try your library with my scripts like scrapers and I would try to submit some benchmarks as well.

josevalim

josevalim

Creator of Elixir

Exciting to see your ideas come to life!

How do you know which functions are pure? Especially when anonymous functions are involved?

Could you please expand on the tricks here (or share a link)? :smiley: I assume some of those may be implementable in Elixir itself, since for is opaque (although it is unlikely we would do Enum fusion).

Curious: how would that be different from Erlang inlining via @compile :inlineand @compile {:inline, size}?

Any ideas here? We do compile map.field to a case statement but, last time I measured, the pattern matching was faster than invoking a BIF instruction (which is what Map.fetch! does). map.fieldshould be slower if the field does not exist though.

Other than that, nice work! I am sure the Erlang Compiler team would also be interested in further ideas to optimize. Some of the peephole and type-checker integration may already be implemented there. Although we don’t perform protocol related type optimizations and the Erlang compiler does not have enough information to do so, so maybe Elixir could/should.

14
Post #8
hst337

hst337 OP

Thanks for your questions!

This is a big questions. Generally, there are two types of functions: functions which are defined in Erlang or Elixir, or functions which are undefined (thus contain erlang:nif_error or call to themselves in their bodies like in Elixir bootstrap).

For the latter, I’ve prepared the ets table file with purity for all such function from all available modules. When unexpected NIF function is found in call stack, Tria would just ask the user in TTY if such function is pure. I have a plan to add annotations like

@tria pure: true, safe: true
def my_nif() do
  ...
end

For the functions which have Erlang/Elixir definitions, compiler fetches the abstract code, translates it to Tria and just takes a look at all possible calls. So, calls to impure or anonymous functions are considered impure and this is not always correct, but it works for the first iteration of compiler and it can be partially solved with type checking in the future


It translates Enum.reduce() |> :lists.reverse to Enum.map. Compiler just needs to make sure that Enum.reduce aggregates each item straight to the accumulator list, without any conditions. Here’s the optimization: tria/lib/tria/optimizer/pass/enum_fusion.ex at main · hissssst/tria · GitHub. You can see there tri macro which is a great tool for pattern-matching on Tria AST.


It will be different in some ways. For example, inter-module calls will be inlined. And defaults (like foo(x, y \\ 0) will be expanded too, removing one call in the stack


However, some of these approaches change the behaviour of the program in two ways:

  1. Pure code which raises exceptions may be reordered by EnumFusion optimization. I am working on fixing this behavior to have more correct compiler.
  2. Runtime recompilation is not yet possible. It can be possible in the future, but Tria just needs some tooling for this.
josevalim

josevalim

Creator of Elixir

What we could do in Elixir itself is to keep a list of the functions in its standard library that are pure. Erlang also keeps a similar list for its standard library and inlines those. WDYT?

We can make this generally applicable but it is worth keeping in mind that each inlined modules becomes a compile-time dependency, and enlarging the compile time graphic can have huge impacts on performance. This is not a concern for Elixir stdlib itself though.

It is also not possible to know if something is pure or not when calling Erlang functions (unless we have an FFI layer where you also explicitly declare those).

Ah, thank you. We had a previous discussion about this. At the time, the cost of traversal in for comparing Enum.reduce vs Enum.map was roughly 13% faster. However, your benchmarks show the body recursive version can be even faster and we could emit Erlang AST with a body recursive version using Erlang’s “named anonymous functions”. Is this something you have an interest in contributing? Or should I open up an issue for someone else to pick?

Where Next? Top

Trending in Announcing Top

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
ausimian
Castle is a package I put together to assist with building Elixir releases capable of being live-upgraded via the ‘official’ release hand...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews