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

performance: dynamic lambda #5654

Merged
merged 172 commits into from
Aug 31, 2023
Merged

performance: dynamic lambda #5654

merged 172 commits into from
Aug 31, 2023

Conversation

yossigi
Copy link
Contributor

@yossigi yossigi commented Aug 10, 2023

Summary

This PR changes the filter timeout on period 0 to be calculated dynamically, based on the history of credential arrival times. This allows reducing the time a node waits during the filter step on this period. If the filter timeout ends up being too short for too many nodes, preventing consensus, the protocol continues to period 1 where we fall back on the original filter timeout value.

Test Plan

Added new tests for player to make sure it reads the time samples correctly.
Added new tests for service to make sure it calculates the time samples correctly.
Added tests for new closed components, such as the credentialArrivalHistory.

@yossigi yossigi requested a review from cce August 10, 2023 21:49
@codecov
Copy link

codecov bot commented Aug 10, 2023

Codecov Report

Merging #5654 (ab7c83b) into master (2670e94) will increase coverage by 0.04%.
The diff coverage is 75.96%.

@@            Coverage Diff             @@
##           master    #5654      +/-   ##
==========================================
+ Coverage   55.51%   55.55%   +0.04%     
==========================================
  Files         473      474       +1     
  Lines       66316    66416     +100     
==========================================
+ Hits        36814    36899      +85     
- Misses      27005    27013       +8     
- Partials     2497     2504       +7     
Files Changed Coverage Δ
agreement/eventtype_string.go 50.00% <ø> (ø)
agreement/vote.go 83.33% <ø> (ø)
config/consensus.go 86.49% <ø> (ø)
agreement/actions.go 75.00% <50.00%> (-0.40%) ⬇️
agreement/events.go 66.54% <62.96%> (-1.01%) ⬇️
agreement/credentialArrivalHistory.go 78.57% <78.57%> (ø)
agreement/player.go 95.28% <86.48%> (-0.94%) ⬇️
agreement/demux.go 91.32% <100.00%> (+0.12%) ⬆️
agreement/persistence.go 77.83% <100.00%> (+0.22%) ⬆️
agreement/proposalStore.go 100.00% <100.00%> (ø)
... and 3 more

... and 12 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@algorandskiy
Copy link
Contributor

@yossigi
I think the param have to be in vFuture but commented out, otherwise it is easy to forget to enable. Plus, please comment it explaining why it is commented out

algorandskiy
algorandskiy previously approved these changes Aug 30, 2023
Copy link
Contributor

@cce cce left a comment

Choose a reason for hiding this comment

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

LGTM! The service tests were a little hard to follow but looks good overall

@gmalouf gmalouf requested a review from winder August 31, 2023 13:47
Copy link
Contributor

@excalq excalq left a comment

Choose a reason for hiding this comment

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

Noticed the two new telemetry field additions, VoteValidatedAt and DynamicFilterTimeout. 👍

@algorandskiy algorandskiy merged commit b0cf5c8 into master Aug 31, 2023
21 checks passed
@gmalouf gmalouf deleted the feature/dynamic-lambda branch August 31, 2023 17:32
// the linear time order statistics algorithm.
sortedArrivals := make([]time.Duration, len(history.history))
copy(sortedArrivals[:], history.history[:])
sort.Slice(sortedArrivals, func(i, j int) bool { return sortedArrivals[i] < sortedArrivals[j] })
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm told slices.Sort() is a bit faster because the bounds checks in the generated code end up better optimized. (Also slightly easier to write/read the code.)

Copy link
Contributor

@jannotti jannotti left a comment

Choose a reason for hiding this comment

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

I'm only reviewing to get my head in the area, before looking at the other PR.

Comment on lines +418 to +423
// Round and Period are the round and period for which to query the
// lowest-credential vote, value or payload. This type of event is only
// sent for reading the lowest period 0 credential, but the Period is here
// anyway to route to the appropriate proposalMachinePeriod.
Round round
Period period
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this Period=0 thing working? I don't see how the calling code can work generically across event types, so it can't just pluck ev.Period out of an arbitrary event of any type.

Comment on lines +289 to +290
re := readLowestEvent{T: readLowestVote, Round: p.Round, Period: p.Period}
re = r.dispatch(*p, re, proposalMachineRound, p.Round, p.Period, 0).(readLowestEvent)
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess my earlier comment is saying that we might as well not have the ev.Period field in the re, and just call r.dispatch with a 0 on line 290.

Comment on lines +356 to +357
re := e.(readLowestEvent)
return r.dispatch(p, re, proposalMachinePeriod, re.Round, re.Period, 0).(readLowestEvent)
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, we would call dispatch with a hard-coded 0.

history.full = false
}

// isFull checks if the circular buffer has been fully populated at least once.
Copy link
Contributor

@jannotti jannotti Oct 2, 2023

Choose a reason for hiding this comment

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

I suppose this is a bit silly, but if you want the 37th best of 40 and you're trying to avoid answering too low, you could start answering once you have 37 samples, and return the worst. We could call this isReady, and you have to initialize the struct with the statistic you care about (37), rather than just the total size. And you'd only support .GetStatistic() rather that all the caller to say which one it wants.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.