123 lines
4.6 KiB
Python
123 lines
4.6 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
"""Tests for PrefillProgressTracker."""
|
|
|
|
import threading
|
|
import time
|
|
from unittest.mock import patch
|
|
|
|
from omlx.prefill_progress import PrefillProgressTracker
|
|
|
|
|
|
class TestPrefillProgressTracker:
|
|
def setup_method(self):
|
|
self.tracker = PrefillProgressTracker()
|
|
|
|
def test_update_and_get_progress(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert len(result) == 1
|
|
assert result[0]["request_id"] == "req-1"
|
|
assert result[0]["processed"] == 2048
|
|
assert result[0]["total"] == 8192
|
|
|
|
def test_auto_remove_on_complete(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 1
|
|
|
|
# Processed reaches total -> auto remove
|
|
self.tracker.update("req-1", 8192, 8192, "llama-3b")
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 0
|
|
|
|
def test_auto_remove_on_exceed(self):
|
|
self.tracker.update("req-1", 9000, 8192, "llama-3b")
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 0
|
|
|
|
def test_explicit_remove(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
self.tracker.remove("req-1")
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 0
|
|
|
|
def test_remove_nonexistent(self):
|
|
# Should not raise
|
|
self.tracker.remove("nonexistent")
|
|
|
|
def test_multiple_requests_same_model(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
self.tracker.update("req-2", 1024, 4096, "llama-3b")
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert len(result) == 2
|
|
ids = {r["request_id"] for r in result}
|
|
assert ids == {"req-1", "req-2"}
|
|
|
|
def test_multiple_models(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
self.tracker.update("req-2", 1024, 4096, "qwen-7b")
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 1
|
|
assert len(self.tracker.get_model_progress("qwen-7b")) == 1
|
|
assert len(self.tracker.get_model_progress("other")) == 0
|
|
|
|
def test_update_overwrites_previous(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
self.tracker.update("req-1", 4096, 8192, "llama-3b")
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert len(result) == 1
|
|
assert result[0]["processed"] == 4096
|
|
|
|
def test_clear(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
self.tracker.update("req-2", 1024, 4096, "qwen-7b")
|
|
self.tracker.clear()
|
|
assert len(self.tracker.get_model_progress("llama-3b")) == 0
|
|
assert len(self.tracker.get_model_progress("qwen-7b")) == 0
|
|
|
|
def test_speed_zero_on_first_update(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert result[0]["speed"] == 0.0
|
|
assert result[0]["eta"] is None
|
|
|
|
def test_speed_and_eta_calculation(self):
|
|
t = 100.0
|
|
with patch("omlx.prefill_progress.time") as mock_time:
|
|
mock_time.monotonic.return_value = t
|
|
self.tracker.update("req-1", 0, 8192, "llama-3b")
|
|
|
|
# 1 second later, processed 2048 tokens
|
|
mock_time.monotonic.return_value = t + 1.0
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert result[0]["speed"] == 2048.0
|
|
# eta = (8192 - 2048) / 2048 = 3.0 seconds
|
|
assert result[0]["eta"] == 3.0
|
|
|
|
def test_eta_none_when_speed_zero(self):
|
|
self.tracker.update("req-1", 2048, 8192, "llama-3b")
|
|
result = self.tracker.get_model_progress("llama-3b")
|
|
assert result[0]["eta"] is None
|
|
|
|
def test_thread_safety(self):
|
|
"""Concurrent updates from multiple threads should not corrupt state."""
|
|
errors = []
|
|
|
|
def updater(model_id, start):
|
|
try:
|
|
for i in range(100):
|
|
rid = f"req-{model_id}-{start + i}"
|
|
self.tracker.update(rid, i * 100, 10000, model_id)
|
|
if i % 2 == 0:
|
|
self.tracker.remove(rid)
|
|
except Exception as e:
|
|
errors.append(e)
|
|
|
|
threads = [
|
|
threading.Thread(target=updater, args=(f"model-{t}", t * 100))
|
|
for t in range(4)
|
|
]
|
|
for t in threads:
|
|
t.start()
|
|
for t in threads:
|
|
t.join()
|
|
|
|
assert not errors
|