Skip to content

[tune] Use generic _ObjectCache for actor reuse - #33045

Merged
krfricke merged 10 commits into
ray-project:masterfrom
krfricke:tune/generic-object-cache-reuse
Mar 7, 2023
Merged

[tune] Use generic _ObjectCache for actor reuse#33045
krfricke merged 10 commits into
ray-project:masterfrom
krfricke:tune/generic-object-cache-reuse

Conversation

@krfricke

@krfricke krfricke commented Mar 5, 2023

Copy link
Copy Markdown
Contributor

Why are these changes needed?

Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Related issue number

Checks

  • I've signed off every commit(by using the -s flag, i.e., git commit -s) in this PR.
  • I've run scripts/format.sh to lint the changes in this PR.
  • I've included any doc changes needed for https://docs.ray.io/en/master/.
  • I've made sure the tests are passing. Note that there might be a few flaky tests, see the recent failures at https://flakey-tests.ray.io/
  • Testing Strategy
    • Unit tests
    • Release tests
    • This PR is not tested :(

krfricke added 2 commits March 4, 2023 20:11
Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <coding@kaifricke.com>
krfricke and others added 3 commits March 5, 2023 14:33
Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>

@justinvyu justinvyu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good! I added a few questions/clarifications.

The eager_caching flag and keep_one logic seems a bit custom tailored to this specific Tune controller loop - is there a way to make it more general? One idea I had was to make this keep_at_least=1 instead. We don't need to over-generalize though, since I'm not too sure where we can use this _ObjectCache in other places in Tune. Any ideas there?

Comment thread python/ray/tune/utils/object_cache.py
Comment thread python/ray/tune/utils/object_cache.py Outdated

while len(objs) > max:
self._num_cached_objects -= 1
yield objs.pop(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want to pop all first, then yield the results? Or is popping as we go intended behavior?

If we break/return in the middle of handling the result, some of the objects we tried to flush will still be in there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that's what we want. The caller may have to run cleanup on the objects, and if we pop them first and fail, the objects are lost and we may end up with leaked objects.

Comment thread python/ray/tune/utils/object_cache.py
Comment thread python/ray/tune/utils/object_cache.py
Comment thread python/ray/tune/utils/object_cache.py Outdated
Comment thread python/ray/tune/execution/ray_trial_executor.py Outdated
Comment thread python/ray/tune/utils/object_cache.py Outdated
@krfricke

krfricke commented Mar 6, 2023

Copy link
Copy Markdown
Contributor Author

Yeah I agree that this is pretty specific to Tune's needs. The main two reasons to separate this out are 1) better unit testability (currently the reuse logic is happening fully within Trial Executor logic) and 2) reuse in the refactoring towards the Tune Controller (to avoid too much code duplication).

I'd propose we leave it as is (i.e. keep eager caching for exactly one unit) and if we actually reuse this in a different component with different requirements, we can change it then. Ok?

Kai Fricke added 2 commits March 6, 2023 11:19
Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>

@justinvyu justinvyu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Makes sense, looks good to me!

Comment thread python/ray/tune/utils/object_cache.py Outdated
Kai Fricke added 2 commits March 6, 2023 16:11
Signed-off-by: Kai Fricke <kai@anyscale.com>

@xwjiang2010 xwjiang2010 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sorry just one more comment :)

Comment thread python/ray/tune/utils/object_cache.py Outdated
Signed-off-by: Kai Fricke <kai@anyscale.com>
@krfricke

krfricke commented Mar 7, 2023

Copy link
Copy Markdown
Contributor Author

The failure in test_commands seems unrelated to this issue and comes up for me locally on master as well. It's due to extensive rllib imports. I'll merge this PR

@krfricke
krfricke merged commit c0f6068 into ray-project:master Mar 7, 2023
@krfricke
krfricke deleted the tune/generic-object-cache-reuse branch March 7, 2023 19:14
ProjectsByJackHe pushed a commit to ProjectsByJackHe/ray that referenced this pull request Mar 21, 2023
Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: Jack He <jackhe2345@gmail.com>
edoakes pushed a commit to edoakes/ray that referenced this pull request Mar 22, 2023
Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: Edward Oakes <ed.nmi.oakes@gmail.com>
krfricke added a commit that referenced this pull request Mar 22, 2023
Similar regression that was originally fixed in #31974, but re-surfaced after #33045.

With actor re-use, we speculatively keep one cached actor around in case it is needed when new trials are added (e.g. if we add trials one-by-one). However, we should only do this when the search has not ended, as otherwise we keep an extra actor until the end of the experiment, wasting resources. This leads the tune_scale_up_down release test fail.

In our refactor to #33045 we generalized object caching, but the eviction logic here explicitly keeps one object in cache. Our previous implementation in RayTrialExecutor relied on not calling the eviction function at all when trials were still coming up, essentially not adjusting the number of cached actors down. This is rarely a problem in practice, but does not make a clean contract when separated out into a component.

In this PR, we change the logic as follows: When the search ended, no trials are pending execution, and we don't want to explicitly cache an actor, we force eviction of all cached objects.

We are refactoring our execution backend, thus I believe it's sufficient to keep the release test to catch this regression. In the new backend we can add light weight unit tests to capture this behavior.

Signed-off-by: Kai Fricke <kai@anyscale.com>
peytondmurray pushed a commit to peytondmurray/ray that referenced this pull request Mar 22, 2023
Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>
elliottower pushed a commit to elliottower/ray that referenced this pull request Apr 22, 2023
Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: elliottower <elliot@elliottower.com>
elliottower pushed a commit to elliottower/ray that referenced this pull request Apr 22, 2023
…ject#33593)

Similar regression that was originally fixed in ray-project#31974, but re-surfaced after ray-project#33045.

With actor re-use, we speculatively keep one cached actor around in case it is needed when new trials are added (e.g. if we add trials one-by-one). However, we should only do this when the search has not ended, as otherwise we keep an extra actor until the end of the experiment, wasting resources. This leads the tune_scale_up_down release test fail.

In our refactor to ray-project#33045 we generalized object caching, but the eviction logic here explicitly keeps one object in cache. Our previous implementation in RayTrialExecutor relied on not calling the eviction function at all when trials were still coming up, essentially not adjusting the number of cached actors down. This is rarely a problem in practice, but does not make a clean contract when separated out into a component.

In this PR, we change the logic as follows: When the search ended, no trials are pending execution, and we don't want to explicitly cache an actor, we force eviction of all cached objects.

We are refactoring our execution backend, thus I believe it's sufficient to keep the release test to catch this regression. In the new backend we can add light weight unit tests to capture this behavior.

Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: elliottower <elliot@elliottower.com>
ProjectsByJackHe pushed a commit to ProjectsByJackHe/ray that referenced this pull request May 4, 2023
Actor reuse is currently implemented within the RayTrialExecutor and tightly coupled to its concepts. To simplify the code, this PR introduces a new internal _ObjectCache class that generically caches objects (e.g. Actors+PGs) given a grouping key (e.g. resource requests).

By moving the caching logic into a separate component, we can write better unit tests to ensure actor reuse works correctly and as expected.

Signed-off-by: Kai Fricke <coding@kaifricke.com>
Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: Jack He <jackhe2345@gmail.com>
ProjectsByJackHe pushed a commit to ProjectsByJackHe/ray that referenced this pull request May 4, 2023
…ject#33593)

Similar regression that was originally fixed in ray-project#31974, but re-surfaced after ray-project#33045.

With actor re-use, we speculatively keep one cached actor around in case it is needed when new trials are added (e.g. if we add trials one-by-one). However, we should only do this when the search has not ended, as otherwise we keep an extra actor until the end of the experiment, wasting resources. This leads the tune_scale_up_down release test fail.

In our refactor to ray-project#33045 we generalized object caching, but the eviction logic here explicitly keeps one object in cache. Our previous implementation in RayTrialExecutor relied on not calling the eviction function at all when trials were still coming up, essentially not adjusting the number of cached actors down. This is rarely a problem in practice, but does not make a clean contract when separated out into a component.

In this PR, we change the logic as follows: When the search ended, no trials are pending execution, and we don't want to explicitly cache an actor, we force eviction of all cached objects.

We are refactoring our execution backend, thus I believe it's sufficient to keep the release test to catch this regression. In the new backend we can add light weight unit tests to capture this behavior.

Signed-off-by: Kai Fricke <kai@anyscale.com>
Signed-off-by: Jack He <jackhe2345@gmail.com>
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.

3 participants