-
Notifications
You must be signed in to change notification settings - Fork 38
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
Magic parsing performance #253
Comments
Sorry about the extended delay in this reply, and thank you for profiling and providing a good test case! While it is possible for magic to be a byte string of arbitrary length, this is unusual, so it does seem reasonable to me at a minimum to use some small inline allocation strategy for this error type instead of always boxing the result. There is an optimisation for magic that exists in codegen, but only for unit enum. Without thinking too hard, it makes sense to me to do something similar here. A workaround for now to improve performance could be to use #[binread]
#[br(import(magic: u16))]
enum Record {
#[br(pre_assert(magic == 0))]
Record000,
#[br(pre_assert(magic == 1))]
Record001,
/* … */
}
#[binread]
struct MagicRecord {
magic: u16,
#[br(args(magic))]
record: Record,
} This is less pleasant, but is at least something you can do right now to avoid both the allocations and the re-reads of the magic. |
No worries. I've been able to solve most of the performance problem I had, since as opposed to the test case the variants in my data aren't evenly distributed so I could put the most common ones first(as noted in the docs). There's still some unnecessary overhead but much less than before. However, having thought some more about this the root of the problem is a mismatch in how I would want/thought Apart from this issue binrw has been great really great to work with, thanks for working on it |
Sure, I understand the confusion. In binrw, it isn’t necessary for magic to always be the same type (or even to exist at all, for fallbacks). Doing what you expect of reading the magic value once and then matching a variant would be a very desirable optimisation for the case where there are multiple variants that use the same type of magic. This optimisation exists for reading unit enum already (I actually forgot that it was only implemented for those, so was initially a little surprised about this ticket). binrw codegen certainly should be capable of supporting more optimisations like these without too much trouble, it is simply a matter of having someone motivated to complete the work. |
I made an initial attempt at optimizing data enums. There's some errors that would need to be fixed and it needs to cleaned up. It also doesn't support |
I'm using binrw to parse a format with an enum with around 300 variants(all using magic directives) and with files that can contain up to 40 000 items. The performance when parsing files weren't what I expected, even if I add
return_unexpected_error
, although that did help. I did some profiling and saw that there's a lot of allocations happening as part of the magic parsing due to the boxed value in the generated error. As an experiment I tried replacing theBadMagic
error returned by themagic
function withNoVariantMatch
(which only contains the position) and saw a +70% decrease in parse time. Considering that the value isn't even used whenreturn_unexpected_error
is enabled this seems like a good opportunity for optimization. It may be possible to improve forreturn_all_errors
as well since the possible data types formagic
are quite small.I've created a repo with a simple reproduction. If you replace
BadMagic
withNoVariantMatch
in binrw you should see the difference in performance.I'm would also be interested if there's any performance to be gained by not re-reading the magic value for each variant. In my case I'm parsing from in-memory, but there's a lot of reading and seeking being done that's unnecessary. It would require a larger change so I've not done any testing but might be worth looking into.
The text was updated successfully, but these errors were encountered: