mirror of
https://github.com/saymrwulf/pytorch.git
synced 2026-05-14 20:57:59 +00:00
adds a `default` tag to experiment configurations, allowing to remove some experiments by default on the random draw:
```
experiments:
lf:
rollout_perc: 25
otherExp:
rollout_perc: 25
default: false
---
```
and includes the configuration to filter what experiments are of interest for a particular workflow (comma separated):
```
get-test-label-type:
name: get-test-label-type
uses: ./.github/workflows/_runner-determinator.yml
with:
...
check_experiments: "awsa100"
```
The end goal, is to enable us to run multiple experiments, that are independent from one another. For example, while we still runs the LF infra experiment, we want to migrate other runners leveraging the current solution. A immediate UC is for the A100 instances, where we want to migrate to AWS.
Those new instances will during the migration period be labeled both `awsa100.linux.gcp.a100` and `linux.aws.a100`. Once the experiment ends, we will remove the first confusing one.
```
jobs:
get-build-label-type:
name: get-build-label-type
uses: ./.github/workflows/_runner-determinator.yml
with:
...
get-test-label-type:
name: get-test-label-type
uses: ./.github/workflows/_runner-determinator.yml
with:
...
check_experiments: "awsa100"
linux-focal-cuda12_1-py3_10-gcc9-inductor-build:
name: cuda12.1-py3.10-gcc9-sm80
uses: ./.github/workflows/_linux-build.yml
needs:
- get-build-label-type
- get-test-label-type
with:
runner_prefix: "${{ needs.get-build-label-type.outputs.label-type }}"
...
test-matrix: |
{ include: [
{ config: "inductor_huggingface_perf_compare", shard: 1, num_shards: 1, runner: "${{ needs.get-test-label-type.outputs.label-type }}linux.gcp.a100" },
...
]}
...
```
```
experiments:
lf:
rollout_perc: 50
awsa100:
rollout_perc: 50
default: false
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/137614
Approved by: https://github.com/malfet
440 lines
11 KiB
Python
440 lines
11 KiB
Python
from unittest import main, TestCase
|
|
from unittest.mock import Mock, patch
|
|
|
|
import runner_determinator as rd
|
|
|
|
|
|
USER_BRANCH = "somebranch"
|
|
EXCEPTION_BRANCH = "main"
|
|
|
|
|
|
class TestRunnerDeterminatorIssueParser(TestCase):
|
|
def test_parse_settings(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 0
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
settings = rd.parse_settings(settings_text)
|
|
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=25),
|
|
settings.experiments["lf"],
|
|
"lf settings not parsed correctly",
|
|
)
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=0, default=False),
|
|
settings.experiments["otherExp"],
|
|
"otherExp settings not parsed correctly",
|
|
)
|
|
|
|
def test_parse_settings_in_code_block(self) -> None:
|
|
settings_text = """
|
|
|
|
```
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 0
|
|
default: false
|
|
```
|
|
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
settings = rd.parse_settings(settings_text)
|
|
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=25),
|
|
settings.experiments["lf"],
|
|
"lf settings not parsed correctly",
|
|
)
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=0, default=False),
|
|
settings.experiments["otherExp"],
|
|
"otherExp settings not parsed correctly",
|
|
)
|
|
|
|
def test_parse_all_branches_setting(self) -> None:
|
|
settings_text = """
|
|
```
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
all_branches: true
|
|
otherExp:
|
|
all_branches: True
|
|
rollout_perc: 0
|
|
```
|
|
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
settings = rd.parse_settings(settings_text)
|
|
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=25, all_branches=True),
|
|
settings.experiments["lf"],
|
|
"lf settings not parsed correctly",
|
|
)
|
|
self.assertTrue(settings.experiments["otherExp"].all_branches)
|
|
self.assertTupleEqual(
|
|
rd.Experiment(rollout_perc=0, all_branches=True),
|
|
settings.experiments["otherExp"],
|
|
"otherExp settings not parsed correctly",
|
|
)
|
|
|
|
def test_parse_users(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
users = rd.parse_users(settings_text)
|
|
self.assertDictEqual(
|
|
{"User1": ["lf"], "User2": ["lf", "otherExp"]},
|
|
users,
|
|
"Users not parsed correctly",
|
|
)
|
|
|
|
def test_parse_users_without_settings(self) -> None:
|
|
settings_text = """
|
|
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
users = rd.parse_users(settings_text)
|
|
self.assertDictEqual(
|
|
{"User1": ["lf"], "User2": ["lf", "otherExp"]},
|
|
users,
|
|
"Users not parsed correctly",
|
|
)
|
|
|
|
|
|
class TestRunnerDeterminatorGetRunnerPrefix(TestCase):
|
|
def test_opted_in_user(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(settings_text, ["User1"], USER_BRANCH)
|
|
self.assertEqual("lf.", prefix, "Runner prefix not correct for User1")
|
|
|
|
def test_opted_in_user_two_experiments(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(settings_text, ["User2"], USER_BRANCH)
|
|
self.assertEqual("lf.otherExp.", prefix, "Runner prefix not correct for User2")
|
|
|
|
def test_opted_in_user_two_experiments_default(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(settings_text, ["User2"], USER_BRANCH)
|
|
self.assertEqual("lf.", prefix, "Runner prefix not correct for User2")
|
|
|
|
def test_opted_in_user_two_experiments_default_exp(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(
|
|
settings_text, ["User2"], USER_BRANCH, frozenset(["lf", "otherExp"])
|
|
)
|
|
self.assertEqual("lf.otherExp.", prefix, "Runner prefix not correct for User2")
|
|
|
|
def test_opted_in_user_two_experiments_default_exp_2(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(
|
|
settings_text, ["User2"], USER_BRANCH, frozenset(["otherExp"])
|
|
)
|
|
self.assertEqual("otherExp.", prefix, "Runner prefix not correct for User2")
|
|
|
|
@patch("random.uniform", return_value=50)
|
|
def test_opted_out_user(self, mock_uniform: Mock) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 25
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
prefix = rd.get_runner_prefix(settings_text, ["User3"], USER_BRANCH)
|
|
self.assertEqual("", prefix, "Runner prefix not correct for user")
|
|
|
|
@patch("random.uniform", return_value=10)
|
|
def test_opted_out_user_was_pulled_in_by_rollout(self, mock_uniform: Mock) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 25
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
# User3 is opted out, but is pulled into both experiments by the 10% rollout
|
|
prefix = rd.get_runner_prefix(settings_text, ["User3"], USER_BRANCH)
|
|
self.assertEqual("lf.otherExp.", prefix, "Runner prefix not correct for user")
|
|
|
|
@patch("random.uniform", return_value=10)
|
|
def test_opted_out_user_was_pulled_in_by_rollout_excl_nondefault(
|
|
self, mock_uniform: Mock
|
|
) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 25
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
# User3 is opted out, but is pulled into default experiments by the 10% rollout
|
|
prefix = rd.get_runner_prefix(settings_text, ["User3"], USER_BRANCH)
|
|
self.assertEqual("lf.", prefix, "Runner prefix not correct for user")
|
|
|
|
@patch("random.uniform", return_value=10)
|
|
def test_opted_out_user_was_pulled_in_by_rollout_filter_exp(
|
|
self, mock_uniform: Mock
|
|
) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 25
|
|
otherExp:
|
|
rollout_perc: 25
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
# User3 is opted out, but is pulled into default experiments by the 10% rollout
|
|
prefix = rd.get_runner_prefix(
|
|
settings_text, ["User3"], USER_BRANCH, frozenset(["otherExp"])
|
|
)
|
|
self.assertEqual("otherExp.", prefix, "Runner prefix not correct for user")
|
|
|
|
@patch("random.uniform", return_value=25)
|
|
def test_opted_out_user_was_pulled_out_by_rollout_filter_exp(
|
|
self, mock_uniform: Mock
|
|
) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 10
|
|
otherExp:
|
|
rollout_perc: 50
|
|
default: false
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
# User3 is opted out, but is pulled into default experiments by the 10% rollout
|
|
prefix = rd.get_runner_prefix(settings_text, ["User3"], USER_BRANCH)
|
|
self.assertEqual("", prefix, "Runner prefix not correct for user")
|
|
|
|
def test_lf_prefix_always_comes_first(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
otherExp:
|
|
rollout_perc: 0
|
|
lf:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
@User1,lf
|
|
@User2,otherExp,lf
|
|
|
|
"""
|
|
|
|
prefix = rd.get_runner_prefix(settings_text, ["User2"], USER_BRANCH)
|
|
self.assertEqual("lf.otherExp.", prefix, "Runner prefix not correct for user")
|
|
|
|
def test_ignores_commented_users(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
#@User1,lf
|
|
@User2,lf,otherExp
|
|
|
|
"""
|
|
|
|
prefix = rd.get_runner_prefix(settings_text, ["User1"], USER_BRANCH)
|
|
self.assertEqual("", prefix, "Runner prefix not correct for user")
|
|
|
|
def test_ignores_extra_experiments(self) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 0
|
|
otherExp:
|
|
rollout_perc: 0
|
|
foo:
|
|
rollout_perc: 0
|
|
---
|
|
|
|
Users:
|
|
@User1,lf,otherExp,foo
|
|
|
|
"""
|
|
|
|
prefix = rd.get_runner_prefix(settings_text, ["User1"], USER_BRANCH)
|
|
self.assertEqual("lf.otherExp.", prefix, "Runner prefix not correct for user")
|
|
|
|
def test_disables_experiment_on_exception_branches_when_not_explicitly_opted_in(
|
|
self,
|
|
) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 100
|
|
---
|
|
|
|
Users:
|
|
@User,lf,otherExp
|
|
|
|
"""
|
|
|
|
prefix = rd.get_runner_prefix(settings_text, ["User1"], EXCEPTION_BRANCH)
|
|
self.assertEqual("", prefix, "Runner prefix not correct for user")
|
|
|
|
def test_allows_experiment_on_exception_branches_when_explicitly_opted_in(
|
|
self,
|
|
) -> None:
|
|
settings_text = """
|
|
experiments:
|
|
lf:
|
|
rollout_perc: 100
|
|
all_branches: true
|
|
---
|
|
|
|
Users:
|
|
@User,lf,otherExp
|
|
|
|
"""
|
|
|
|
prefix = rd.get_runner_prefix(settings_text, ["User1"], EXCEPTION_BRANCH)
|
|
self.assertEqual("lf.", prefix, "Runner prefix not correct for user")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|