-
Notifications
You must be signed in to change notification settings - Fork 845
Add interface for NetVC services #9482
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
Conversation
|
The virtual member function I added for the tunnel metrics may show a pattern that could be used for this: https://github.com/apache/trafficserver/pull/9403/files#diff-28fd9480778c3af26dbe33816ff4f4d35a616444bb9d19adaecd6735e29ca546R365 |
|
|
|
To keep changes minimal, I suggest this pattern: https://godbolt.org/z/E86E4zxGs . |
I'd say it's a worse version of |
iocore/net/NetVConnection.cc
Outdated
| } else { | ||
| return nullptr; | ||
| } | ||
| } |
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.
This will not work properly, for reasons illustrated by this example code: https://godbolt.org/z/bGofcYhse . Not that f() and g() do not have the same assembly code. With multiple inheritance, there is no known implementation (and probably impossible) where all the base classes to have the same (start) address as the derived class. Even with no multiple inheritance, I think it's undefined behavior to assume that (direct and indirect) base classes have the same address as the derived class. Although the de facto portability of this assumption is very high in that case.
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.
Ok, looks like this approach doesn't work at a minimum. What about other approaches? Do you see any technical issues?
|
There is some chance that this would be faster than dynamic_cast: https://godbolt.org/z/fvzWsxj5T . |
I don't think we need to cast MixinA to MixinB. In that sense this should be enough, it's so naive though. https://godbolt.org/z/fjnMxfj85 But your code suggests that I could store pre-casted pointers into a map instead of just having supported types in a set. I wonder if this kind of ways can be ten times faster than dynamic_cast. Only 5% faster way is not a win here. |
|
This would be faster: https://godbolt.org/z/66YofcchT |
|
Sure, but again, if we do that the base class has to be modified every time we add new mixins, and the base class has to know all mixin names. |
|
Not as clean as |
6522558 to
5d97947
Compare
|
[approve ci autest] |
|
[approve ci autest] polite_hook_wait failed. |
|
[approve ci autest] polite_hook_wait failed again. |
|
[approve ci autest] |
Were you able to do any benchmarks to demonstrate the performance effect? |
|
My 2c o the API here is that there's too great a reliance on always having to match the enum and type pointer. You need to do it in every place that registers a helper, and every place that consumes one, which is error-prone. It would be great if the mapping was in exactly one place. For example, you could keep the mapping in a template specialization: template <typename T> T* NetConnectionService(const NetVConnection *);
template<> ALPNSupport* NetConnectionService(const NetVConnection * vc)
{
return static_cast< ALPNSupport*>(vc.get_thing(TLS_ALPN))
}
/// etc ..This approach could also let you get rid of the nil checks: template <typename T, F>
WithNetConnectionService(const NetVConnection * vc, F&& handler)
{
T * svc = NetConnectionService<T>(vc);
if (svc) {
handler(svc)
}
} |
|
I'm going to abstain on this one. The clean way to get rid of dynamic_cast is to move the distinct behavior for derived classes into the derived class. But it's very difficult to do that in this case. I feel like this is adding complexity, for only a speculative benefit of significantly improved performance. Maybe find another reviewer, or start a thread on the dev mailing list. |
de78c49 to
805ae67
Compare
Before (w/o this change)After (w/ this change)
|
|
How about this approach? |
|
None of the dynamic_casts need casting from a base class to another base class. |
X corresponds to NetVConnection, and Y1, Y2, ... correspond to TLSTunnelSupport, TLSSNISupport, etc. D1 would correspond to some class like SSLNetVConnection. |
|
Oh you mean the mixins. What's the advantage of your code? Looks like doing static_cast in a complicated way. |
|
I suggest using this alternate approach. It only requires each NetVConnection object to have an additional pointer, rather than an array of pointers: This performance test indicates the performance would be the same or slightly better: |
IIUC this requires the use of inheritance, where the existing approach allows the option of composition. I agree that is would be nice to store fewer pointers though. |
Composition is an interesting idea. It can reduce the size of Unix/SSL/QUICNetVConnection. For example, if TLS early data is disabled by setting, we don't need to have TLSEarlyData and related variables in the first place. |
|
OK, here's composition, and the option of multiple services with the same type. For a total of three shrubberies. |
|
Looks like This PR touches many places and I don't want to keep this open for long time to find the best way (there's already a conflict). It looks like we all agreed on the interface at a minimum. I'm going to make the changes James suggested, so we can start using the new interface. |
45561f2 to
fa45f3b
Compare
No. If the service object is not within the derived object's memory footprint, there would not be a fixed offset to it. You could perhaps use std::optional. |
|
I think it's in a good shape now, and I'd like to merge this if there's no blocker. Let me know if there are comments/issues that are not resolved yet. |
jpeach
left a comment
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.
When you squash the commit, please add a summary of the performance benefit from the discussion here.
| } | ||
|
|
||
| inline void | ||
| NetVConnection::_set_service(enum NetVConnection::Service service, void *instance) |
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.
Note that this isn't type-safe. I expect it would be possible to make it typesafe if you had a template that mapped the enum to the type directly.
Co-authored-by: James Peach <jpeach@apache.org>
This is a follow-up on apache#9482. I missed one place on the previous PR.
This is a follow-up on apache#9482. I missed one place on the previous PR.
This is a follow-up on #9482. I missed one place on the previous PR.


TLSomethingSupport, which enables using SSLNetVC and QUICNetVC in the same way, requires dynamic_cast at many places. I don't know how much it affects performance, but this is one of ways to remove the dynamic_cast.
It still relies on RTTI, so maybe it's not as fast as you want, but I guess it's faster than looking up vtable.We probably want to avoid std::unordered_map here, and I'm going to change it later if we go this way. Current code is just to show the idea.To remove the dynamic_casts, I added an array to store pre-static_cast-ed pointers to NetVConnection.