Fuse SamplingBatchInfo tensor construction into one pass
from_schedule_batch built temperature/top_p/top_k/min_p (+seed) with 4-5 separate list comprehensions and one synchronous H2D copy each, plus 4 more passes for the is_all_greedy/need_* flags. Collect everything in a single pass over reqs and upload the float params as one pinned non-blocking H2D copy (disjoint device views of one buffer; filter/merge only index and cat, producing fresh tensors, so the shared buffer is safe), int32 top_k and optional int64 seeds as their own pinned copies. B300 (torch 2.11 cu130), scheduler-thread blocking time per call: bs=8: 38.8 -> 18.2 us (2.1x); bs=32: 1.9x; bs=200: 1.2x CPU-only construction at bs=200: 2890 -> 1387 us (2.1x). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -464,6 +464,47 @@ class TestFromScheduleBatch(CustomTestCase):
|
||||
self.assertAlmostEqual(info.top_ps[0].item(), 0.9, places=5)
|
||||
self.assertEqual(info.top_ks[0].item(), 50)
|
||||
|
||||
@patch("sglang.srt.sampling.sampling_batch_info.get_global_server_args")
|
||||
def test_mixed_batch_tensor_values_dtypes_shapes(self, mock_server_args):
|
||||
"""All per-request params land in the right slot with the right dtype,
|
||||
and the fused float tensors are independent after filtering."""
|
||||
mock_server_args.return_value.enable_deterministic_inference = False
|
||||
mock_server_args.return_value.enable_custom_logit_processor = False
|
||||
|
||||
params = [
|
||||
dict(temp=0.5, top_p=0.7, top_k=10, min_p=0.2),
|
||||
dict(temp=1.0, top_p=1.0, top_k=1, min_p=0.0),
|
||||
dict(temp=1.3, top_p=0.95, top_k=TOP_K_ALL, min_p=0.05),
|
||||
]
|
||||
batch = MagicMock()
|
||||
batch.reqs = [self._make_req(**p) for p in params]
|
||||
batch.device = DEVICE
|
||||
info = SamplingBatchInfo.from_schedule_batch(batch, VOCAB_SIZE)
|
||||
|
||||
self.assertEqual(info.temperatures.shape, (3, 1))
|
||||
self.assertEqual(info.temperatures.dtype, torch.float32)
|
||||
self.assertEqual(info.top_ps.shape, (3,))
|
||||
self.assertEqual(info.top_ps.dtype, torch.float32)
|
||||
self.assertEqual(info.min_ps.shape, (3,))
|
||||
self.assertEqual(info.top_ks.dtype, torch.int32)
|
||||
for i, p in enumerate(params):
|
||||
self.assertAlmostEqual(info.temperatures[i, 0].item(), p["temp"], places=5)
|
||||
self.assertAlmostEqual(info.top_ps[i].item(), p["top_p"], places=5)
|
||||
self.assertEqual(info.top_ks[i].item(), p["top_k"])
|
||||
self.assertAlmostEqual(info.min_ps[i].item(), p["min_p"], places=5)
|
||||
self.assertFalse(info.is_all_greedy)
|
||||
self.assertTrue(info.need_top_p_sampling)
|
||||
self.assertTrue(info.need_top_k_sampling)
|
||||
self.assertTrue(info.need_min_p_sampling)
|
||||
|
||||
# Filtering must yield independent tensors with the right values even
|
||||
# though construction shares one fused buffer.
|
||||
keep = torch.tensor([2, 0], dtype=torch.int64)
|
||||
info.filter_batch([2, 0], keep)
|
||||
self.assertAlmostEqual(info.temperatures[0, 0].item(), 1.3, places=5)
|
||||
self.assertAlmostEqual(info.top_ps[1].item(), 0.7, places=5)
|
||||
self.assertEqual(info.top_ks[0].item(), TOP_K_ALL)
|
||||
|
||||
@patch("sglang.srt.sampling.sampling_batch_info.get_global_server_args")
|
||||
def test_greedy_detection(self, mock_server_args):
|
||||
"""Test that top_k=1 sets is_all_greedy=True."""
|
||||
|
||||
Reference in New Issue
Block a user