Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster AST Construction #21398

Closed
wants to merge 6 commits into from
Closed

Conversation

RetroDev256
Copy link
Contributor

@RetroDev256 RetroDev256 commented Sep 13, 2024

  • Faster on majority of source files
  • Doesn't make the source code too obscure

With alternate changes, I could consistently get ~10% speed improvements on large files, but it had a big downside. Firstly, smaller files took a lot longer to parse, and secondly, it made the Parse.zig source code really hard to maintain.

With these sets of tweaks, a typical source file will be parsed ~3-5% faster, but very small files seem to be parsed slightly slower. Do note that by "slightly slower", it is a percentage difference. Smaller files are inherently less complicated, so less time is gained/wasted by the same percentage difference of parsing a small file, than a large file, and if you look at the benchmarks, the standard deviation makes telling if something was "slow" or "fast" pretty difficult.

This does constitute a breaking change on std.zig.Tokenizer.Token - my reasoning for the change is that the language itself limits itself to 2^32 bytes per file at most, so the standard library should not need to bother allowing us to tokenize up to 2^64 bytes of source, while not being able to parse it all. With the breaking change, I got rid of that annoying 'loc', which personally I don't think was too necessary.

Optimizations in the Zig compiler are of course really enjoyable to try out, but do note that the AST construction takes a very insignificant time in the grand scheme of things.

Benchmarking ast-check on Sema.zig:

bench Sema

Benchmarking ast-check on print_air.zig:

bench print_air

Benchmarking ast-check on the zig init main.zig:

bench zig_init_main

Copy link
Contributor

@Rexicon226 Rexicon226 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick glance.

lib/std/zig/Ast.zig Outdated Show resolved Hide resolved
lib/std/zig/Ast.zig Outdated Show resolved Hide resolved
lib/std/zig/Ast.zig Outdated Show resolved Hide resolved
@RetroDev256
Copy link
Contributor Author

For the recent changes, perf on the zig init main.zig and print_air.zig remain very slightly improved, but now I am consistently seeing this benchmark for Sema.zig:
sema

tag: Token.Tag,
start: ByteOffset,
});
pub const TokenList = std.MultiArrayList(Token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has this changed? Storing only the start offset of the token is a very intentional design choice.

Copy link
Contributor Author

@RetroDev256 RetroDev256 Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that the tokenSlice function in Ast.zig could avoid running the tokenizer if I stored the end index. Would you like me to revert that change?

That change alone is responsible for the higher memory usage, but also cut off a few percent on the wall time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please. This tradeoff was made intentionally to save memory at the potential expense of a small amount of performance. I say "potential" because tokenization is fast enough that it could be faster to re-tokenize this one then than to get more cache misses from storing this data in memory. See Andrew's talk on DOD for details.

If the performance impact is more significant than expected perhaps we can revisit this. If you'd like to quantify the performance difference this gives on ast-check, that'd be appreciated.

Copy link
Contributor Author

@RetroDev256 RetroDev256 Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the benchmark on Sema.zig with the changes to Ast.zig:
image
Here is the benchmark on Sema.zig without the changes to Ast.zig:
image

The results honestly make me wonder if anything else I did was just pure noise.

Copy link
Contributor Author

@RetroDev256 RetroDev256 Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
And the difference between these two runs is purely the pub const TokenList = std.MultiArrayList(Token); change (alongside the tokenSlice change), without any of the other changes in this PR thrown in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that based on these findings, I should close this PR if we want the memory savings.

@RetroDev256
Copy link
Contributor Author

In any case, the changes aren't playing well with translate-c/ast.zig, I don't think this change is significant enough to warrant a ton of code shuffling.

@RetroDev256 RetroDev256 deleted the fastest-ast branch September 18, 2024 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants