Repository navigation
[TRTLLM-11042][feat] Implement suffix automaton on device for spec and support one model with help from @mahmoudhas #11434
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
Merged
+4,561
−243
Merged
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
1503aa8
init commit
cascade812 aba2525
first version works
cascade812 a070a1f
implement ngram using sa
cascade812 84c8963
pre-commit
cascade812 fb6da64
remove python fallback and update ngram test
cascade812 7274a59
remove 3 deprecated parameters
cascade812 be5be52
one model for ngram
cascade812 40ffa20
dynamic seq length
cascade812 1412a49
precommit
cascade812 e1771d1
remove unnecessary files
cascade812 82f835b
remove redundancy in sa manager and refactor mtp
cascade812 c4aad50
merge main branch
cascade812 39502e1
address comments
cascade812 5415e1a
revert remove 3 dreprecated parameters
cascade812 c0c1631
split sa as standalone technique
cascade812 294eaab
update tests
cascade812 a3c596e
restore ngram related
cascade812 60c714c
pre-commit
cascade812 1dbf519
address comments
cascade812 097e769
remove SampleStateTensorsMTP
cascade812 b24e159
fix test error
cascade812 0cedc79
Merge branch 'main' into guiju/at
cascade812 d8f449e
fix failed test after merge
cascade812 35f2851
Merge branch 'main' into guiju/at
cascade812 0260785
fix merge issue
cascade812 448733a
fix failed test
cascade812 88a0cc6
fix illegal memory access
cascade812 d35a301
add accuracy tests
cascade812 20529dd
merge branch main
cascade812 2ee99e8
Merge main
cascade812 ec4eb98
pre-commit
cascade812 daf4bd4
fix merge error
cascade812 8da1525
Merge branch 'main' into guiju/at
cascade812 8743318
update license
cascade812 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
294 changes: 294 additions & 0 deletions
294
cpp/tensorrt_llm/kernels/speculativeDecoding/suffixAutomaton/saBuffer.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,294 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| * Adapted from Baseten's sa_spec library (Apache-2.0) | ||
| * https://github.com/basetenlabs/sa_spec | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cassert> | ||
| #include <cstddef> | ||
| #include <cstring> | ||
| #include <type_traits> | ||
|
|
||
| #include "saCudaCallable.h" | ||
|
|
||
| #include "tensorrt_llm/common/config.h" | ||
|
|
||
| TRTLLM_NAMESPACE_BEGIN | ||
|
|
||
| namespace kernels::speculative_decoding::suffix_automaton | ||
| { | ||
|
|
||
| /** | ||
| * @brief A fixed-capacity buffer that uses external memory (pointer-based). | ||
| * | ||
| * This is a view into externally-managed memory. The buffer does not own | ||
| * the memory and does not perform any allocation/deallocation. | ||
| * | ||
| * This design enables: | ||
| * - Runtime-configurable capacity (no compile-time template parameter) | ||
| * - Trivially copyable (can be memcpy'd between host and GPU) | ||
| * - CUDA graph compatible (fixed memory addresses after initialization) | ||
| * | ||
| * @tparam T Element type (must be trivially copyable) | ||
| * @tparam IndexT Index type (default size_t) | ||
| */ | ||
| template <typename T, typename IndexT = size_t> | ||
| struct SABuffer | ||
| { | ||
| T* mData{nullptr}; | ||
| size_t mCapacity{0}; | ||
|
|
||
| T const& at(IndexT, IndexT) const = delete; | ||
| T& at(IndexT, IndexT) = delete; | ||
|
|
||
| SABuffer() = default; | ||
|
|
||
| SA_CUDA_CALLABLE void init(T* data, size_t capacity) | ||
| { | ||
| mData = data; | ||
| mCapacity = capacity; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T const& at(IndexT row) const | ||
| { | ||
| assert(static_cast<size_t>(+row) < mCapacity); | ||
| return mData[+row]; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T& at(IndexT row) | ||
| { | ||
| assert(static_cast<size_t>(+row) < mCapacity); | ||
| return mData[+row]; | ||
| } | ||
|
|
||
| struct Iterator | ||
| { | ||
| SABuffer const& buffer; | ||
| IndexT index; | ||
|
|
||
| SA_CUDA_CALLABLE Iterator(SABuffer const& buffer, IndexT index) | ||
| : buffer(buffer) | ||
| , index(index) | ||
| { | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T const& operator*() const | ||
| { | ||
| return buffer.at(index); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE Iterator& operator++() | ||
| { | ||
| index = IndexT(+index + 1); | ||
| return *this; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE bool operator==(Iterator const& other) const | ||
| { | ||
| return index == other.index; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE bool operator!=(Iterator const& other) const | ||
| { | ||
| return index != other.index; | ||
| } | ||
| }; | ||
|
|
||
| SA_CUDA_CALLABLE Iterator begin() const | ||
| { | ||
| return Iterator(*this, IndexT(0)); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE Iterator end() const | ||
| { | ||
| return Iterator(*this, IndexT(mCapacity)); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE size_t size() const | ||
| { | ||
| return mCapacity; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE size_t capacity() const | ||
| { | ||
| return mCapacity; | ||
| } | ||
|
|
||
| void clear() | ||
| { | ||
| if (mData && mCapacity > 0) | ||
| { | ||
| memset(static_cast<void*>(mData), 0, mCapacity * sizeof(T)); | ||
| } | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T* data() | ||
| { | ||
| return mData; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T const* data() const | ||
| { | ||
| return mData; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Relocate the data pointer by a given delta. | ||
| * | ||
| * Used when copying between host and GPU memory to adjust pointers. | ||
| */ | ||
| void relocate(ptrdiff_t delta) | ||
| { | ||
| if (mData) | ||
| { | ||
| mData = reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(mData) + delta); | ||
| } | ||
| } | ||
|
|
||
| static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable"); | ||
| }; | ||
|
|
||
| /** | ||
| * @brief A dynamic buffer with runtime-configurable capacity using external memory. | ||
| * | ||
| * Like SABuffer, but tracks current length separately from capacity. | ||
| * Supports push/pop operations up to the capacity limit. | ||
| * | ||
| * @tparam T Element type (must be trivially copyable) | ||
| * @tparam IndexT Index type (default size_t) | ||
| */ | ||
| template <typename T, typename IndexT = size_t> | ||
| struct SADynamicBuffer | ||
| { | ||
| T* mData{nullptr}; | ||
| size_t mCapacity{0}; | ||
| IndexT mLength{0}; | ||
|
|
||
| SADynamicBuffer() = default; | ||
|
|
||
| SA_CUDA_CALLABLE void init(T* data, size_t capacity) | ||
| { | ||
| mData = data; | ||
| mCapacity = capacity; | ||
| mLength = IndexT(0); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE void clear() | ||
| { | ||
| mLength = IndexT(0); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE IndexT size() const | ||
| { | ||
| return mLength; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE size_t capacity() const | ||
| { | ||
| return mCapacity; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE bool empty() const | ||
| { | ||
| return +size() == 0; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE void extend(size_t n) | ||
| { | ||
| mLength = IndexT(+mLength + n); | ||
| assert(static_cast<size_t>(+mLength) <= mCapacity); | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T& pushBack(T const& value) | ||
| { | ||
| assert(static_cast<size_t>(+mLength) < mCapacity); | ||
|
|
||
| T& result = mData[+mLength]; | ||
| result = value; | ||
| mLength = IndexT(+mLength + 1); | ||
| return result; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T& pushBack(T&& value) | ||
| { | ||
| assert(static_cast<size_t>(+mLength) < mCapacity); | ||
| T& result = mData[+mLength]; | ||
| result = std::move(value); | ||
| mLength = IndexT(+mLength + 1); | ||
| return result; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T& popBack() | ||
| { | ||
| assert(!empty()); | ||
| T& result = mData[+mLength - 1]; | ||
| mLength = IndexT(+mLength - 1); | ||
| return result; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T const& at(IndexT row) const | ||
| { | ||
| assert(row < mLength); | ||
| return mData[+row]; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T& at(IndexT row) | ||
| { | ||
| assert(row < mLength); | ||
| return mData[+row]; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T* data() | ||
| { | ||
| return mData; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE T const* data() const | ||
| { | ||
| return mData; | ||
| } | ||
|
|
||
| SA_CUDA_CALLABLE bool hasCapacity() const | ||
| { | ||
| return static_cast<size_t>(+mLength) < mCapacity; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Relocate the data pointer by a given delta. | ||
| * | ||
| * Used when copying between host and GPU memory to adjust pointers. | ||
| */ | ||
| void relocate(ptrdiff_t delta) | ||
| { | ||
| if (mData) | ||
| { | ||
| mData = reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(mData) + delta); | ||
| } | ||
| } | ||
|
|
||
| static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable"); | ||
| }; | ||
|
|
||
| // Verify that our buffer types are trivially copyable (required for GPU memcpy) | ||
| static_assert(std::is_trivially_copyable<SABuffer<int>>::value, "SABuffer must be trivially copyable"); | ||
| static_assert(std::is_trivially_copyable<SADynamicBuffer<int>>::value, "SADynamicBuffer must be trivially copyable"); | ||
|
|
||
| } // namespace kernels::speculative_decoding::suffix_automaton | ||
|
|
||
| TRTLLM_NAMESPACE_END |
33 changes: 33 additions & 0 deletions
33
cpp/tensorrt_llm/kernels/speculativeDecoding/suffixAutomaton/saCudaCallable.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2022-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| * Adapted from Baseten's sa_spec library (Apache-2.0) | ||
| * https://github.com/basetenlabs/sa_spec | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #ifdef __CUDACC__ | ||
| #include <cuda_runtime.h> | ||
| #define SA_CUDA_CALLABLE __host__ __device__ __forceinline__ | ||
| #else | ||
| #define SA_CUDA_CALLABLE | ||
| // Provide a placeholder type for cudaStream_t when not compiling with CUDA. | ||
| // Only define if not already defined to avoid conflicts with cuda_runtime_api.h. | ||
| #if !defined(cudaStream_t) | ||
| #define cudaStream_t int | ||
| #endif | ||
| #endif // __CUDACC__ | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.