Skip to content

Handle fewer than two requests in RotateRoundRobinArbiter - #305

Open
Shubham-Padkonde wants to merge 1 commit into
intel:mainfrom
Shubham-Padkonde:arbiter-fewer-than-two-requests
Open

Shubham-Padkonde wants to merge 1 commit into
intel:mainfrom
Shubham-Padkonde:arbiter-fewer-than-two-requests

Conversation

@Shubham-Padkonde

Copy link
Copy Markdown

Description

RotateRoundRobinArbiter sizes its preference register with log2Ceil(count), which degenerates for small request lists. Probing all three arbiters on main at c67e2f7:

requests RotateRoundRobinArbiter MaskRoundRobinArbiter PriorityArbiter
0 UnsupportedError: Infinity or NaN toInt builds builds
1 PortWidthMismatchException: Expected ports Logic(0): preference and Logic(1): _binary_add_const_1 to be the same width builds builds
2 builds builds builds
3 builds builds builds

For one request, log2Ceil(1) is 0, so preference is 0 bits wide and cannot hold the result of the + 1 in the Sequential block — exactly the squashing described in #272. For zero requests, log2Ceil(0) goes through log(0), so the failure is an Infinity or NaN conversion rather than anything that points at the real problem.

The fix follows the suggestion in the issue:

  • preference gets a width of at least 1. A single request needs no rotation, but the increment still has to land somewhere.
  • An empty request list returns early. There is nothing to arbitrate between and no grant to drive, so the rotation math is skipped entirely.

On the question the issue raises — whether an empty list is illegal — I went with accepting it rather than throwing, because MaskRoundRobinArbiter and PriorityArbiter already accept it and build a module with no grants. Making the third arbiter behave the same way seemed better than introducing an error that its siblings don't raise. If you'd rather all three rejected an empty list, that's a separate (and breaking) change I'm happy to write instead.

I also checked the sibling arbiters for the same class of problem as the issue asks: MaskRoundRobinArbiter and PriorityArbiter both handle 0 and 1 requests correctly today, so neither needed changing.

Related Issue(s)

Fixes #272

Testing

Two tests added to the existing round robin group in test/arbiter_test.dart, so they run against both round-robin arbiters:

  • single request — builds a 1-request arbiter, then simulates: the only requester is granted on every cycle it asks, and the grant drops when the request does.
  • no requests — builds a 0-request arbiter and checks count and grants are empty.

Running them with the library change stashed shows the rotate variants failing and the mask variants passing, which is the behaviour difference this PR removes:

00:00 +13 -1: round robin rotate single request [E]
00:00 +13 -2: round robin rotate no requests [E]
  Unsupported operation: Infinity or NaN toInt
00:00 +13 -2: Some tests failed.

test/arbiter_test.dart with the change: 00:00 +15: All tests passed!

Full suite, dart test -j 3, clean main versus this branch:

12:23 +1356 ~1: All tests passed!    <- main
06:06 +1360 ~1: All tests passed!    <- this branch

No failures either way; the +4 is the two new tests across the two arbiter types.

dart format --output=none --set-exit-if-changed reports no changes and dart analyze finds no issues on the touched files.

Backwards-compatibility

Not a breaking change. Request lists of 2 or more behave exactly as before — the max(1, ...) only takes effect at count == 1, where log2Ceil returned 0 and the module could not be built at all. The early return only triggers for an empty list, which previously threw.

Documentation

No documentation changes needed — the arbiter's public API is unchanged. I added two short comments at the changed lines explaining why the width has a floor and why an empty list returns early.


Disclosure: this change was written by Claude Code (Claude Opus 5) working as my agent, at my direction. The exception messages and test output quoted above come from real runs in my local environment; I am accountable for the content of this PR and happy to iterate on review feedback.

🤖 Generated with Claude Code

RotateRoundRobinArbiter sizes its `preference` register with
log2Ceil(count), which degenerates for small request lists while the
other two arbiters cope:

  count=0  UnsupportedError: Infinity or NaN toInt
  count=1  PortWidthMismatchException: Expected ports Logic(0): preference
           and Logic(1): _binary_add_const_1 to be the same width

MaskRoundRobinArbiter and PriorityArbiter both build for 0 and 1
requests, so make this one consistent rather than failing inside the
rotation math:

  - give `preference` a width of at least 1, since a single request needs
    no rotation but the increment still has to land somewhere;
  - return early for an empty request list, where there is nothing to
    arbitrate and no grant to drive.

Fixes intel#272

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

Gracefully handle fewer than 2 requests to arbitrate between

1 participant