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

Allow choosing between compile-time or runtime generation of large attack tables. #79

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

wreald
Copy link

@wreald wreald commented Jul 22, 2024

I'm trying to use shakmaty in a WebAssembly project that will run in a browser. Unfortunately the static attack tables (particularly shakmaty::bootstrap::ATTACKS, which is 700KB on its own) are increasing my binary size by an order of magnitude (~80KB -> ~800KB). To address this, I would like a Cargo feature that controls whether the tables are generated at compile time and embedded in the binary, or are generated at runtime.

With this PR, when the runtime-lut feature is enabled, ATTACKS and RAYS are boxed (Box::<[u64, _]>), and use the lazy_static macro to defer initialisation to the first use at runtime.

The code is not really the prettiest, but I believe the maybe_const_fn macro is the only way to avoid writing out the table generation functions twice, once for array and once for Box. It would have been possible to simply call Box::new(init_magics()), which semantically works, but causes the whole LUT to be pushed onto the stack while it's generated, which triggered a stack overflow for me building against the wasm32-unknown-unknown target.

Possible concerns:

  • New (small, popular) dependency on lazy_static when feature is enabled.
  • The ATTACKS and RAYS variables now have different types depending on a feature flag. It would be possible to make them both &'static [u64; _] (using Box::leak for the box version), but since they are internal-only and Box derefs to an array anyway this didn't seem necessary.
  • I didn't bother to implement runtime generation for individual piece tables (KNIGHT_ATTACKS etc.) since they are much smaller. If the consistency is desirable though this approach could be extended to all static tables.

@niklasf
Copy link
Owner

niklasf commented Aug 7, 2024

Exploring the space of possible tradeoffs, there's also Hyperbola Quintessence, which does not need such large tables even at runtime. For example, https://github.com/niklasf/chessops uses it to reduce bootstrap time, which could be important in web applications.

I now implemented enough of it for a benchmark, and see "only" a ~20% perft performance drop. Maybe that's the way to go then, instead of runtime generated magic tables?

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.

2 participants