151 lines
5.0 KiB
Python
151 lines
5.0 KiB
Python
import pytest
|
|
|
|
from ray.data._internal.cluster_autoscaler.throughput_solver import (
|
|
allocate_resources,
|
|
compute_optimal_throughput,
|
|
)
|
|
from ray.data._internal.execution.interfaces import ExecutionResources
|
|
|
|
|
|
class TestComputeOptimalThroughput:
|
|
def test_one_op_cpu_bound(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources(cpu=1)},
|
|
resource_limits=ExecutionResources.for_limits(cpu=2),
|
|
concurrency_limits={"A": float("inf")},
|
|
)
|
|
assert result == pytest.approx(2.0)
|
|
|
|
def test_one_op_gpu_bound(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources(gpu=1)},
|
|
resource_limits=ExecutionResources.for_limits(gpu=2),
|
|
concurrency_limits={"A": float("inf")},
|
|
)
|
|
assert result == pytest.approx(2.0)
|
|
|
|
def test_one_op_memory_bound(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources(memory=1e6)},
|
|
resource_limits=ExecutionResources.for_limits(memory=2e6),
|
|
concurrency_limits={"A": float("inf")},
|
|
)
|
|
assert result == pytest.approx(2.0)
|
|
|
|
def test_one_op_concurrency_bound(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources(cpu=1)},
|
|
resource_limits=ExecutionResources.for_limits(),
|
|
concurrency_limits={"A": 2},
|
|
)
|
|
assert result == pytest.approx(2.0)
|
|
|
|
def test_two_ops_equal_rates(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0, "B": 1.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
"B": ExecutionResources(cpu=1),
|
|
},
|
|
resource_limits=ExecutionResources.for_limits(cpu=2),
|
|
concurrency_limits={"A": float("inf"), "B": float("inf")},
|
|
)
|
|
assert result == pytest.approx(1.0)
|
|
|
|
def test_two_ops_different_rates(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0, "B": 2.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
"B": ExecutionResources(cpu=1),
|
|
},
|
|
resource_limits=ExecutionResources.for_limits(cpu=3),
|
|
concurrency_limits={"A": float("inf"), "B": float("inf")},
|
|
)
|
|
assert result == pytest.approx(2.0)
|
|
|
|
def test_two_ops_different_resource_requirements(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0, "B": 1.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
"B": ExecutionResources(cpu=2),
|
|
},
|
|
resource_limits=ExecutionResources.for_limits(cpu=3),
|
|
concurrency_limits={"A": float("inf"), "B": float("inf")},
|
|
)
|
|
assert result == pytest.approx(1.0)
|
|
|
|
def test_zero_resource_requirement(self):
|
|
result = compute_optimal_throughput(
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources.zero()},
|
|
resource_limits=ExecutionResources.for_limits(cpu=1),
|
|
concurrency_limits={"A": float("inf")},
|
|
)
|
|
assert result == float("inf")
|
|
|
|
|
|
class TestAllocateResources:
|
|
def test_empty_rates(self):
|
|
result = allocate_resources(
|
|
0.0,
|
|
rates={},
|
|
resource_requirements={},
|
|
)
|
|
assert result == {}
|
|
|
|
def test_zero_throughput(self):
|
|
result = allocate_resources(
|
|
0.0,
|
|
rates={"A": 1.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
},
|
|
)
|
|
assert result == {
|
|
"A": ExecutionResources.zero(),
|
|
}
|
|
|
|
def test_one_op(self):
|
|
result = allocate_resources(
|
|
1.0,
|
|
rates={"A": 1.0},
|
|
resource_requirements={"A": ExecutionResources(cpu=1)},
|
|
)
|
|
assert result["A"] == ExecutionResources(cpu=1)
|
|
|
|
def test_two_ops_different_rates(self):
|
|
result = allocate_resources(
|
|
2.0,
|
|
rates={"A": 1.0, "B": 2.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
"B": ExecutionResources(cpu=1),
|
|
},
|
|
)
|
|
assert result["A"] == ExecutionResources(cpu=2)
|
|
assert result["B"] == ExecutionResources(cpu=1)
|
|
|
|
def test_two_ops_different_resource_requirements(self):
|
|
result = allocate_resources(
|
|
1.0,
|
|
rates={"A": 1.0, "B": 1.0},
|
|
resource_requirements={
|
|
"A": ExecutionResources(cpu=1),
|
|
"B": ExecutionResources(cpu=2),
|
|
},
|
|
)
|
|
assert result["A"] == ExecutionResources(cpu=1)
|
|
assert result["B"] == ExecutionResources(cpu=2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
sys.exit(pytest.main(["-v", __file__]))
|