Conversation
There was a problem hiding this comment.
I am worried about all this allocator business creeping to user code. How about we have an O2 specific smart pointer which hides all this? e.g.:
o2::ptr<std::vector<char>>
which internally holds a std::vector<char,o2::memory_resource::polymorphic_allocator<o2::byte>>
There was a problem hiding this comment.
sounds a bit complicated, introduces yet another abstraction layer for something which is standard and introduces pointer semantics for vector (which already is a smart pointer of sorts). I think an alias would be enough, sth like std::pmr::vector.
I think it is not more complicated to remember to pass an additional argument to a constructor than to go through the logic of registering the data in a framework. We should give the users some credit ;)
|
@mkrzewic : Could you add some more explanation of what is the target use here? Is it to support shared memory transport in DPL? Or being able to adopt another vector or the like? Thanks. |
|
@sawenzel I updated the description. The point is to transparently be able to take advantage of shared memory/ofi transports without copying data while just using standard containers (currently only std::vector and std::string would make sense afaik, in the future - who knows :)). So if you use an |
|
also: when developing new containers we would only have to stick to the STL container requirements making the development standards-compliant and at the same time be "message-efficient" with no extra effort. |
|
I think we need to discuss this next week. IMHO, esposing allocators is as bad as an idea as it can possibly get. Data own by the framework should be created via the framework.
…On 29 Nov 2018, 15:23 +0100, Mikolaj Krzewicki ***@***.***>, wrote:
also: when developing new containers we would only have to stick to the STL container requirements making the development standards-compliant and at the same time be "message-efficient" with no extra effort.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
this PR does not expose allocators (any more than they already were), see as for the ownership - modern C++ practice is to keep ownership with the data since move semantics allow us to do this efficiently - this way we don't have to have magical entities to manage resource lifetimes - so in that respect I cannot disagree more with your statement. |
|
You were exposing the allocator in the user code, as in "user has to know the allocator type", as far as I remember. This is indeed not the case anymore and using something like the The advantage of having an The reason for having the Framework / DPL to create the object, rather than doing it in vacuum is that there is no chance to mistake and create the wrong type of vector. To me: auto r = ctx.outputs().makeVector<Clusters>(Output("TPC/TRACKS/0"), 10);is better than: auto v = o2::vector<Clusters>{10};
auto r = ctx.outputs().adoptVector(Output("TPC/TRACKS/0"), v);You expose less of the details and you keep everything in one place. If you really do not like the Apart from that, which we can keep for a later discussion, I would drop the |
it is the same, just different wording, user does have to know where the data is supposed to be going. Whether you call it allocator or output channel, I don't care, things can always be aliased with some dumbed down name.
I think this is superfluous, an allocator aware container already IS a wrapper around data, and has everything that is needed for efficient data transfers. No need to hide everything from users.
i'm not suggesting to do it in vacuum, just suggesting a more natural syntax (see previous post): this is just plain C++, no need to invent some additional syntax and logic for it.
i have no problem with ctx.outputs() being explicitly visible - other than the confusing naming (plural suggests you get some collection of outputs, but you get a DataAllocator (i think), all that is hidden by everything is auto, so hard to actually find the thing you are getting)
I have no strong preference here, but I think there is no need to hide the fact that the vector is a pmr vector. Plus it would make it easy to switch to std::pmr::vector when that gets implemented in the standard libraries. |
|
now I come to think of it: maybe the make* methods that return something managed (like the ones that call adopt(...) internally) should return by pointer, not by value (to avoid dtors being called on exception) and not by reference (confusing since value semantics suggest ownership). |
|
No, there is a huge difference semantically by having an allocator, an output channel or anything related to transport layer and specifying an output datatype, which does not know anything about how data gets transported to the rest of the consumers. The example you have: auto v = o2::vector<Clusters>{ctx.outputs().getTransportAllocator(), Args...}will not be enough for the case in which you have multiple outputs or multiple transports. If at lower level as an implementation detail we want to use
These requirements are there since the beginning and I think they are turning out to be a good idea. I am happy to improve the API and remove confusions, but I think those principles should remain intact. Regarding the naming of |
of course it is enough: auto v = o2::vector<Clusters>{ctx.outputs().getTransportAllocator(Output("TPC/TRACKS/0")), Args...}something like that will take care of selecting the proper one. We should probably also avoid specifying the output by string since it is supposed to be predeclared already. Also note there is no need to specify the size since it will either resize itself or user calls reserve() - it is a std::vector after all.
sure, nothing wrong with it, I don't see how my proposal breaks it. I'll reshuffle the code a bit to make it a bit more clear.
should be possible, but i see a funny interference with std::vector after changing that - in some cases o2::vector gets precedence in implementation files which use "vector", even after a "using std::vector" statement at the beginning... |
|
Regarding your example, I still prefer: auto v = ctx.outputs().makeVector<Cluster>{Output("TPC/TRACKS/0")), Args...}
// or:
auto v = ctx.outputs().make<o2::vector<Cluster>>{Output("TPC/TRACKS/0")), Args...}
// or:
o2::ref<std::vector<Cluster>> v = ctx.outputs().make<std::vector<Cluster>>{Output("TPC/TRACKS/0")), Args...}over: auto v = o2::vector<Cluster>{ctx.outputs().getTransportAllocator(Output("TPC/TRACKS/0")), Args...}as it is more symmetric with all the cases which we will have which do not support polymorphic allocators (e.g. histograms, boost serialised objects as implemented right now) or which have different mechanisms (e.g. arrow and it's |
|
just to answer you quickly: i'm not aiming at full symmetry, I don't believe it is quite possible and I would not like to be limited to only one possibility. As for the other cases: I don't know ATM, but i'll give it some thought:) |
What do you mean exactly by "created"? Assuming you mean "allocated", then Mikolajs contribution is exactly enforcing the property you stated above. If the framework does not expose its allocator, then the stated property will deny moving data to the framework, or am I missing anything? That is at least the feature I recognize Mikolaj wants to add here? |
|
@dennisklein In an entity-component-system system, the system should be used to create entities and components. They should not come to life autonomously. In this case, a method of DPL should be used to construct an object, allocated with whatever policy (which is really an implementation detail and should not be exposed) and return it to the user. The user should not care / know how the object comes into life and the object itself should not expose how it comes into life or who it belongs to. Ideally I would not even expose the fact that the container is a @mkrzewic given it's syntactic sugar, why not having symmetric sugar and have a specialisation which matches: o2::vector<T> make<o2::vector<T>>(const Output& spec, Args&&... args)isn't what you propose a simply a more verbose and implementation details exposing version of the same thing? I am not against breaking symmetry (we do it actually for pointers and everything else already), but why deliberately breaking the symmetry? |
|
@ktf makeVector looks how it looks like (i.e. slightly differently) because your make<> templates consistently return by reference - which is in my opinion dangerous since the compiler will not warn you if you catch by value - you get a local copy and will not be working with the entity that was registered internally... |
Nono, that's called ROOT. Or in other words: For every type Or in modern ROOT: |
|
yes, I agree with your concern, this is why I was proposing to have an |
|
Well, nevermind.. |
5d6d4a8 to
6ef1e5e
Compare
|
I squashed everything together for an easier read and added observer_ptr (could not find anything like that in boost), still not sure what to do with the makeVector() method... |
Get rid of Stack::getFreefn() - use stl containers with pmr allocator Fix codechecker concerns Clang format Rename o2::memory_resource -> o2::pmr, introduce o2::pmr::vector Advertise explicit return type from makeVector instead of auto Minor update of documentation o2::vector
|
it seems this is stuck. Since a large part of this PR is actually not DPL related and contains a long needed fix of the data header (like the removal of Stack::freefn - which has to go away) I could move the DPL related part to another PR, but then the author of DPLmerger (@gabrielefronze ) will have to fix or remove that code. |
|
removing [WIP], there is not much that can be changed here on short notice. This PR fixes a number of long standing issues related to the data model and the remaining concerns can be resolved in the future if needed. |
|
|
||
| // Do not change this for a full inclusion of FairMQDevice. | ||
| class FairMQDevice; | ||
| #include <FairMQDevice.h> |
There was a problem hiding this comment.
Is this really necessary? There was a big cost in including the FairMQDevice.h due to the boost state machine.
There was a problem hiding this comment.
FairMQ headers do not contain MSM anymore, all MSM is in source files.
There was a problem hiding this comment.
Is it true? I see
#include <FairMQStateMachine.h>which itself includes MSM. When was this changed?
There was a problem hiding this comment.
In May 2018 MSM includes were moved to FairMQStateMachine.cxx.
| // In applying this license CERN does not waive the privileges and immunities | ||
| // granted to it by virtue of its status as an Intergovernmental Organization | ||
| // or submit itself to any jurisdiction. | ||
|
|
There was a problem hiding this comment.
Could you split this is a separate PR, adding a test exercising it? I think this can go in without further discussion.
| return mBlockDescriptors.size() - count; | ||
| } | ||
|
|
||
| int MessageFormat::addMessages(const vector<BufferDesc_t>& list) |
There was a problem hiding this comment.
These changes (adding a std::) can also go in as soon as possible. Could you factor them out in a separate PR?
|
ok, i'll reshuffle. closing in favour of #1581 and following. |
marked as WIP since this is a proposal on how interfaces in DPL to handle STL containers with polymorphic allocators could look like. A proposed use case is in DPLmerger.cxx - it also finally got rid of the last instance of the use of the header:Stack freefn public API. Good riddance.
The use of pmr containers with appropriate allocators is meant to achieve zero copy data exchange in all cases supported by fairmq (including shmem and ofi) in a transparent standards compliant way.