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

[AIR] Experiment restore stress tests #33706

Merged
merged 32 commits into from
Apr 13, 2023

Conversation

justinvyu
Copy link
Contributor

@justinvyu justinvyu commented Mar 25, 2023

Why are these changes needed?

This test is meant to be an integration stress test for Train/Tune experiment restoration.

Test setup

  • For Tuner.restore:

    • 8 trials, with a max of 2 running concurrently (--> 4 rounds of trials)
    • Each iteration takes 0.5 seconds
    • Each trial runs for 8 iterations --> 4 seconds
    • Each round of 2 trials should take 4 seconds
    • Without any interrupts/restoration:
      • Minimum runtime: 4 rounds * 4 seconds / round = 16 seconds
    • The test will stop the script with a SIGINT at a random time between
      4-8 iterations each restore.
  • For Trainer.restore:

    • 1 trial with 4 workers
    • Each iteration takes 0.5 seconds
    • Runs for 32 iterations --> Minimum runtime = 16 seconds
    • The test will stop the script with a SIGINT at a random time between
      4-8 iterations after each restore.

Test Passing Requirements

  • Req 1: Reasonable runtime
    • The experiment should finish within 1.5 * 16 = 24 seconds.
    • 1.5x is the passing threshold.
  • Req 2: Training progress persisted
    • The experiment should progress monotonically.
      (The training iteration shouldn't go backward at any point)
    • Trials shouldn't start from scratch.
  • Req 3: Searcher state saved/restored correctly
  • Req 4: Callback state saved/restored correctly

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 added any new APIs to the API Reference. For example, if I added a
      method in Tune, I've added it in doc/source/tune/api/ under the
      corresponding .rst file.
  • 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 :(

@justinvyu justinvyu marked this pull request as draft March 25, 2023 01:50
@justinvyu justinvyu marked this pull request as ready for review April 10, 2023 18:48
Copy link
Member

@gjoliver gjoliver left a comment

Choose a reason for hiding this comment

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

thanks man!

os.environ.get("RUN_STARTED_MARKER", "/tmp/does-not-exist")
)
if training_started_marker.exists():
# Multiple workers may be trying to delete the same marker
Copy link
Member

Choose a reason for hiding this comment

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

instead of try ... except, can you just missing_ok=True?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used that originally but seems like missing_ok was introduced in py38.

Copy link
Member

Choose a reason for hiding this comment

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

can you please except FileNotFoundError instead then?

python/ray/air/tests/test_experiment_restore.py Outdated Show resolved Hide resolved
run_started_marker.write_text("", encoding="utf-8")

run = subprocess.Popen(
[sys.executable, script_path], env=env # , stderr=subprocess.PIPE
Copy link
Member

Choose a reason for hiding this comment

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

actually why do you want to go the subprocess route?
why not just write those train() and tune() functions as test code here, and simply call the functions?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is because we are simulating script interruption by user input here, which is closer to the user behavior if run in a subprocess

Copy link
Member

Choose a reason for hiding this comment

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

I see. 👌

Copy link
Contributor

@krfricke krfricke left a comment

Choose a reason for hiding this comment

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

Generally looks good to me!

run_started_marker.write_text("", encoding="utf-8")

run = subprocess.Popen(
[sys.executable, script_path], env=env # , stderr=subprocess.PIPE
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is because we are simulating script interruption by user input here, which is closer to the user behavior if run in a subprocess

python/ray/train/base_trainer.py Show resolved Hide resolved
Copy link
Member

@gjoliver gjoliver left a comment

Choose a reason for hiding this comment

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

cool, cool.
a couple of nits left. thanks again.

os.environ.get("RUN_STARTED_MARKER", "/tmp/does-not-exist")
)
if training_started_marker.exists():
# Multiple workers may be trying to delete the same marker
Copy link
Member

Choose a reason for hiding this comment

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

can you please except FileNotFoundError instead then?

run_started_marker.write_text("", encoding="utf-8")

run = subprocess.Popen(
[sys.executable, script_path], env=env # , stderr=subprocess.PIPE
Copy link
Member

Choose a reason for hiding this comment

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

I see. 👌

# Pass criteria
no_interrupts_runtime = 16.0
passing_factor = 1.5
passing_runtime = no_interrupts_runtime * passing_factor
Copy link
Member

Choose a reason for hiding this comment

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

I am a little worried about this hardcoded runtime, since tests can act quite differently on CI machines.
I hope this won't be flaky.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gjoliver I see, yeah I was a bit worried about this too. What about making the threshold much more lenient? Like 2x.

The total_runtime calculation is only adding up actual training time. On every run, it's calculated as the time between training started and when the run gets killed by interrupt. So, it's independent of extra time CI machines might take to initialize Trainable, and handle restoration, etc.

Copy link
Contributor

@krfricke krfricke left a comment

Choose a reason for hiding this comment

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

Nice! @gjoliver can you merge once you're happy?

@gjoliver gjoliver merged commit 17eb052 into ray-project:master Apr 13, 2023
vitsai pushed a commit to vitsai/ray that referenced this pull request Apr 17, 2023
elliottower pushed a commit to elliottower/ray that referenced this pull request Apr 22, 2023
ProjectsByJackHe pushed a commit to ProjectsByJackHe/ray that referenced this pull request May 4, 2023
@justinvyu justinvyu deleted the air/experiment_restore_tests branch August 9, 2023 01:24
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