Skip to content
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

Code cleanups and performance optimizations. #1017

Merged
merged 4 commits into from
Feb 24, 2021

Conversation

stebet
Copy link
Contributor

@stebet stebet commented Feb 18, 2021

Proposed Changes

Removing some redundant code and some performance optimizations.

Types of Changes

  • Bug fix (non-breaking change which fixes issue #NNNN)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause an observable behavior change in existing systems)
  • Documentation improvements (corrections, new content, etc)
  • Cosmetic change (whitespace, formatting, etc)

Checklist

  • I have read the CONTRIBUTING.md document
  • I have signed the CA (see https://cla.pivotal.io/sign/rabbitmq)
  • All tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)
  • Any dependent changes have been merged and published in related repositories

@stebet
Copy link
Contributor Author

stebet commented Feb 18, 2021

@bollhals might want to take a look as well.

Copy link
Contributor

@bollhals bollhals left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good to me. Question is though, what will remain in Protocol class? It seems to slowly die out.

projects/RabbitMQ.Client/client/impl/Frame.cs Outdated Show resolved Hide resolved
projects/RabbitMQ.Client/client/impl/Frame.cs Outdated Show resolved Hide resolved
projects/RabbitMQ.Client/client/impl/Frame.cs Outdated Show resolved Hide resolved
}

if (!_closeServerInitiated && frame.Type == FrameType.FrameMethod)
if (_closing)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we switch the common case first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'll involve doing a lot more checks really. This just does the first check on if _closing which is almost always false and then just continues to the transmit. This usually compiles to no code jumping unless the if matches which is usually faster.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this to be cheaper than acquiring a lock either way ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This for sure =)
A quick "is null" check might be as fast as a enum compare 🤔

projects/RabbitMQ.Client/client/impl/MainSession.cs Outdated Show resolved Hide resolved
projects/RabbitMQ.Client/client/impl/SessionBase.cs Outdated Show resolved Hide resolved
@stebet
Copy link
Contributor Author

stebet commented Feb 19, 2021

Looking good to me. Question is though, what will remain in Protocol class? It seems to slowly die out.

Yes. The Protocol class seems redundant to me. I can see what the point of it was but extending the client with a new protocol other than AMQP 0.9.8 is a much bigger task than just adding a new protocol.

Is there a reason to keep the protocol abstraction around @michaelklishin? Seems like it'd be easier to write a new client for a new protocol than to support more than one in the current client.

@bollhals
Copy link
Contributor

Looking good to me. Question is though, what will remain in Protocol class? It seems to slowly die out.

Yes. The Protocol class seems redundant to me. I can see what the point of it was but extending the client with a new protocol other than AMQP 0.9.8 is a much bigger task than just adding a new protocol.

Is there a reason to keep the protocol abstraction around @michaelklishin? Seems like it'd be easier to write a new client for a new protocol than to support more than one in the current client.

Sounds reasonable to me.

@michaelklishin
Copy link
Member

This looks reasonable, thank you. Any benchmarks that demonstrate the improvement for some key workloads?

@stebet
Copy link
Contributor Author

stebet commented Feb 19, 2021

This looks reasonable, thank you. Any benchmarks that demonstrate the improvement for some key workloads?

I'll see if I can do some benchmarks. They are a bit harder to do here since they require actual usages of Connection/Model objects.

{
if (!_closing)
lock (this)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general it is not a good practice to lock on this since this can lead to deadlocks because your are locking the whole instance on which someone external could also lock on. Either bring the lock instance object back or use a compare exchange spin approach?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sessions are internal objects not exposed in any way to the public. While I agree with the general statement, I think one does not always have to follow it if the lock from outside is not possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I know locking on the instance is not recommended but in this case we can be sure that no one external will lock on it, unless through reflection gymnastics but all bets are off at that point anyway.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a fan of least surprises. Even for internal usage. It doesn't necessarily have to be user code. Sometimes over time things slip in. Having a dedicated lock is the safer choice. Yet I'm not hung up on it. Feel free to ignore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a new field just for locking. One more object per connection is not going to make much of a difference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do this?

@stebet
Copy link
Contributor Author

stebet commented Feb 22, 2021

Rudimentary benchmarks for unthrottled publishing with 8 connections:
Before:
Sent 18663500 messages in 60044 ms. 311058 messages per sec.

Calls to ManualResetEventSlim.Wait():
image

After:
Sent 18683500 messages in 60036 ms. 311391 messages per sec.

Calls to ManualResetEventSlim.Wait():
image

@stebet stebet marked this pull request as ready for review February 22, 2021 11:55
@michaelklishin
Copy link
Member

Given that the gain is 0,1% or so, do we want to proceed with this solely for code simplification (if any) or just close it? We obviously appreciate the time @stebet and the reviewers have put into this PR. But if an optimization PR doesn't make any difference to benchmarks in the end, is it worth adopting?

@stebet
Copy link
Contributor Author

stebet commented Feb 23, 2021

Given that the gain is 0,1% or so, do we want to proceed with this solely for code simplification (if any) or just close it? We obviously appreciate the time @stebet and the reviewers have put into this PR. But if an optimization PR doesn't make any difference to benchmarks in the end, is it worth adopting?

I'm biased, this being my PR and all, but from a code cleaning perspective I'd say yes. The performance optimization was purely a bonus and not the main point of the PR, although less locking is always better too. Although throughput gains were minimal, CPU usage also dropped a bit as a result.

@michaelklishin
Copy link
Member

The Protocol class seems redundant to me

At this point, we can just drop it and leave only 0-9-1 as supported. 0-8 and 0-9 share a lot with 0-9-1 (unlike 1.0, which is a completely different protocol), so years ago it made sense to support them all.

0-9-1 is available in RabbitMQ 2.0+, which has been out for more than a decade. So we can remove all 0-8 and 0-9 bits (I don't expect there to be many) in a separate PR.

@michaelklishin michaelklishin merged commit 0810d13 into rabbitmq:master Feb 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants