-
Notifications
You must be signed in to change notification settings - Fork 124
Reducing memory footprint in StreamIndexedIO #228
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
Reducing memory footprint in StreamIndexedIO #228
Conversation
…nter to the global Index and to the low level DirectoryNode. Adding a specific class for DirectoryNode that holds the information loaded from the index. Adding a member m_nodeType in NodeBase to distinguish derived classes without adding virtual methods.
…ield. Using char instead of the enums in the structs to compact members in one word. Original struct sizes were StreamIndexedIO::Node 104 bytes and DataNode was 56. Current struct sizes are DirectoryNode 56 and DataNode 40 bytes.
This does not affect the class size and should not break binary compatibility. As a consequence the Node class reduced from 32 bytes to 16 bytes (not derived from RefCounted anymore).
… data is small enough and avoid the big DataNode struct (40 bytes).
… SubIndexNode (24 bytes). This helps on the memory requirements for opening a file with a large amount of stored Objects. In particular, large LinkedScenes.
… for the purposes of filtering child entries by type.
Hey Lucio - impressive reductions! Unfortunately I'm seeing a performance regression when testing some multithreaded access in Gaffer. Here's the script I'm using to test, along with some measurements I took with it in the comments at the bottom. Could you see if you can reproduce that there?
I've only taken a quick look at the actual code so far - perhaps you could look into this first and then I'll take a more detailed look? |
You can get the bunny here if you don't already have him : http://imageengine.github.io/gaffer/resources/caches/bigBuckBunny_001.scc.gz It'd be interesting to try the same with some production assets... |
…he hierarchy of Nodes. Added a boolean in each Directory node that will be true only if there's a child that is SubIndex and only uses mutex on these locations. Also, avoids keeping the mutex locked while reading the subindex or during deallocation of duplicated Directories.
Good one John! With the latest change they are in pair with the current trunk Could you double check on your end? |
And here some production examples: hugeLayout: LSCC 7Mb (plus sub-layouts) animated asset: SCC 8Gb huge geo: SCC 104Gb |
That's an improvement for me too - still not quite as quick as master but within a % or two. Are your [old] measurements from master or from this branch before your latest fix? Any idea how the huge geo is so quick in comparison to the others? |
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.
I think we should definitely do this before merging - the whole Node vs NodeBase discrepancy is quite confusing.
I might be wrong as I haven't looked at everywhere they're used, but generally I feel that all the Node classes could do with encapsulating their data a bit more. I don't really understand the codebase fully, but it seems that a lot of the members are hanging out in public as non-const, whereas my guess in many cases is that they aren't intended to change after construction, or only in specific circumstances. Do you think it'd be worth tightening this up a little to reassure the naive onlooker that they aren't going to change and to have the compiler do a bit more checking for us? |
This is of no use to us now, but it's good to know that C++11 allows the size of an enum to be controlled - that'd be handy for those spots where we've been forced to lose type safety and store them in a char : http://www.cprogramming.com/c++11/c++11-nullptr-strongly-typed-enum-class.html I wonder when our 3rd party dependencies will allow us to move to a modern enough compiler to use this stuff? |
Adding some comments to explain better the rationale behind them.
I believe I've addressed most of your notes John. I think it's way clearer for the naive onlooker. |
Thanks Lucio! Leaving the Node class rename till later seems like the right thing to do for now - sorry I hadn't noticed that it was exposed via methods in the API. |
Reducing memory footprint in StreamIndexedIO
As scenes get heavier and deeper, the memory overhead of the data structures holding the hierarchy of the internal nodes in the StreamIndexedIO becomes significant. The structure is a tree of StreamIndexedIO::Node classes (104 bytes* each + contents of children map ) with DataNodes (56 bytes*) where data is saved.
With the following commits I've maintained the file format as is, and also binary compatibility (please review my third commit on that). And from my tests, performance was not affected. The memory consumption reduction varied in my tests from %20 to %70:
The idea behind these changes were to have more Node classes that are specialized on particular cases and therefore don't need as many bytes. In order to do that, my first step was to change the StreamIndexedIO::Node class to behave as "private MemberData" class (kept the name for binary compatibility), that holds the pointer to the underlying Directory node and another pointer to the shared Index.
Then I've created this new class hierarchy:
NodeBase (16 bytes_)
|- DataNode ( 40 bytes_ )
|- SmallDataNode ( 24 bytes* )
|- DirectoryNode (56 bytes* )
|- SubIndexNode ( 24 bytes* )