-
Notifications
You must be signed in to change notification settings - Fork 30
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
MappedBinaryIO, Testimplementation for alternating KaitaiStream - maybe #76
Comments
#67 might be related |
Python has support of native typed arrays. Though I'm not sure they interplay well with It seems that the current code still doubles memory usage since it parses native types and reads them into fields of a Python object. If we just wanna use memory mapping, would just passing a |
Well, yes. I guess 50% of the performance deficit is more a bad (and repetitive) implementation. I had exceptional results with reading. But as soon as it comes to writing the problems begin. First of all, you cant mmap an empty file on windows which is really annoying. About Integrating it into the current Runtime: Yes, should be possible but that would require changes to the Compiler aswell. I could figure out some prototypes for mmaped kaitai in Python but (don't laugh, 3 weeks ago i didn't even know what scala is. I tried changing stuff around a bit but (dont get me wrong), the current Compiler is really messy (for me). About the arrays: About the memory: Currently im using ACCESS_COPY and also created some kind of buffer with the write methods. I guess one could easily reduce memory usage by changing it to write. Also closing the mmap file and the fileIO object is a bit wonky. As far as I can tell you need the fileIO object just for the mmap creation. After that It can be dropped. |
But also there is ctypes with support if C-structs and arrays of them and I wonder if there is any benefits of utilizing them. Well, I didnt touch ctypes anymore because it has no "proper" (convenient) way of handling endianess |
So, i prepared some (hopefully comparable) approaches. If someone wanna play around with it:
|
Handling endianness is simple, if we assumme there are only 2 of them: if it is not the same as your hardware one - swap. In x86 CPUs since i486 there is a dedicated instruction for this, BSWAP. In modern CPUs starting from some editions of Pentium 4 it takes 1 uop, has latency and inverse throughput of 1 and occupies an ALU unit only. In other words: swapping endianness should be fast.
I didn't mean that. I meant that by using self.version = self.reader.read_value("u2le") you kake a copy. When we read only inline uint16_t field(){
return std::bit_cast<our_struct *>(raw_ptr_in_mmap)->field;
} can be possible, it occupies 0 additional memory, we read the data directly from mapping on every access. When the data is BE, we just add |
Yes, i understood later. I played around with following approach. That should do exactly what you mean:
Which should also be easy to integrate Bad thing is just that it limits the IO to mmap or memoryview (which looks insanely good after i figured out how to properly use it) |
The above code with 1k iterations took 0.00024369192123413087 Which is 8 times faster than everything else i tested |
Thanks for the Info by the way, really interesting! |
If you want implement serialization respecting constraints, the things become tricky. We cannot write directly into the mmap - the writes can violate constraints and require recalc. We cannot do checks before writes - some changes require atomic and coherent changes in multiple places. We cannot and shouldn't dumbly do copy-on-write - we wanna minimize the amount written. In other words objects stop being proxies to raw memory and start have complex logic with memory allocation, deallocation, constraints checking, dependency tracking, dependent values recomputation, SMT- and other symbolic solving, moving memory areas, scheduling and maybe even bytecode. Some ideas about implementing that were described in kaitai-io/kaitai_struct#27 . Although none of it is required immediately and can be added gradually in indefinite future, it is important to remember that this can be needed in future, and so design the way that it would be possible to add it in future without complete redesign. |
Considering your answer it looks like my Tests dont really help. Atleast this way. @KOLANICH
Integration was a bit wonky but all in all its a really small change (doesnt even interfere with the rest)
|
Another experimental approach:
@KOLANICH, this is nearly what you wanted. The mmap itself is only as big in memory as the structured data given. Next step would be avoiding to mmap and just to collect a dict or something of size + offset, for an abstract IO |
I actually have a working memoryview KaitaiStruct embracing zerocopy and its init and io is 40% faster than the current implementation BUT: Achieving this need a nearly complete rewrite of the python runtime and of the generated Classes(less important, gain was only like 10%) Long story short, case closed for me |
Edit: forget about it, its nonsense So this topic didn't let me be happy. (It became a personal topic, dont worry, i made this for me :D) Good News:
So i tried a lot of methods to create some kind of "offset-size" mapping. The idea would be, that (in this example): This way it should be possible to avoid most memory alloc. Would love some feedback (not in terms of implementing it into Kaitai but rather what you think about the method) class MIO_IO(Cursor):
def __init__(self, io_stream: Cursor) -> None:
self._io: Cursor = io_stream
self.size = os.path.getsize(r"D:\Dev\MIOStream\MIOStream\files\test.dat")
self.index_map = (ctypes.c_uint64 * (self.size // 32))()
@classmethod
def from_file(cls, file: str) -> "MIO_IO":
with open(file, 'rb') as f:
m: Cursor = Cursor(mmap.mmap(f.fileno(), 0, access = mmap.ACCESS_READ))
return cls(m)
def create_index(self, chunk_size: int):
chunks = self.size // chunk_size
self.index_map = (ctypes.c_uint64 * chunks)()
for i in range(chunks):
self.index_map[i] = self._io.tell()
self._io.seek(chunk_size, 1)
def main():
file_path = r"D:\Dev\MIOStream\MIOStream\files\test.dat"
M = MIO_IO.from_file(file_path)
M.create_index(32)
|
Hello everyone,
im decently new to working with binary files and KaitaiStruct. I love it but i unfortunately dont like the ReadWriteStruct.
I created a different approach based on the Python Runtime and i would like to have some feedback about possible improvements (and / or / or why) thats not suitable for Kaitai.
Please be kind with me, thats my first "package" and definitely the first mmap impl. i created.
The overall intention is (if you guys like the approach) that i would try to convert it and improve it further ( and create a new /different compiler-mode).
If you see mistakes or not logical implementations, please tell me. I want to learn!
Edit1: Note, there are obviously a lot of functions missing that Kaitai needs. This is just my usecase i currently build this around. Take it as a Prototype for a possible mmap approach.
Edit2: About the performance: I cant really say much at the moment but just by testing this, i already noticed a gain in speed (IDE runs the code a lot faster). Thats obviously a really bad comparison but if someone is interested, i could do tests aswell
and a testfile class:
The text was updated successfully, but these errors were encountered: