-
Notifications
You must be signed in to change notification settings - Fork 423
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
[POC] Baggage API : return Baggage
instead of shared_ptr<Baggage>
using PImpl idiom
#836
Conversation
Codecov Report
@@ Coverage Diff @@
## main #836 +/- ##
==========================================
+ Coverage 95.50% 95.53% +0.03%
==========================================
Files 156 157 +1
Lines 6620 6632 +12
==========================================
+ Hits 6322 6335 +13
+ Misses 298 297 -1
|
Nice work! One question: Did we have performance benchmarks for this like we do for span processors? If not we should open a bug going forward to check performance of baggage propagation. |
Good point. Will raise a bug for this. |
Baggage
instead of shared_ptr<Baggage>
using Pimpl idiomBaggage
instead of shared_ptr<Baggage>
using PImpl idiom
|
||
return ret; | ||
} | ||
std::string ToHeader() const { return baggage_impl_->ToHeader(); } |
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.
Since this is in API, is this std::string
type ever going to be exposed across DLL / Shared Library boundary? Even if it's a private method, isn't this still something where we'd rather return a nostd::string_view
instead of std::string
?
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.
It's a non-virtual function, so it should be safe to return std::string
, it won't break ABI stability. Though we can change it as below had it been a virtual function:
void ToHeader(nostd::string &header) {
}
// Store entries in a C-style array to avoid using std::array or std::vector. | ||
nostd::unique_ptr<opentelemetry::common::KeyValueProperties> kv_properties_; | ||
Baggage(BaggageImpl *baggage_impl) : baggage_impl_(baggage_impl) {} | ||
nostd::shared_ptr<BaggageImpl> baggage_impl_; |
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.
Maybe I'm missing something: the shared_ptr
is wrapped now and not exposed, but isn't it the goal to provide a way to get completely rid of shared_ptr
usage? How would that work with this solution?
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.
Yes, getting rid of shared_ptr
, and dynamic allocation is the ideal solution, but that won't be easy to implement as the same baggage can also be stored in Context
.
The current approach removes the control of smart pointer management away from external users. It is inspired from:
opencensus
: https://github.com/census-instrumentation/opencensus-cpp/blob/9461de16eef2286a4a062e890548ab148aa94c55/opencensus/trace/span.h#L194
and
https://vector-of-bool.github.io/2018/12/02/smart-pointer-apis.html
Do you see any better approach to handle it? I saw your comment on returning unique_ptr
and convert to shared_ptr
later. How can that be done, as these would be two different pointers. The unique_ptr
would get invalidated once it is moved to shared_ptr, and the user would still be trying to use unique_ptr
.
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.
So, in essence, we are not really making it better-perf for any of the default exporters.. we making it worse by creating yet another abstraction layer with a shared_ptr. Okay. 🤔
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'd like to see a Google Benchmark run, for a synthetic loop with some work in it, before and after. This issue would be a great start to do the initial set of measurements #837
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.
Yes true. In fact, it adds another layer of redirection, along with a small cost incurred for storing <shared_ptr> as a data member. This should be a solution only if we plan not to use smart pointers across API. It's more of a design decision than a performance solution.
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.
Let's run some numbers. I am also interested in synchronous, non-batching, streaming exporter. And in good numbers.
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.
So, in essence, we are not really making it better-perf for any of the default exporters.. we making it worse by creating yet another abstraction layer with a shared_ptr. Okay.
I kind of agree, I don't see how this improves things. We still have a baked-in shared pointer which we hide from the user, and the user has no way to change that.
I don't see any benefits of this refactor. If it's a purely stylistic effort, I have no strong opinion about that.
Do you see any better approach to handle it?
I see two possible ways:
- Implementing a purely stack-based solution ourselves. This would require a re-implementation of the underlying key/value data structure.
- Giving the user means so they can provide their own baggage implementation, which follows their own memory management strategy.
Maybe there are other ways not coming to my mind. If we go with (2), the same approach could also be used to avoid using shared pointers for spans.
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.
Nice work, thanks.
static constexpr char kMembersSeparator = ','; | ||
static constexpr char kMetadataSeparator = ';'; | ||
|
||
class BaggageImpl |
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 this be hidden? Maybe have an "internal" as part of the namespace and we add a rule that everything in the internal package is private? "baggage::internal::BaggageImpl"?
I think perf numbers presently show that this refactor isn't making anything better (it is x1.7 times worse perf for a barebone span)... Also it takes away the partial ownership semantics. I think it'd be best if we carefully allow additional API, maybe in a separate namespace? To address the ask for a value object return type without refactoring / breaking of what we already got working in
Can you elaborate on those two points, if maybe I'm misunderstanding / misinterpreting something.. Can we take another stab at this after GA? Options to consider:
I'm quite tempted to set the status on it to |
These are the perf numbers for baggage api ( the earlier one posted at #828 was for Span create api ) with and without PIMP idiom. Existing Implementation ( without PIMPL):
New Implementation ( this PR) using PIMPL
There is no significant performance difference in both the approaches, which is expected as we still use |
Not to merge for now - this is proof of concept for Baggage Implementation using Pimpl Idiom, as part of discussion #828
For significant contributions please make sure you have completed the following items:
CHANGELOG.md
updated for non-trivial changes