2022-05-17 10:50:42 +02:00
|
|
|
load("@bazel_skylib//lib:paths.bzl", "paths")
|
|
|
|
|
|
2020-08-30 14:09:34 +08:00
|
|
|
# py_test_module_list creates a py_test target for each
|
2020-08-06 10:58:42 -07:00
|
|
|
# Python file in `files`
|
2022-05-19 21:46:55 -07:00
|
|
|
|
2025-03-19 14:24:08 -05:00
|
|
|
def _convert_target_to_import_path(t):
|
|
|
|
|
"""Get a Python import path for the provided bazel file target."""
|
|
|
|
|
if not t.startswith("//"):
|
|
|
|
|
fail("Must be an absolute target starting in '//'.")
|
|
|
|
|
if not t.endswith(".py"):
|
|
|
|
|
fail("Must end in '.py'.")
|
2023-05-30 10:15:49 -07:00
|
|
|
|
2025-03-19 14:24:08 -05:00
|
|
|
# 1) Strip known prefix and suffix (validated above).
|
|
|
|
|
t = t[len("//"):-len(".py")]
|
|
|
|
|
# 2) Normalize separators to '/'.
|
|
|
|
|
t = t.replace(":", "/")
|
|
|
|
|
# 3) Replace '/' with '.' to form an import path.
|
|
|
|
|
return t.replace("/", ".")
|
|
|
|
|
|
2025-08-20 15:23:23 -07:00
|
|
|
def doctest_each(files, gpu = False, deps=[], srcs=[], data=[], args=[], size="medium", tags=[], pytest_plugin_file="//bazel:default_doctest_pytest_plugin.py", **kwargs):
|
|
|
|
|
# Unlike the `doctest` macro, `doctest_each` runs `pytest` on each file separately.
|
|
|
|
|
# This is useful to run tests in parallel and more clearly report the test results.
|
|
|
|
|
for file in files:
|
|
|
|
|
doctest(
|
|
|
|
|
files = [file],
|
|
|
|
|
gpu = gpu,
|
|
|
|
|
name = paths.split_extension(file)[0],
|
|
|
|
|
deps = deps,
|
|
|
|
|
srcs = srcs,
|
|
|
|
|
data = data,
|
|
|
|
|
args = args,
|
|
|
|
|
size = size,
|
|
|
|
|
tags = tags,
|
|
|
|
|
pytest_plugin_file = pytest_plugin_file,
|
|
|
|
|
**kwargs
|
|
|
|
|
)
|
|
|
|
|
|
2025-03-19 14:24:08 -05:00
|
|
|
def doctest(files, gpu = False, name="doctest", deps=[], srcs=[], data=[], args=[], size="medium", tags=[], pytest_plugin_file="//bazel:default_doctest_pytest_plugin.py", **kwargs):
|
2023-05-30 10:15:49 -07:00
|
|
|
# NOTE: If you run `pytest` on `__init__.py`, it tries to test all files in that
|
|
|
|
|
# package. We don't want that, so we exclude it from the list of input files.
|
|
|
|
|
files = native.glob(include=files, exclude=["__init__.py"])
|
|
|
|
|
if gpu:
|
|
|
|
|
name += "[gpu]"
|
|
|
|
|
tags = tags + ["gpu"]
|
|
|
|
|
else:
|
|
|
|
|
tags = tags + ["cpu"]
|
|
|
|
|
|
2025-03-19 14:24:08 -05:00
|
|
|
|
2023-05-30 10:15:49 -07:00
|
|
|
native.py_test(
|
|
|
|
|
name = name,
|
|
|
|
|
srcs = ["//bazel:pytest_wrapper.py"] + srcs,
|
|
|
|
|
main = "//bazel:pytest_wrapper.py",
|
|
|
|
|
size = size,
|
|
|
|
|
args = [
|
|
|
|
|
"--doctest-modules",
|
2023-06-12 14:49:24 -07:00
|
|
|
"--doctest-glob='*.md'",
|
2023-07-25 19:57:28 -05:00
|
|
|
"--disable-warnings",
|
2025-03-19 14:24:08 -05:00
|
|
|
"-v",
|
|
|
|
|
# Don't pick up the global pytest.ini for doctests.
|
|
|
|
|
"-c", "NO_PYTEST_CONFIG",
|
|
|
|
|
# Pass the provided pytest plugin as a Python import path.
|
|
|
|
|
"-p", _convert_target_to_import_path(pytest_plugin_file),
|
2023-05-30 10:15:49 -07:00
|
|
|
] + args + ["$(location :%s)" % file for file in files],
|
2025-03-19 14:24:08 -05:00
|
|
|
data = [pytest_plugin_file] + files + data,
|
2023-05-30 10:15:49 -07:00
|
|
|
python_version = "PY3",
|
|
|
|
|
srcs_version = "PY3",
|
|
|
|
|
tags = ["doctest"] + tags,
|
|
|
|
|
deps = ["//:ray_lib"] + deps,
|
|
|
|
|
**kwargs
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2022-07-19 12:21:19 +08:00
|
|
|
def py_test_module_list(files, size, deps, extra_srcs=[], name_suffix="", **kwargs):
|
2020-08-30 14:09:34 +08:00
|
|
|
for file in files:
|
|
|
|
|
# remove .py
|
2022-05-17 10:50:42 +02:00
|
|
|
name = paths.split_extension(file)[0] + name_suffix
|
|
|
|
|
if name == file:
|
|
|
|
|
basename = basename + "_test"
|
2020-08-30 14:09:34 +08:00
|
|
|
native.py_test(
|
|
|
|
|
name = name,
|
|
|
|
|
size = size,
|
2020-12-20 14:54:18 -08:00
|
|
|
main = file,
|
2020-08-30 14:09:34 +08:00
|
|
|
srcs = extra_srcs + [file],
|
2022-07-19 12:21:19 +08:00
|
|
|
deps = deps,
|
2020-08-30 14:09:34 +08:00
|
|
|
**kwargs
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def py_test_run_all_subdirectory(include, exclude, extra_srcs, **kwargs):
|
2022-05-17 10:50:42 +02:00
|
|
|
for file in native.glob(include = include, exclude = exclude, allow_empty=False):
|
|
|
|
|
basename = paths.split_extension(file)[0]
|
|
|
|
|
if basename == file:
|
|
|
|
|
basename = basename + "_test"
|
2020-08-30 14:09:34 +08:00
|
|
|
native.py_test(
|
2022-05-17 10:50:42 +02:00
|
|
|
name = basename,
|
2020-08-30 14:09:34 +08:00
|
|
|
srcs = extra_srcs + [file],
|
|
|
|
|
**kwargs
|
|
|
|
|
)
|
2022-02-27 08:07:34 +01:00
|
|
|
|
|
|
|
|
# Runs all included notebooks as py_test targets, by first converting them to .py files with "test_myst_doc.py".
|
2022-07-09 19:47:21 -07:00
|
|
|
def py_test_run_all_notebooks(include, exclude, allow_empty=False, **kwargs):
|
|
|
|
|
for file in native.glob(include = include, exclude = exclude, allow_empty=allow_empty):
|
2022-02-27 08:07:34 +01:00
|
|
|
print(file)
|
2022-05-17 10:50:42 +02:00
|
|
|
basename = paths.split_extension(file)[0]
|
|
|
|
|
if basename == file:
|
|
|
|
|
basename = basename + "_test"
|
2022-02-27 08:07:34 +01:00
|
|
|
native.py_test(
|
2022-05-17 10:50:42 +02:00
|
|
|
name = basename,
|
2022-02-27 08:07:34 +01:00
|
|
|
main = "test_myst_doc.py",
|
2022-05-17 10:50:42 +02:00
|
|
|
srcs = ["//doc:test_myst_doc.py"],
|
|
|
|
|
# --find-recursively will look for file in all
|
|
|
|
|
# directories inside cwd recursively if it cannot
|
|
|
|
|
# find it right away. This allows to deal with
|
|
|
|
|
# mismatches between `name` and `data` args.
|
|
|
|
|
args = ["--find-recursively", "--path", file],
|
2022-02-27 08:07:34 +01:00
|
|
|
**kwargs
|
|
|
|
|
)
|
Aggregate autoscaling metrics on controller (#56306)
## Controller Metrics Aggregation + Code Refactoring
### What Changed
- **New Feature**: Added `RAY_SERVE_AGGREGATE_METRICS_AT_CONTROLLER`
flag to enable metrics aggregation at controller level using timeseries
merging
- **Code Cleanup**: Refactored `get_total_num_requests()` as it was
starting to get complicated
- **Enhanced Testing**: Added multi-environment test variants to cover
different metrics collection modes
**Fully backward compatible** - existing behavior unchanged when flag is
disabled.
### Changed the merge algorithm
i think the problem is the current algorithm that uses latest in bucket
during merge is not robust and is lossy. Which make it highly
susceptible to the choice of bucket width.
I am going to rewrite that algorithm as follows to see if it helps
Interpret each replica’s gauge as **right-continuous,
last-observation-carried-forward (LOCF)**. Then:
1. **Turn each replica into “delta events.”**
For a sorted series $(t_0,v_0),(t_1,v_1),…$ emit:
* at $t_0$: $+\;v_0$
* at $t_j$: $+\;(v_j - v_{j-1})$ for $j\ge1$
2. **K-way merge all events by time.**
Maintain `current_sum`. At each event time $t$, apply the sum of all
deltas at $t$, update `current_sum`, and **record a point** $(t,
current_sum)$.
The result is an **event-driven, piecewise-constant series** $S(t)$:
between event timestamps it holds constant and represents the
instantaneous total across replicas.
3. **Resample to a regular grid** To get the instantaneous value at grid
time $g_k$, take the last event at or before $g_k$ (LOCF on the merged
step series).
## Next PR
https://github.com/ray-project/ray/pull/56311
---------
Signed-off-by: abrar <abrar@anyscale.com>
2025-09-23 14:29:50 -07:00
|
|
|
|
|
|
|
|
def py_test_module_list_with_env_variants(files, env_variants, size="medium", **kwargs):
|
|
|
|
|
"""Create multiple py_test_module_list targets with different environment variable configurations.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
files: List of test files to run
|
|
|
|
|
env_variants: Dict where keys are variant names and values are dicts containing
|
|
|
|
|
'env' and 'name_suffix' keys
|
|
|
|
|
size: Test size
|
|
|
|
|
**kwargs: Additional arguments passed to py_test_module_list
|
|
|
|
|
"""
|
|
|
|
|
for variant_name, variant_config in env_variants.items():
|
|
|
|
|
py_test_module_list(
|
|
|
|
|
size = size,
|
|
|
|
|
files = files,
|
|
|
|
|
env = variant_config.get("env", {}),
|
|
|
|
|
name_suffix = variant_config.get("name_suffix", "_{}".format(variant_name)),
|
|
|
|
|
**kwargs
|
|
|
|
|
)
|