mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
simplify running benchmarks (#10536)
This commit is contained in:
@@ -5,6 +5,10 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_COLOR: "1"
|
||||||
|
PY_COLORS: "1"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bench:
|
bench:
|
||||||
name: run benchmarks
|
name: run benchmarks
|
||||||
@@ -13,6 +17,24 @@ jobs:
|
|||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
- uses: iterative/dvc-bench@main
|
|
||||||
|
- uses: hynek/setup-cached-uv@v2
|
||||||
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
pytest_options: "-k 'test_init or test_help'"
|
ref: ${{ github.event.pull_request.base.sha }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- run: uv pip install '.[tests]' --system
|
||||||
|
- name: run benchmarks on base branch
|
||||||
|
run: pytest --benchmark-autosave dvc/testing/benchmarks/ -k 'test_init or test_help'
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
clean: false
|
||||||
|
- run: uv pip install '.[tests]' --system
|
||||||
|
- name: run benchmarks for PR
|
||||||
|
run: >
|
||||||
|
pytest --benchmark-compare --benchmark-compare-fail=min:5%
|
||||||
|
--benchmark-group-by name
|
||||||
|
dvc/testing/benchmarks/ -k 'test_init or test_help'
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PYTHONUTF8: 1
|
PYTHONUTF8: 1
|
||||||
run: >
|
run: >
|
||||||
pytest ${{ matrix.pytestargs }} -n=logical --timeout=300 --durations=0
|
pytest ${{ matrix.pytestargs }} -n=logical --dist=worksteal --timeout=300 --durations=0
|
||||||
--cov --cov-report=xml --cov-report=term --durations-path=./.github/.test_durations
|
--cov --cov-report=xml --cov-report=term --durations-path=./.github/.test_durations
|
||||||
- name: upload coverage report
|
- name: upload coverage report
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
from .fixtures import * # noqa: F403
|
from .fixtures import * # noqa: F403
|
||||||
|
|
||||||
|
pytest_plugins = ["dvc.testing.plugin"]
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ def dvc_venvs():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def dvc_git_repo(tmp_path_factory, bench_config):
|
def dvc_repo(tmp_path_factory, bench_config):
|
||||||
url = bench_config.dvc_git_repo
|
url = bench_config.dvc_repo
|
||||||
|
|
||||||
if os.path.isdir(url):
|
if os.path.isdir(url):
|
||||||
return url
|
return url
|
||||||
@@ -73,8 +73,10 @@ def dvc_git_repo(tmp_path_factory, bench_config):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def dvc_bench_git_repo(tmp_path_factory, bench_config):
|
def dvc_bench_repo(tmp_path_factory, bench_config):
|
||||||
url = bench_config.dvc_bench_git_repo
|
url = bench_config.dvc_bench_repo
|
||||||
|
if url is None:
|
||||||
|
pytest.skip("--dvc-bench-repo is not set")
|
||||||
|
|
||||||
if os.path.isdir(url):
|
if os.path.isdir(url):
|
||||||
return Path(url)
|
return Path(url)
|
||||||
@@ -90,7 +92,7 @@ def make_dvc_bin(
|
|||||||
dvc_rev,
|
dvc_rev,
|
||||||
dvc_venvs,
|
dvc_venvs,
|
||||||
make_dvc_venv,
|
make_dvc_venv,
|
||||||
dvc_git_repo,
|
dvc_repo,
|
||||||
bench_config,
|
bench_config,
|
||||||
request,
|
request,
|
||||||
):
|
):
|
||||||
@@ -102,7 +104,7 @@ def make_dvc_bin(
|
|||||||
pkg = f"dvc[{bench_config.dvc_install_deps}]"
|
pkg = f"dvc[{bench_config.dvc_install_deps}]"
|
||||||
else:
|
else:
|
||||||
pkg = "dvc"
|
pkg = "dvc"
|
||||||
packages = [f"{pkg} @ git+file://{dvc_git_repo}@{dvc_rev}"]
|
packages = [f"{pkg} @ git+file://{dvc_repo}@{dvc_rev}"]
|
||||||
try:
|
try:
|
||||||
if version.Version(dvc_rev) < version.Version("3.50.3"):
|
if version.Version(dvc_rev) < version.Version("3.50.3"):
|
||||||
packages.append("pygit2==1.14.1")
|
packages.append("pygit2==1.14.1")
|
||||||
@@ -186,14 +188,14 @@ def _pull(repo, *args):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def make_dataset(request, bench_config, tmp_dir, dvc_bench_git_repo):
|
def make_dataset(request, bench_config, tmp_dir, dvc_bench_repo):
|
||||||
def _make_dataset(
|
def _make_dataset(
|
||||||
dvcfile=False, files=True, cache=False, commit=False, remote=False
|
dvcfile=False, files=True, cache=False, commit=False, remote=False
|
||||||
):
|
):
|
||||||
from dvc.repo import Repo
|
from dvc.repo import Repo
|
||||||
|
|
||||||
path = tmp_dir / "dataset"
|
path = tmp_dir / "dataset"
|
||||||
root = dvc_bench_git_repo
|
root = dvc_bench_repo
|
||||||
src = root / "data" / bench_config.dataset / "dataset"
|
src = root / "data" / bench_config.dataset / "dataset"
|
||||||
src_dvc = src.with_suffix(".dvc")
|
src_dvc = src.with_suffix(".dvc")
|
||||||
|
|
||||||
@@ -252,7 +254,7 @@ def make_project(tmp_path_factory):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def project(bench_config, monkeypatch, make_project):
|
def project(bench_config, monkeypatch, make_project):
|
||||||
rev = bench_config.project_rev
|
rev = bench_config.project_rev
|
||||||
url = bench_config.project_git_repo
|
url = bench_config.project_repo
|
||||||
|
|
||||||
if os.path.isdir(url):
|
if os.path.isdir(url):
|
||||||
path = url
|
path = url
|
||||||
|
|||||||
@@ -1,31 +1,44 @@
|
|||||||
|
import os
|
||||||
|
from dataclasses import dataclass, fields
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
DEFAULT_DVC_BIN = "dvc"
|
DEFAULT_DVC_BIN = "dvc"
|
||||||
DEFAULT_DVC_GIT_REPO = "https://github.com/iterative/dvc"
|
DEFAULT_DVC_REPO = os.fspath(Path(__file__).parents[3])
|
||||||
DEFAULT_DVC_BENCH_GIT_REPO = "https://github.com/iterative/dvc-bench"
|
DEFAULT_PROJECT_REPO = "https://github.com/iterative/example-get-started"
|
||||||
DEFAULT_PROJECT_GIT_REPO = "https://github.com/iterative/example-get-started"
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_report_header(config):
|
def pytest_report_header(config):
|
||||||
bconf = config.bench_config
|
bconf = config.bench_config
|
||||||
return f"dvc-bench: (dataset: {bconf.dataset!r}, revs: {bconf.dvc_revs!r})"
|
return f"dvc-bench: {bconf}"
|
||||||
|
|
||||||
|
|
||||||
def pytest_generate_tests(metafunc):
|
def pytest_generate_tests(metafunc):
|
||||||
str_revs = metafunc.config.getoption("--dvc-revs")
|
revs = metafunc.config.getoption("--dvc-revs")
|
||||||
revs = str_revs.split(",") if str_revs else [None]
|
if not revs:
|
||||||
|
revs = [None]
|
||||||
if "dvc_rev" in metafunc.fixturenames:
|
if "dvc_rev" in metafunc.fixturenames:
|
||||||
metafunc.parametrize("dvc_rev", revs, scope="session")
|
metafunc.parametrize("dvc_rev", revs, scope="session")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class DVCBenchConfig:
|
class DVCBenchConfig:
|
||||||
def __init__(self):
|
dataset: str = "tiny"
|
||||||
self.dataset = "small"
|
dvc_repo: str = DEFAULT_DVC_REPO
|
||||||
self.dvc_bin = DEFAULT_DVC_BIN
|
dvc_bench_repo: Optional[str] = None
|
||||||
self.dvc_revs = None
|
project_repo: str = DEFAULT_PROJECT_REPO
|
||||||
self.dvc_git_repo = DEFAULT_DVC_GIT_REPO
|
project_rev: Optional[str] = None
|
||||||
self.dvc_install_deps = None
|
dvc_bin: str = DEFAULT_DVC_BIN
|
||||||
self.dvc_bench_git_repo = DEFAULT_DVC_BENCH_GIT_REPO
|
dvc_revs: Optional[list[str]] = None
|
||||||
self.project_rev = None
|
dvc_install_deps: Optional[str] = None
|
||||||
self.project_git_repo = DEFAULT_PROJECT_GIT_REPO
|
|
||||||
|
def __repr__(self):
|
||||||
|
args = ", ".join(
|
||||||
|
f"{f.name}={val!r}"
|
||||||
|
for f in fields(self)
|
||||||
|
if (val := getattr(self, f.name)) != f.default
|
||||||
|
)
|
||||||
|
return f"{self.__class__.__name__}({args})"
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
@@ -33,23 +46,29 @@ def pytest_configure(config):
|
|||||||
"markers",
|
"markers",
|
||||||
"requires(spec): mark a test to run only on versions that satisfy the spec",
|
"requires(spec): mark a test to run only on versions that satisfy the spec",
|
||||||
)
|
)
|
||||||
|
config.bench_config = DVCBenchConfig(
|
||||||
|
dataset=config.getoption("--dataset"),
|
||||||
|
dvc_repo=config.getoption("--dvc-repo"),
|
||||||
|
dvc_bench_repo=config.getoption("--dvc-bench-repo"),
|
||||||
|
project_repo=config.getoption("--project-repo"),
|
||||||
|
project_rev=config.getoption("--project-rev"),
|
||||||
|
dvc_bin=config.getoption("--dvc-bin"),
|
||||||
|
dvc_revs=config.getoption("--dvc-revs"),
|
||||||
|
dvc_install_deps=config.getoption("--dvc-install-deps"),
|
||||||
|
)
|
||||||
|
|
||||||
config.bench_config = DVCBenchConfig()
|
|
||||||
config.bench_config.dataset = config.getoption("--dataset")
|
def resolve_path(path):
|
||||||
config.bench_config.dvc_bin = config.getoption("--dvc-bin")
|
if os.path.isdir(path):
|
||||||
config.bench_config.dvc_revs = config.getoption("--dvc-revs")
|
return os.path.abspath(path)
|
||||||
config.bench_config.dvc_git_repo = config.getoption("--dvc-git-repo")
|
return path
|
||||||
config.bench_config.dvc_install_deps = config.getoption("--dvc-install-deps")
|
|
||||||
config.bench_config.dvc_bench_git_repo = config.getoption("--dvc-bench-git-repo")
|
|
||||||
config.bench_config.project_rev = config.getoption("--project-rev")
|
|
||||||
config.bench_config.project_git_repo = config.getoption("--project-git-repo")
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--dataset",
|
"--dataset",
|
||||||
type=str,
|
type=str,
|
||||||
default="small",
|
default="tiny",
|
||||||
help="Dataset name to use in tests (e.g. tiny/small/large/mnist/etc)",
|
help="Dataset name to use in tests (e.g. tiny/small/large/mnist/etc)",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,36 +81,34 @@ def pytest_addoption(parser):
|
|||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--dvc-revs",
|
"--dvc-revs",
|
||||||
type=str,
|
type=lambda revs: revs.split(","),
|
||||||
help=("Comma-separated list of DVC revisions to test (overrides `--dvc-bin`)"),
|
help=("Comma-separated list of DVC revisions to test (overrides `--dvc-bin`)"),
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--dvc-git-repo",
|
"--dvc-repo",
|
||||||
type=str,
|
type=resolve_path,
|
||||||
default=DEFAULT_DVC_GIT_REPO,
|
default=DEFAULT_DVC_REPO,
|
||||||
help="Path or url to dvc git repo",
|
help="Path or url to dvc git repo",
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--dvc-install-deps",
|
"--dvc-install-deps",
|
||||||
type=str,
|
type=str,
|
||||||
default="",
|
|
||||||
help="Comma-separated list of DVC installation packages",
|
help="Comma-separated list of DVC installation packages",
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--dvc-bench-git-repo",
|
"--dvc-bench-repo",
|
||||||
type=str,
|
type=resolve_path,
|
||||||
default=DEFAULT_DVC_BENCH_GIT_REPO,
|
default=None,
|
||||||
help="Path or url to dvc-bench git repo (for loading benchmark datasets)",
|
help="Path or url to dvc-bench git repo (for loading benchmark datasets)",
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.addoption("--project-rev", type=str, help="Project revision to test")
|
parser.addoption("--project-rev", type=str, help="Project revision to test")
|
||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--project-git-repo",
|
"--project-repo",
|
||||||
type=str,
|
type=resolve_path,
|
||||||
default=DEFAULT_PROJECT_GIT_REPO,
|
default=DEFAULT_PROJECT_REPO,
|
||||||
help="Path or url to dvc project",
|
help="Path or url to dvc project",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,3 +18,9 @@ def pytest_configure(config):
|
|||||||
from .benchmarks.plugin import pytest_configure as bench_configure
|
from .benchmarks.plugin import pytest_configure as bench_configure
|
||||||
|
|
||||||
bench_configure(config)
|
bench_configure(config)
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_report_header(config):
|
||||||
|
from .benchmarks.plugin import pytest_report_header as bench_report_header
|
||||||
|
|
||||||
|
return bench_report_header(config)
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ namespaces = false
|
|||||||
write_to = "dvc/_dvc_version.py"
|
write_to = "dvc/_dvc_version.py"
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
addopts = "-ra --cov-config pyproject.toml --dist worksteal --benchmark-skip"
|
addopts = "-ra --cov-config pyproject.toml"
|
||||||
filterwarnings = [
|
filterwarnings = [
|
||||||
"error::ResourceWarning",
|
"error::ResourceWarning",
|
||||||
"error::pytest.PytestUnraisableExceptionWarning",
|
"error::pytest.PytestUnraisableExceptionWarning",
|
||||||
|
|||||||
+1
-1
@@ -3,4 +3,4 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
sys.exit(pytest.main(["-v", "-n=logical", *sys.argv[1:]]))
|
sys.exit(pytest.main(["-v", "-n=logical", "--dist=worksteal", *sys.argv[1:]]))
|
||||||
|
|||||||
Reference in New Issue
Block a user