Skip to content

Commit 2f9350c

Browse files
Collect scheduler memray profiles when benchmarking geospatial tests (#1568)
1 parent 5758097 commit 2f9350c

File tree

10 files changed

+102
-5
lines changed

10 files changed

+102
-5
lines changed

.github/workflows/ab_tests.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ jobs:
106106
DB_NAME: ${{ matrix.runtime-version }}-${{ matrix.repeat }}.db
107107
CLUSTER_KWARGS: AB_environments/${{ matrix.runtime-version }}.cluster.yaml
108108
H2O_DATASETS: ${{ matrix.h2o_datasets }}
109-
run: pytest --benchmark ${{ matrix.pytest_args }}
109+
MEMRAY_PROFILE: "scheduler"
110+
run: pytest --benchmark --memray $MEMRAY_PROFILE ${{ matrix.pytest_args }}
110111

111112
- name: Dump coiled.Cluster kwargs
112113
run: cat cluster_kwargs.merged.yaml

.github/workflows/tests.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,9 @@ jobs:
141141
COILED_RUNTIME_VERSION: ${{ matrix.runtime-version }}
142142
DB_NAME: ${{ matrix.name_prefix }}-${{ matrix.os }}-py${{ matrix.python_version }}.db
143143
DASK_DATAFRAME__QUERY_PLANNING: True
144+
MEMRAY_PROFILE: "scheduler"
144145
run: |
145-
pytest --benchmark -n 4 --dist loadscope ${{ env.PYTEST_MARKERS }} ${{ matrix.pytest_args }}
146+
pytest --benchmark -n 4 --dist loadscope --memray $MEMRAY_PROFILE ${{ env.PYTEST_MARKERS }} ${{ matrix.pytest_args }}
146147
147148
- name: Dump coiled.Cluster kwargs
148149
run: cat cluster_kwargs.merged.yaml || true

.github/workflows/tpch.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ jobs:
105105
pytest --benchmark \
106106
${{ env.PYTEST_BENCHMARKS }} \
107107
-n 4 --dist loadscope \
108-
--scale ${{ inputs.scale }}
108+
--scale ${{ inputs.scale }} \
109109
110110
- name: Upload benchmark results
111111
uses: actions/upload-artifact@v4

AB_environments/AB_baseline.conda.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ dependencies:
5454
- pystac-client ==0.8.3
5555
- odc-stac ==0.3.10
5656
- adlfs ==2024.7.0
57+
- memray ==1.13.4
5758
# End copy-paste
5859

5960
- pip:

AB_environments/AB_sample.conda.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ dependencies:
6060
- pystac-client ==0.8.3
6161
- odc-stac ==0.3.10
6262
- adlfs ==2024.7.0
63+
- memray ==1.13.4
6364
# End copy-paste
6465

6566
- pip:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Add column for Memray profiles url
2+
3+
Revision ID: 1095dfdfc4ae
4+
Revises: 2d2405ad763b
5+
Create Date: 2024-10-23 11:11:15.238042
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '1095dfdfc4ae'
14+
down_revision = '2d2405ad763b'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade() -> None:
20+
op.add_column('test_run', sa.Column('memray_profiles_url', sa.String(), nullable=True))
21+
22+
23+
def downgrade() -> None:
24+
op.drop_column("test_run", "memray_profiles_url")

benchmark_schema.py

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class TestRun(Base):
6262
# Artifacts
6363
performance_report_url = Column(String, nullable=True) # Not yet collected
6464
cluster_dump_url = Column(String, nullable=True)
65+
memray_profiles_url = Column(String, nullable=True)
6566

6667

6768
class TPCHRun(Base):

ci/environment.yml

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ dependencies:
5656
- pystac-client ==0.8.3
5757
- odc-stac ==0.3.10
5858
- adlfs ==2024.7.0
59+
- memray ==1.13.4
5960

6061
########################################################
6162
# PLEASE READ:

tests/conftest.py

+67
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pickle
1010
import subprocess
1111
import sys
12+
import tarfile
1213
import threading
1314
import time
1415
import uuid
@@ -28,6 +29,7 @@
2829
import yaml
2930
from coiled import Cluster
3031
from dask.distributed import Client, WorkerPlugin
32+
from dask.distributed.diagnostics import memray
3133
from dask.distributed.diagnostics.memory_sampler import MemorySampler
3234
from dask.distributed.scheduler import logger as scheduler_logger
3335
from dotenv import load_dotenv
@@ -68,6 +70,14 @@ def pytest_addoption(parser):
6870
"--benchmark", action="store_true", help="Collect benchmarking data for tests"
6971
)
7072

73+
parser.addoption(
74+
"--memray",
75+
action="store",
76+
default="scheduler",
77+
help="Memray profiles to collect: scheduler or none",
78+
choices=("scheduler", "none"),
79+
)
80+
7181

7282
def pytest_sessionfinish(session, exitstatus):
7383
# https://github.com/pytest-dev/pytest/issues/2393
@@ -652,6 +662,16 @@ def _(**exta_options):
652662
return _
653663

654664

665+
@pytest.fixture(scope="session")
666+
def s3_performance(s3):
667+
profiles_url = f"{S3_BUCKET}/performance"
668+
# Ensure that the performance directory exists,
669+
# but do NOT remove it as multiple test runs could be
670+
# accessing it at the same time
671+
s3.mkdirs(profiles_url, exist_ok=True)
672+
return profiles_url
673+
674+
655675
@pytest.fixture(scope="session")
656676
def s3_scratch(s3):
657677
# Ensure that the test-scratch directory exists,
@@ -675,6 +695,13 @@ def s3_url(s3, s3_scratch, test_name_uuid):
675695
pass
676696

677697

698+
@pytest.fixture(scope="function")
699+
def s3_performance_url(s3, s3_performance, test_name_uuid):
700+
url = f"{s3_performance}/{test_name_uuid}"
701+
s3.mkdirs(url, exist_ok=False)
702+
return url
703+
704+
678705
GCS_REGION = "us-central1"
679706
GCS_BUCKET = "gs://coiled-oss-scratch/benchmarks-bot"
680707

@@ -843,3 +870,43 @@ def _(*args, **kwargs):
843870
@pytest.fixture(params=[0.1, 1])
844871
def memory_multiplier(request):
845872
return request.param
873+
874+
875+
@pytest.fixture
876+
def memray_profile(
877+
pytestconfig,
878+
s3,
879+
s3_performance_url,
880+
s3_storage_options,
881+
test_run_benchmark,
882+
tmp_path,
883+
):
884+
if not test_run_benchmark:
885+
yield
886+
else:
887+
memray_option = pytestconfig.getoption("--memray")
888+
889+
if memray_option == "none":
890+
yield contextlib.nullcontext
891+
elif memray_option != "scheduler":
892+
raise ValueError(f"Unhandled value for --memray: {memray_option}")
893+
else:
894+
895+
@contextlib.contextmanager
896+
def _memray_profile(client):
897+
profiles_path = tmp_path / "profiles"
898+
profiles_path.mkdir()
899+
try:
900+
with memray.memray_scheduler(directory=profiles_path):
901+
yield
902+
finally:
903+
archive = tmp_path / "memray.tar.gz"
904+
with tarfile.open(archive, mode="w:gz") as tar:
905+
for item in profiles_path.iterdir():
906+
tar.add(item, arcname=item.name)
907+
test_run_benchmark.memray_profiles_url = (
908+
f"{s3_performance_url}/{archive.name}"
909+
)
910+
s3.put(archive, s3_performance_url)
911+
912+
yield _memray_profile

tests/geospatial/conftest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def cluster_name(request, scale):
2727

2828

2929
@pytest.fixture()
30-
def client_factory(cluster_name, github_cluster_tags, benchmark_all):
30+
def client_factory(cluster_name, github_cluster_tags, benchmark_all, memray_profile):
3131
import contextlib
3232

3333
@contextlib.contextmanager
@@ -43,7 +43,7 @@ def _(n_workers, env=None, **cluster_kwargs):
4343
with cluster.get_client() as client:
4444
# FIXME https://github.com/coiled/platform/issues/103
4545
client.wait_for_workers(n_workers)
46-
with benchmark_all(client):
46+
with memray_profile(client), benchmark_all(client):
4747
yield client
4848

4949
return _

0 commit comments

Comments
 (0)