-
-
Notifications
You must be signed in to change notification settings - Fork 55
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
Specialize bytes #278
Specialize bytes #278
Conversation
I'm getting errors on the following lines:
For these tests, not sure why: # use deku::prelude::*;
# use std::convert::{TryInto, TryFrom};
# #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
#[deku(type = "u32", bytes = "2")]
enum DekuTest {
#[deku(id = "0xBEEF")]
VariantA(u8),
}
let data: Vec<u8> = vec![0xEF, 0xBE, 0xFF];
let value = DekuTest::try_from(data.as_ref()).unwrap();
assert_eq!(
DekuTest::VariantA(0xFF),
value
);
let value: Vec<u8> = value.try_into().unwrap();
assert_eq!(data, value); Example: # use deku::prelude::*;
# use std::convert::{TryInto, TryFrom};
# #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
struct DekuTest {
#[deku(bytes = 2)]
field_a: u32,
field_b: u8, // defaults to size_of<u8>
}
let data: Vec<u8> = vec![0xAB, 0xCD, 0xFF];
let value = DekuTest::try_from(data.as_ref()).unwrap();
assert_eq!(
DekuTest {
field_a: 0xCDAB,
field_b: 0xFF,
},
value
);
let value: Vec<u8> = value.try_into().unwrap();
assert_eq!(data, value); |
@sharksforarms @constfold lmk what you think |
src/impls/primitive.rs
Outdated
|
||
let (bit_slice, rest) = input.split_at(bit_size); | ||
|
||
let bytes: &[u8] = bit_slice.as_raw_slice(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what I want in that comment. But...
the removal of this branch for bytes
if pad == 0 && bit_slice.len() == max_type_bits && bit_slice.as_raw_slice().len() * 8 == max_type_bits
Can we really do this? What if bit_slice
is not byte aligned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be good given:
let bit_size: usize = size.0 * 8;
-- will always be byte aligned- we check
bit_size > max_type_bits
&input.len() < bit_size
before callingsplit_at
two error messages both said:
It looks like the same as #224, caused by alignment issue(might be the one I mentioned above). |
Hey @wcampbell0x2a, nice work! and 👋 @constfold nice to hear from you too. This is looking great (thanks for the benchmarks!) I don't have any comments apart from the test cases, I can offer my understanding on why they're failing.
So, the issue with these tests is that the changes no longer consider padding when reading: Original code: let value = if pad == 0
&& bit_slice.len() == max_type_bits
&& bit_slice.as_raw_slice().len() * 8 == max_type_bits
{
// if everything is aligned, just read the value This section of code is an optimisation for when we have exactly what we want. The above test using this PR, will read 2 bytes and try to convert that slice to a u32 and fail (u32 needs 4 bytes). To fix this, we'd need to bring padding back some way or another. I'm thinking it may be possible to pad using arithmetic instead of allocation too. Maybe a later optimisation. |
Could we add a Just trying to reduce as many branches as I can for performance. |
If we can do that at compile type that'd be great, I'm not sure we can though... |
Current benchmarking 📈
|
One of the CI failures is from
which looks to be a duplicate of: rust-lang/rust-clippy#9413 |
Thanks! There was a couple more TODO i added in regards to code duplication that should be addressed before merging |
I think I fixed those now. |
Remove Size in favor of a BitSize and ByteSize. This allows the Deku{Read/Write}(Endian, BitSize) and Deku{Read/Write}(Endian, ByteSize) impls to be created and allow the ByteSize impls to be faster. Most of the assumption I made (and the perf that is gained) is from the removal of this branch for bytes: let value = if pad == 0 && bit_slice.len() == max_type_bits && bit_slice.as_raw_slice().len() * 8 == max_type_bits { See sharksforarms#44 I Added some benchmarks, in order to get a good idea of what perf this allows. The benchmarks look pretty good, but I'm on my old thinkpad. These results are vs the benchmarks running from master. deku_read_vec time: [744.39 ns 751.13 ns 759.58 ns] change: [-23.681% -21.358% -19.142%] (p = 0.00 < 0.05) Performance has improved. Found 8 outliers among 100 measurements (8.00%) 4 (4.00%) high mild 4 (4.00%) high severe See sharksforarms#25
Remove DekuRead for BitSize, and use same as other through macro generation
56b8e07
to
bbd3663
Compare
Thanks! Release pending :) |
Remove Size in favor of a BitSize and ByteSize. This allows the
Deku{Read/Write}(Endian, BitSize) and Deku{Read/Write}(Endian, ByteSize)
impls to be created and allow the ByteSize impls to be faster. Most of
the assumption I made (and the perf that is gained) is from the removal
of this branch for bytes:
See #44
I Added some benchmarks, in order to get a good idea of what perf this
allows. The benchmarks look pretty good, but I'm on my old thinkpad.
These results are vs the benchmarks running from master.
See #25