-
Notifications
You must be signed in to change notification settings - Fork 51
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
Expose internal buffers to writers #901
Conversation
5d6a2f1
to
a5b5413
Compare
9c830a3
to
5586e73
Compare
92e29da
to
242cb1d
Compare
c823946
to
d3e8f15
Compare
1368ef8
to
9db8694
Compare
7da46a0
to
f8d2366
Compare
UserFlush, | ||
/** | ||
* Default mode, flush everything that can be flushed | ||
* Does not need to uphold user-level guarantees about clearing and filling |
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 don't understand the 2nd sentence yet:
Are you saying that this cannot check the API contract we have with the user, aka that the user must have given us valid buffers and they are ready to use at this point?
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've clarified documentation now by introducing a concept of flush points. Difference between both modes is that UserFlush defines a flush point and FlushEverything InternalFlush does not.
test/SerialIOTest.cpp
Outdated
* Hijack the functor that is called for buffer creation if the | ||
* backend doesn't support the task to see whether the backend | ||
* did support it or not. |
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.
Can you please split this into two sentences? It's a bit hard to parse for me :)
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.
Should we make this lambda a helper function? Looks like a generally useful implementation that people would use?
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.
Can you please split this into two sentences? It's a bit hard to parse for me :)
Will do
Should we make this lambda a helper function? Looks like a generally useful implementation that people would use?
I'm not sure about it.. This sidechannels the return value (the boolean) as a value caught-by-reference. Can we write this in a way that would actually be a good API?
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.
Will do
Done
6864ced
to
c348616
Compare
@franzpoeschel can you please rebase this one? :) |
UserFlush: Exposed flush point, buffers are read from / written to FlushEverything (todo: rename to InternalFlush): Flush everything except for things that are only allowed to be flushed at a flush point. Attributes must be flushed. SkeletonOnly: Guarantees to setup the openPMD hierarchy in the backends. Datasets are not created yet.
47f3056
to
a5dd63e
Compare
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.
Looks already in great shape! Notes inline :)
@@ -1041,7 +1068,9 @@ namespace detail | |||
std::vector< std::unique_ptr< BufferedAction > > m_buffer; | |||
std::map< std::string, BufferedAttributeWrite > m_attributeWrites; | |||
std::vector< BufferedAttributeRead > m_attributeReads; | |||
std::vector< std::unique_ptr< BufferedAction > > m_alreadyEnqueued; |
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.
Should we add further doxygen strings to these member variables?
The amount of member variables indicates we are doing quite involved things here :)
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.
Good point, will do
{ | ||
switch( iterationEncoding() ) | ||
IOHandler()->m_flushLevel = level; | ||
try |
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.
Here and below: why do we use exception handling at this point and rethrow another exception?
I am just concerned that we absorb legit exceptions from backends, e.g. if a low-level ADIOS/HDF5 operation fails.
The try-catch pattern on this high level looks a bit duck-tape-y to me.
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.
The purpose of this is to emulate the same thing that the Python or Java finally
keywords do. This does not absorb exceptions from a layer below, this construct does some cleanup and passes the exception on:
Rethrows the currently handled exception. Abandons the execution of the current catch block and passes control to the next matching exception handler (but not to another catch clause after the same try block: its compound-statement is considered to have been 'exited'), reusing the existing exception object: no new objects are made.
(https://en.cppreference.com/w/cpp/language/throw)
The purpose is to ensure that the base state is restored even if an exception is thrown.
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.
Perfect, thanks!
Co-authored-by: Axel Huebl <[email protected]>
695b3ee
to
d4e5672
Compare
Co-authored-by: Axel Huebl <[email protected]>
6cea2ea
to
9884dc1
Compare
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.
Thank you for the great PR, this is ready to go! 🚀 ✨
Based on #904 (see below for the reason), for comparison: franzpoeschel/openPMD-api@topic-pipe-executable...franzpoeschel:topic-spanThis makes the functionality provided by
adios2::Variable::Span<T>
available to users of the openPMD API.Use case: If in the writing application, write buffers are newly allocated right before
RecordComponent::storeChunk()
(as opposed to passing buffers tostoreChunk()
that already exist in the application), this PR allows the buffer to be allocated by the openPMD backend (e.g. in ADIOS2: provide a view into the serialization buffers). In such a case, this may avoid memcopies, ideally cutting memory usage in half.Possible benefitting applications:
UPDATE: I've implemented this in a PIConGPU branch, this diff gives an example on usage.
TODO:
Failing test: I can reproduce this with ADIOS 2.6.0, ADIOS 2.7.0 does not have this issue. Hence, this needs to wait until we bump the required ADIOS2 version.nah, that one was on me actuallyopenpmd-pipe.py
ing the HDF5 git sample crashes)openpmd-pipe
. So, merge that first.Span
interface in C++ to be more similar to the one in Python? Maybe this silent buffer reallocation thing is a bit too much to hide it automatically behind a Span interface.. ?