Skip to content

Commit f29710f

Browse files
committed
[None][fix] Fix gather_generation_logits corruption: per-slot fragmentPointerDevice
The mergeLogitsFragmentsKernel reads fragment GPU addresses from fragmentPointerDevice ([kCACHE_LENGTH]). When multiple requests in the same batch flush their logits fragments sequentially, each overwrites that shared device buffer before the previous kernel has committed its result on the stream — a race that caused intermittent degenerate output ("happ happ happ") with gather_generation_logits=True. Fix: resize fragmentPointerDevice from [kCACHE_LENGTH] to [maxBatchSize, kCACHE_LENGTH], matching the layout of fragmentPointerHost. Add getFragmentPointerDevice() to return the current-workIdx row without advancing it, and call it before getFragmentPointerHost() so both use the same per-slot row. Each request in the batch now has its own device-side pointer array, eliminating cross-request clobbering. Signed-off-by: Aurelien Chartier <2567591+achartier@users.noreply.github.com>
1 parent eea3b0f commit f29710f

3 files changed

Lines changed: 18 additions & 6 deletions

File tree

cpp/include/tensorrt_llm/batch_manager/runtimeBuffers.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ class RuntimeBuffers
208208
//! Temporarily store the transposed results of multiple fragment logits, [maxBeamWidth, kCACHE_LENGTH]
209209
TensorPtr transposedLogits;
210210

211-
//! Temporarily store logits buffer address during the transposing, [kCACHE_LENGTH]
211+
//! Temporarily store logits buffer address during the transposing, [maxBatchSize, kCACHE_LENGTH]
212+
//! One row per batch slot (same layout as fragmentPointerHost) so concurrent flushes for
213+
//! different requests in the same batch never clobber each other's pointer arrays.
212214
TensorPtr fragmentPointerDevice;
213215

214216
//! Temporarily store logits buffer address during the transposing, [maxBatchSize, kCACHE_LENGTH]
@@ -227,6 +229,12 @@ class RuntimeBuffers
227229
TensorPtr slice = runtime::ITensor::slice(fragmentPointerHost, workIdx, 1);
228230
cycleWorkIdx();
229231
return slice;
232+
}
233+
234+
//! Returns the device pointer row for the current workIdx (called before cycleWorkIdx).
235+
[[nodiscard]] TensorPtr getFragmentPointerDevice()
236+
{
237+
return runtime::ITensor::slice(fragmentPointerDevice, workIdx, 1);
230238
};
231239
};
232240

cpp/tensorrt_llm/batch_manager/runtimeBuffers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ void RuntimeBuffers::create(SizeType32 maxBatchSize, SizeType32 maxBeamWidth,
152152
ITensor::makeShape({GenerationLogitsCache::kCACHE_LENGTH, maxBatchSize * maxBeamWidth, vocabSizePadded}),
153153
logitsType);
154154

155-
generationLogitsCache.fragmentPointerDevice
156-
= manager.gpu(ITensor::makeShape({GenerationLogitsCache::kCACHE_LENGTH}), nvinfer1::DataType::kINT64);
155+
generationLogitsCache.fragmentPointerDevice = manager.gpu(
156+
ITensor::makeShape({maxBatchSize, GenerationLogitsCache::kCACHE_LENGTH}), nvinfer1::DataType::kINT64);
157157
generationLogitsCache.fragmentPointerHost = tensorrt_llm::runtime::BufferManager::pinnedPool(
158158
ITensor::makeShape({maxBatchSize, GenerationLogitsCache::kCACHE_LENGTH}), nvinfer1::DataType::kINT64);
159159
}

cpp/tensorrt_llm/batch_manager/utils/inflightBatchingUtils.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,14 @@ void copyGenerationLogits(RuntimeBuffers::GenerationLogitsCache& generationLogit
103103

104104
auto const fragmentSize = llmReq.getGenerationLogitsFragmentsSize();
105105

106-
// Merge logits fragments on device
106+
// Merge logits fragments on device.
107+
// getFragmentPointerDevice() reads the current workIdx row; getFragmentPointerHost() reads the
108+
// same row then advances workIdx. Calling device-slot first preserves the pairing so both
109+
// host and device pointer arrays use the same per-batch-slot row, preventing concurrent
110+
// flushes for different requests from clobbering each other's pointer arrays.
107111
auto const& transposeBufferPtr = generationLogitsCache.transposedLogits;
108-
auto const& cachePointerDevice = generationLogitsCache.fragmentPointerDevice;
109-
auto const& cachePointerHost = generationLogitsCache.getFragmentPointerHost();
112+
auto const cachePointerDevice = generationLogitsCache.getFragmentPointerDevice();
113+
auto const cachePointerHost = generationLogitsCache.getFragmentPointerHost();
110114
tensorrt_llm::runtime::kernels::mergeLogitsFragments(bufferManager, *transposeBufferPtr,
111115
llmReq.getGenerationLogitsFragments(), *cachePointerDevice, *cachePointerHost, 0, 1, reqBeamWidth,
112116
bufferManager.getStream(), 0);

0 commit comments

Comments
 (0)