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

wrr: improve randomWRR performance #5067

Merged
merged 8 commits into from Jan 12, 2022

Conversation

huangchong94
Copy link
Contributor

@huangchong94 huangchong94 commented Dec 17, 2021

This PR improves randomWRR.Next performance by

  1. using binary search when weights are not equal
  2. picking item randomly when weights are equal

In general, this PR performs better than current implementation and has a more stable performance characteristics while the previous approach is more sensitive to weights distribution but it works better in some cases (i.e. small number of items with different weights)

RELEASE NOTES: wrr: improve randomWRR performance

@huangchong94 huangchong94 force-pushed the optimize-wrr-random branch 2 times, most recently from 61ee291 to 4dc83ca Compare December 17, 2021 12:34
@huangchong94 huangchong94 changed the title wrr: use binary search to improve randomWRR performance WIP: wrr: improve randomWRR performance Dec 17, 2021
* use binary search when weights are not equal
* random pick one when weights are equal
@huangchong94 huangchong94 changed the title WIP: wrr: improve randomWRR performance wrr: improve randomWRR performance Dec 17, 2021
Item interface{}
Weight int64
Item interface{}
// TODO Delete Weight? This field is not necessary for randomWRR to work.
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete this field if it's not used.

And it seems all fields in this struct can be unexported, right? Can you also change that? Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

internal/wrr/random.go Show resolved Hide resolved
@@ -51,27 +57,35 @@ var grpcrandInt63n = grpcrand.Int63n
func (rw *randomWRR) Next() (item interface{}) {
rw.mu.RLock()
defer rw.mu.RUnlock()
if rw.sumOfWeights == 0 {
sumOfWeights := rw.items[len(rw.items)-1].AccumulatedWeight
Copy link
Contributor

Choose a reason for hiding this comment

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

This will fail if there's no item, right? (And add a test)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

func BenchmarkRandomWRRNext(b *testing.B) {
for _, n := range []int{100, 500, 1000} {
b.Run("equal-weights-"+strconv.Itoa(n)+"-items", func(b *testing.B) {
w := NewRandom().(*randomWRR)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need this type assertion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

…e unexported;

add comment for field equalWeights in randomWRR;
fix panic when there is no item in randomWRR.Next;
add test case for wrr;

 remove redundant type assertion in BenchmarkRandomWRRNext;
internal/wrr/random.go Outdated Show resolved Hide resolved
return rw.items[len(rw.items)-1].Item
sumOfWeights = rw.items[len(rw.items)-1].accumulatedWeight
// Random number in [0, sumOfWeights).
randomWeight := grpcrandInt63n(sumOfWeights)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, this may still fail if sumOfWeights == 0 (this happens when the items added all are weight 0 🤷‍♂️ )

Maybe keep the check if sumOfWeights == 0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If items added all are weight 0, then rw.equalWeights will be true, Next will return normally at line 61 return rw.items[grpcrandInt63n(int64(len(rw.items)))].item

I considered keeping if sumOfWeights == 0 return nil, but the behaviour will be different from edf.go, in edf, if all
item's weights are zero, Next will return non nil item

lastItem := rw.items[len(rw.items)-1]
accumulatedWeight = lastItem.accumulatedWeight + weight
lastItemWeight := lastItem.accumulatedWeight
if len(rw.items) > 1 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I now see what you meant in the old comments. weight is used once here.
I would be OK to keep the weight field to simplify the code here.
Either way is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added weight back to weightedItem to simplify code here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By the way, why weight type is int64 not uint32, int64 will allow user add negative weight item to WRR which will result undefined behaviour in Next.

internal/wrr/wrr_test.go Outdated Show resolved Hide resolved
Copy link
Contributor

@menghanl menghanl left a comment

Choose a reason for hiding this comment

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

LGTM

@menghanl menghanl requested a review from dfawley January 12, 2022 19:54
@menghanl menghanl assigned dfawley and unassigned menghanl Jan 12, 2022
@menghanl menghanl merged commit f231ac5 into grpc:master Jan 12, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants