TensorRT-LLM Coding Guidelines
This document outlines the coding standards and guidelines for contributing to TensorRT-LLM. Following these guidelines ensures consistency, maintainability, and quality across the codebase.C++ Coding Guidelines
The TensorRT-LLM C++ Coding Guidelines are mainly derived from the Google C++ Style Guide.Namespaces
Closing braces of namespaces should have a comment saying the namespace it closes:Constants
- Prefer
constorconstexprvariables over#defineswhenever possible, as the latter are not visible to the compiler. - A variable that is not modified after its initialization should be declared as
const. - For naming of constants, see the Naming section.
Literals
Except0 (only used in comparison for checking signness/existence/emptiness) and nullptr, true, false, all other literals should only be used for variable initialization.
Example:
Brace Notation
- Use the Allman indentation style.
- Put the semicolon for an empty
fororwhileloop in a new line. - The statement forming the body of a
switch,while,do .. whileorforstatement shall be a compound statement (use brace-delimited statements). ifandelseshould always be followed by brace-delimited statements, even if empty or a single statement.
Naming
1. Filenames
- Camel case with first letter lowercase:
thisIsASubDirandthisIsAFilename.cpp - All files involved in the compilation of a compilation target (.exe/.so) must have filenames that are case-insensitive unique.
2. Types
- All types (including class names) are camel case with uppercase first letter.
- Example:
FooBarClass
3. Local Variables, Methods and Namespaces
- Camel case with first letter lowercase.
- Example:
localFooBar
4. Non-magic-number Global Variables (non-static, not in anonymous namespace)
- Camel case prefixed by a lower case ‘g’.
- Example:
gDontUseGlobalFoos
5. Non-magic-number Global Variables (static or in anonymous namespace)
- Camel case prefixed by a lower case ‘s’.
- Example:
sMutableStaticGlobal
6. Locally Visible Static Variable
- Camel case with lowercase prefix ‘s’ as the first letter of the name.
- Example:
static std::once_flag sFlag;
7. Class Member Variables
- Camelcase prefixed with an ‘m’:
mNbFooValues. - Public member variables do not require the ‘m’ prefix but it is highly encouraged to use the prefix when needed to improve code clarity.
8. Constants
- Enumerations, global constants, static constants at class-scope and function-scope magic-number/literal constants are uppercase snakecase with prefix ‘k’:
Function-scope constants that are not magic numbers or literals are named like non-constant variables:
9. Macros
- See Constants section (preferred over
#define). - If you must use macros, follow uppercase snakecase:
FOO_VERSION
Naming Notes
- In general don’t use hungarian notation, except for ‘apps hungarian’ in some cases such as ‘nb’ in a variable name to indicate count:
mNbLayers - If a constructor’s parameter name
fooconflicts with a public member namefoo, add a trailing underscore to the parameter name:foo_. - Literal suffixes should be upper case. For example, use
1234Linstead of1234l.
Tabs vs Spaces
- Use only spaces. Do not use tabs.
- Indent 4 spaces at a time. This is enforced automatically if you format your code using our clang-format config.
Formatting
- Use the LLVM clang-format tool for formatting your changes prior to submitting the PR.
- Use a maximum of 120 characters per line. The auto formatting tool will wrap longer lines.
- Exceptions to formatting violations must be justified on a per-case basis. Bypassing the formatting rules is discouraged, but can be achieved for exceptions as follows:
Pointers and Memory Allocation
- Use smart pointers for allocating objects on the heap.
- When picking a smart pointer, prefer
unique_ptrfor single resource ownership andshared_ptrfor shared resource ownership. Useweak_ptronly in exceptional cases. - Do not use smart pointers that have been deprecated in C++11.
Comments
- C++ comments are required. C comments are not allowed except for special cases (inline).
- C++ style for single-line comments:
// This is a single line comment - In function calls where parameters are not obvious from inspection, it can be helpful to use an inline C comment to document the parameter for readers:
- If the comment is a full sentence, it should be capitalized and punctuated properly.
- Follow Doxygen rules for documenting new class interfaces and function prototypes:
- For C++-style single-line comments use
//!. - For class members, use
//!<.
- For C++-style single-line comments use
Preprocessor Directives
#defineand#undefof macros should be done only at global namespace.- Avoid the use of
#ifdefand#ifndefdirectives (except in the case of header include guards). Prefer to use#if defined(...)or#if !defined(...)instead:
- When nesting preprocessor directives, use indentation after the hash mark (#):
- Use a preprocessor guard:
- The guard name must have prefix
TRTLLM_followed by the filename, all in caps. - For a header file named
FooBarHello.h, name the symbol asTRTLLM_FOO_BAR_HELLO_H. - Only use the file name to create the symbol.
- Do not use prefix with underscore or trailing underscore.
- The guard name must have prefix
Additional C++ Guidelines
- Exceptions: Must not be thrown across library boundaries.
- Casts: Use the least forceful cast necessary. Prefer
static_castoverreinterpret_cast. Avoiddynamic_cast. - Expressions: Do not use assignment operator in subexpressions.
- Switch Statements: Should be well-structured with proper breaks or throws.
- Functions: Avoid large inline functions. Use anonymous namespaces instead of static for internal linkage.
- Signed vs Unsigned: Use signed integers by default, except for bitmaps or when interfacing with libraries that expect unsigned.
Common Pitfalls
- C headers: Use C++ headers instead (e.g.,
<cstdint>instead of<stdint.h>). - C library functions: Avoid when possible. Use brace initialization or
std::fill_n()instead ofmemset().
Python Coding Guidelines
Python Standard
The code developed for TensorRT-LLM should conform to Python 3.8+.Indentation
Indent code with 4 spaces. Do not use tabs.Imports
Always maintain the namespace when importing, even if only one class or function from a module is used. Example:Naming
Identifier Format
- Files:
snake_case-some_file.py - Classes:
PascalCase-class SomeClass - Functions and Methods:
snake_case-def my_awesome_function(): - Local Variables:
snake_case-my_variable = ...- Prefix
kfor variable names that start with a number:k_99th_percentile = ...
- Prefix
- Global Variables: upper
snake_caseand prefixG-G_MY_GLOBAL = ... - Constants: upper
snake_case-MY_CONSTANT = ...
Identifier Guidelines
- Avoid shadowing variables declared in an outer scope.
- Initialize all externally visible members of a class in the constructor.
Comments and Docstrings
- For interfaces that may be used outside a file, prefer docstrings over comments.
- Comments should be reserved for code within a function, or interfaces that are local to a file.
Docstring Syntax
Use the Google style, which can be parsed by Sphinx. Example:Pydantic Guidelines
When defining any user-facing configuration classes (particularlyLlmArgs or any class used in its fields), always use Pydantic classes rather than dataclasses or vanilla classes.
Model Structure
- Inherit from
StrictBaseModel(which setsextra="forbid") to fail fast when users specify invalid field names - Use discriminated unions when a field needs to accept one of several possible config classes
- Do not define
__init__methods - this bypasses Pydantic’s validation and type coercion. Instead:- For validation logic, use
@field_validatoror@model_validator - For post-validation initialization, use
model_post_init() - For custom construction patterns, use classmethods (e.g.
from_yaml())
- For validation logic, use
Field Definitions
- Add descriptions to all user-facing fields via
Field(description="..."). Avoid using comments for descriptions. - Avoid
dict,object,Anyas field types - use properly typed alternatives - Avoid defining mutable defaults directly; use
default_factoryinstead:- Good:
Field(default_factory=list),Field(default_factory=dict) - Bad:
Field(default=[]),Field(default={})
- Good:
- Use
Literal["value1", "value2"]instead ofstrwhen a field should only accept certain values - Prefer
PositiveInt,NonNegativeInt,NonNegativeFloat,PositiveFloat,Field(gt=0),Field(ge=0)for numeric constraints - Use
Field(min_length=1)to enforce minimum length of a list
Validation
- Use
@field_validatorand@model_validatorinstead of manualvalidate()oris_valid()methods - Raise
ValueErrorinstead of using assertions - Co-locate validation logic within the class itself rather than in a parent class
Serialization
- Avoid defining
to_dict()methods - prefer Pydantic’s built-inmodel_dump():- Good:
MyModel.model_dump() - Bad:
MyModel.to_dict()
- Good:
- Avoid defining
from_dict()/from_kwargs()methods - prefer constructing the class directly:- Good:
MyModel(**kwargs),MyModel(**my_dict) - Bad:
MyModel.from_dict(kwargs)
- Good:
Error Handling
- When using try-except blocks, limit the except to the smallest set of errors possible:
- When using try-except blocks to handle multiple possible variable types, keep the body of the try as small as possible:
Avoid Reflection
Avoid using reflection when functionality can be easily achieved without reflection.Pre-commit Hooks
We usepre-commit for automatic code formatting and validation. Install and set up pre-commit hooks:
- isort: Import sorting
- yapf: Python code formatting
- clang-format: C++ code formatting
- cmake-format: CMake file formatting
- autoflake: Remove unused imports
- ruff: Python linting
- codespell: Spell checking
- mdformat: Markdown formatting
Documentation Guidelines
CLI Options in Documentation
When documenting CLI commands fortrtllm-serve, trtllm-bench, trtllm-eval, or similar tools, prefer using --config over --extra_llm_api_options for specifying configuration files.
Example:
NVIDIA Copyright
All TensorRT-LLM Open Source Software code should contain an NVIDIA copyright header that includes the year of its latest meaningful modification. The following block of text should be prepended to the top of all files (.cpp, .h, .cu, .py, and other source files):
Update the copyright year to the current year when modifying existing files.
Summary
Following these coding guidelines ensures:- Consistency: Code is uniform across the entire codebase
- Maintainability: Code is easier to read, understand, and modify
- Quality: Automated tools catch common errors and enforce best practices
- Collaboration: Team members can work together more effectively