-
Notifications
You must be signed in to change notification settings - Fork 391
[tinker] Fix per-tenant blocking on forward/forward_backward calls #1920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
|
|
||
| import argparse | ||
| import time | ||
| from collections import defaultdict | ||
| from contextlib import contextmanager | ||
| from datetime import datetime, timedelta, timezone | ||
| from pathlib import Path | ||
|
|
@@ -728,28 +729,39 @@ def process_batch_requests( | |
| requests: dict[str, tuple[str, BaseModel]], | ||
| processor: Callable[[dict[str, tuple[str, BaseModel]]], dict[str, BaseModel]], | ||
| name: str, | ||
| per_model: bool = False, | ||
| ): | ||
| """Process a batch of requests with error handling and future completion. | ||
|
|
||
| Args: | ||
| requests: Dict mapping request_id to (model_id, request_data) tuples | ||
| processor: Function that processes requests and returns results dict | ||
| name: Name for logging | ||
| per_model: Process one model's requests at a time, completing each | ||
| model's futures as soon as its sub-batch finishes (GPU execution | ||
| is serialized per model anyway; this only changes completion | ||
| granularity, not batching within a model). | ||
| """ | ||
| if not requests: | ||
| return | ||
| with log_timing(f"process_batch_requests({name}, n={len(requests)})"): | ||
| try: | ||
| error_results, valid_requests = self._filter_valid_requests(requests) | ||
| if valid_requests: | ||
| results = processor(valid_requests) | ||
| results.update(error_results) | ||
| else: | ||
| results = error_results | ||
| except Exception as e: | ||
| logger.exception(f"Error processing batch: {e}") | ||
| results = {request_id: types.ErrorResponse(error=str(e), status="failed") for request_id in requests} | ||
| self._complete_futures(results) | ||
| error_results, valid_requests = self._filter_valid_requests(requests) | ||
| if error_results: | ||
| self._complete_futures(error_results) | ||
| if per_model: | ||
| grouped: dict[str, dict] = defaultdict(dict) | ||
| for request_id, item in valid_requests.items(): | ||
| grouped[item[0]][request_id] = item | ||
| groups = list(grouped.values()) | ||
| else: | ||
| groups = [valid_requests] if valid_requests else [] | ||
| for group in groups: | ||
| with log_timing(f"process_batch_requests({name}, n={len(group)})"): | ||
|
Comment on lines
+757
to
+758
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a multi-tenant environment where multiple models are processed, logging the timing of each model's sub-batch with its specific for group in groups:
model_id = next(iter(group.values()))[0] if group else "unknown"
with log_timing(f"process_batch_requests({name}, model={model_id}, n={len(group)})"): |
||
| try: | ||
| results = processor(group) | ||
| except Exception as e: | ||
| logger.exception(f"Error processing batch: {e}") | ||
| results = {request_id: types.ErrorResponse(error=str(e), status="failed") for request_id in group} | ||
| self._complete_futures(results) | ||
|
|
||
| def process_pending_requests(self): | ||
| """Main loop to process pending requests.""" | ||
|
|
@@ -767,8 +779,10 @@ def process_pending_requests(self): | |
| other_requests = self.find_single_requests(session) | ||
|
|
||
| # Process batches outside of session context | ||
| self.process_batch_requests(forward_backward_requests, self.process_forward_backward, "forward_backward") | ||
| self.process_batch_requests(forward_requests, self.process_forward, "forward") | ||
| self.process_batch_requests( | ||
| forward_backward_requests, self.process_forward_backward, "forward_backward", per_model=True | ||
| ) | ||
| self.process_batch_requests(forward_requests, self.process_forward, "forward", per_model=True) | ||
| self.process_batch_requests(sample_requests, self.process_sample, "sample") | ||
|
|
||
| # Process other request types individually (in the future we can also batch independent optim_steps) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type annotation for
groupedis currentlydict[str, dict], which is a bit too generic. Providing a more precise type annotation likedict[str, dict[str, tuple[str, BaseModel]]]will improve code maintainability and allow static analysis tools (such as mypy or pyright) to correctly type-check thegroupslist and ensure compatibility with theprocessorfunction signature.