Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions .github/workflows/linux_x64_cuda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ jobs:
# Copy test binary and testdata to install directory for artifact upload
cp out/build/trt_ep_tests out/${ARTIFACT_NAME}/bin/ 2>/dev/null || true
cp -r out/build/testdata out/${ARTIFACT_NAME}/bin/testdata 2>/dev/null || true
# Copy libonnxruntime.so from NuGet package so unit tests can find it at runtime
cp out/build/_deps/ortlib-src/runtimes/linux-x64/native/libonnxruntime.so out/${ARTIFACT_NAME}/bin/ 2>/dev/null || true
# Create versioned symlink (binary links against libonnxruntime.so.1)
ln -sf libonnxruntime.so out/${ARTIFACT_NAME}/bin/libonnxruntime.so.1 2>/dev/null || true

- name: Upload artifacts
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -357,7 +361,21 @@ jobs:
run: |
echo "TRTEP_LIBRARY_PATH=$GITHUB_WORKSPACE/orttrtep/lib/libORTTensorRTEp.so" >> $GITHUB_ENV

- name: Run tests
- name: Run unit tests
env:
TRT_EP_LIBRARY_PATH: ${{ env.TRTEP_LIBRARY_PATH }}
TESTDATA_DIR: "${{ github.workspace }}/orttrtep/bin/testdata"
LD_LIBRARY_PATH: "${{ github.workspace }}/orttrtep/bin:${{ github.workspace }}/onnxruntime:${{ github.workspace }}/orttrtep/lib:$LD_LIBRARY_PATH"
run: |
TEST_EXE="$GITHUB_WORKSPACE/orttrtep/bin/trt_ep_tests"
if [ -f "$TEST_EXE" ]; then
chmod +x "$TEST_EXE"
"$TEST_EXE" --gtest_output=xml:trt_ep_unit_test_results.xml
else
echo "WARNING: trt_ep_tests not found, skipping unit tests"
fi

- name: Run onnxruntime_provider_test
env:
ORT_UNIT_TEST_MAIN_LOG_LEVEL: 0
ORT_TRT_EP_ENABLE_BUILDER_PLACEHOLDER: 1
Expand All @@ -375,20 +393,6 @@ jobs:
"$GITHUB_WORKSPACE/onnxruntime/onnxruntime_provider_test" \
"${{ env.ARTIFACT_NAME }}"

- name: Run unit tests
env:
TRT_EP_LIBRARY_PATH: ${{ env.TRTEP_LIBRARY_PATH }}
TESTDATA_DIR: "${{ github.workspace }}/orttrtep/bin/testdata"
LD_LIBRARY_PATH: "${{ github.workspace }}/onnxruntime:${{ github.workspace }}/orttrtep/lib:$LD_LIBRARY_PATH"
run: |
TEST_EXE="$GITHUB_WORKSPACE/orttrtep/bin/trt_ep_tests"
if [ -f "$TEST_EXE" ]; then
chmod +x "$TEST_EXE"
"$TEST_EXE" --gtest_output=xml:trt_ep_unit_test_results.xml
else
echo "WARNING: trt_ep_tests not found, skipping unit tests"
fi

- name: Upload build artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
Expand Down
57 changes: 36 additions & 21 deletions .github/workflows/windows_x64_cuda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ jobs:
xcopy out\build\testdata out\%ARTIFACT_NAME%\bin\testdata\ /E /I /Q 2>nul || (
xcopy out\build\%BUILD_TYPE%\testdata out\%ARTIFACT_NAME%\bin\testdata\ /E /I /Q 2>nul
)
:: Copy onnxruntime.dll from NuGet package so unit tests can find it at runtime
copy out\build\_deps\ortlib-src\runtimes\win-x64\native\onnxruntime.dll out\%ARTIFACT_NAME%\bin\ 2>nul || (
echo WARNING: onnxruntime.dll not found at expected NuGet path
)

- name: Upload artifacts
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -316,7 +320,38 @@ jobs:
python-version: '3.x'
architecture: x64

- name: Run tests
- name: Run unit tests
shell: pwsh
env:
TRT_EP_LIBRARY_PATH: ${{ env.TRTEP_LIBRARY_PATH }}
TESTDATA_DIR: '${{ github.workspace }}\orttrtep\bin\testdata'
run: |
$testExe = "${{ github.workspace }}\orttrtep\bin\trt_ep_tests.exe"
if (Test-Path $testExe) {
$testDir = "${{ github.workspace }}\orttrtep\bin"
# Ensure onnxruntime.dll is alongside test exe (may already be there from build artifact)
if (-not (Test-Path "$testDir\onnxruntime.dll")) {
# Try to find it in ORT artifacts
$ortDll = Get-ChildItem -Path "${{ github.workspace }}\onnxruntime" -Filter "onnxruntime.dll" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
if ($ortDll) {
Copy-Item $ortDll.FullName "$testDir\onnxruntime.dll" -Force
Write-Host "Copied onnxruntime.dll from $($ortDll.FullName)"
} else {
Write-Warning "onnxruntime.dll not found - tests may fail with API version mismatch"
}
} else {
Write-Host "onnxruntime.dll already present in test directory"
}

& $testExe --gtest_output=xml:trt_ep_unit_test_results.xml
if ($lastExitCode -ne 0) {
exit $lastExitCode
}
} else {
Write-Warning "trt_ep_tests.exe not found, skipping unit tests"
}

- name: Run onnxruntime_provider_test
shell: pwsh
env:
ORT_UNIT_TEST_MAIN_LOG_LEVEL: 0
Expand All @@ -336,26 +371,6 @@ jobs:
exit $lastExitCode
}

- name: Run unit tests
shell: pwsh
env:
TRT_EP_LIBRARY_PATH: ${{ env.TRTEP_LIBRARY_PATH }}
TESTDATA_DIR: '${{ github.workspace }}\orttrtep\bin\testdata'
run: |
$testExe = "${{ github.workspace }}\orttrtep\bin\trt_ep_tests.exe"
if (Test-Path $testExe) {
# Copy onnxruntime.dll to same directory as test exe so it's found
Copy-Item "${{ github.workspace }}\onnxruntime\onnxruntime.dll" `
"${{ github.workspace }}\orttrtep\bin\onnxruntime.dll" -ErrorAction SilentlyContinue

& $testExe --gtest_output=xml:trt_ep_unit_test_results.xml
if ($lastExitCode -ne 0) {
exit $lastExitCode
}
} else {
Write-Warning "trt_ep_tests.exe not found, skipping unit tests"
}

- name: Upload build artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v7
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ if(ORTTensorRTEp_BUILD_TESTS)
include(GoogleTest)
gtest_discover_tests(trt_ep_tests
PROPERTIES ENVIRONMENT "TESTDATA_DIR=$<TARGET_FILE_DIR:trt_ep_tests>/testdata"
DISCOVERY_MODE PRE_TEST
)
endif()

Expand Down
49 changes: 48 additions & 1 deletion src/onnx_ctx_model_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,34 @@ bool EPContextNodeReader::GraphHasCtxNode(const OrtGraph* graph, const OrtApi& o

for (size_t i = 0; i < num_nodes; ++i) {
auto node = nodes[i];
if (node == nullptr) continue;

const char* op_type = nullptr;
RETURN_IF_ERROR(ort_api.Node_GetOperatorType(node, &op_type));
if (node != nullptr && std::string(op_type) == "EPContext") {
if (std::string(op_type) == "EPContext") {
// Only match EPContext nodes that belong to this EP.
// If the "source" attribute is present and doesn't match, skip the node.
Ort::ConstNode ort_node(node);
Ort::ConstOpAttr source_attr;
OrtStatus* status = ort_node.GetAttributeByName("source", source_attr);
if (status == nullptr && source_attr != nullptr) {
if (source_attr.GetType() == OrtOpAttrType::ORT_OP_ATTR_STRING) {
std::string source_value;
OrtStatus* val_status = source_attr.GetValue<std::string>(source_value);
if (val_status == nullptr && !source_value.empty() &&
source_value != "TensorrtExecutionProvider") {
// Source doesn't match this EP, skip this node
continue;
}
if (val_status != nullptr) {
ort_api.ReleaseStatus(val_status);
}
}
}
if (status != nullptr) {
// Attribute not found — backward compatibility, treat as ours
ort_api.ReleaseStatus(status);
}
return true;
}
}
Expand Down Expand Up @@ -193,6 +217,29 @@ OrtStatus* EPContextNodeReader::GetEpContextFromGraph(const OrtGraph& graph) {
auto& node = nodes[0];
Ort::ConstOpAttr node_attr;

// Check "source" attribute: reject EPContext nodes from other EPs
// (This is a secondary check; GraphHasCtxNode already filters by source.)
OrtStatus* source_status = node.GetAttributeByName("source", node_attr);
if (source_status == nullptr && node_attr != nullptr) {
if (node_attr.GetType() == OrtOpAttrType::ORT_OP_ATTR_STRING) {
std::string source_value;
OrtStatus* val_status = node_attr.GetValue<std::string>(source_value);
if (val_status == nullptr && !source_value.empty() &&
source_value != "TensorrtExecutionProvider") {
return ort_api.CreateStatus(ORT_EP_FAIL,
("[TensorRT EP] EPContext node has source '" + source_value +
"' which does not match this EP. Skipping.").c_str());
}
if (val_status != nullptr) {
ort_api.ReleaseStatus(val_status);
}
}
}
if (source_status != nullptr) {
// "source" attribute not found — backward compatibility, proceed
ort_api.ReleaseStatus(source_status);
}

// Get "embed_mode" attribute
RETURN_IF_ERROR(node.GetAttributeByName("embed_mode", node_attr));
RETURN_IF_NOT(node_attr.GetType() == OrtOpAttrType::ORT_OP_ATTR_INT, "\'embed_mode\' attribute should be integer type.");
Expand Down
28 changes: 25 additions & 3 deletions src/tensorrt_execution_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ TensorrtLogger& GetTensorrtLogger(bool verbose_log,
const OrtApi* ort_api) {
const auto log_level = verbose_log ? nvinfer1::ILogger::Severity::kVERBOSE : nvinfer1::ILogger::Severity::kWARNING;
static TensorrtLogger trt_logger(ort_default_logger, ort_api, log_level);
// Always update the logger reference to the current session's OrtLogger,
// since the static trt_logger outlives individual EP/session instances.
trt_logger.update_logger(ort_default_logger, ort_api);
if (log_level != trt_logger.get_level()) {
trt_logger.set_level(verbose_log ? nvinfer1::ILogger::Severity::kVERBOSE : nvinfer1::ILogger::Severity::kWARNING);
}
Expand Down Expand Up @@ -1345,7 +1348,16 @@ OrtStatus* TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(OrtEp* this
auto trt_parser =
tensorrt_ptr::unique_pointer<nvonnxparser::IParser>(nvonnxparser::createParser(*trt_network, trt_logger));
trt_parser->setFlags(ComputeParserFlags());
trt_parser->parse(string_buf.data(), string_buf.size(), model_path_);
if (!trt_parser->parse(string_buf.data(), string_buf.size(), model_path_)) {
int num_errors = trt_parser->getNbErrors();
const char* node_name = nullptr;
RETURN_IF_ERROR(ort_api.Node_GetName(fused_node, &node_name));
std::string error_msg = "[TensorRT EP] Failed to parse the ONNX model for fused node: " + std::string(node_name ? node_name : "unknown");
if (num_errors > 0) {
error_msg += ". Parser error: " + std::string(trt_parser->getError(0)->desc());
}
return ort_api.CreateStatus(ORT_EP_FAIL, error_msg.c_str());
}
if (max_workspace_size_ > 0) {
trt_config->setMemoryPoolLimit(nvinfer1::MemoryPoolType::kWORKSPACE, max_workspace_size_);
}
Expand Down Expand Up @@ -2080,14 +2092,24 @@ OrtStatus* TensorrtExecutionProvider::CreateNodeComputeInfoFromGraph(OrtEp* this
// Create output to index and type maps
// TRT network output -> ORT fused_node output index
const auto& graph_output = model_proto.graph().output();

// Build a name-to-index map for graph proto outputs to safely look up by name
std::unordered_map<std::string, int> graph_output_name_to_idx;
for (int i = 0; i < graph_output.size(); ++i) {
graph_output_name_to_idx[graph_output[i].name()] = i;
}

for (int i = 0; i < num_outputs; ++i) {
const std::string& output_name = trt_network->getOutput(i)->getName();
const auto& iter = output_map.find(output_name);
if (iter != output_map.end()) {
output_indexes[output_name] = iter->second;
}
const auto& tensor_type = graph_output[i].type().tensor_type();
output_types[output_name] = tensor_type.elem_type();
const auto& graph_out_iter = graph_output_name_to_idx.find(output_name);
if (graph_out_iter != graph_output_name_to_idx.end()) {
const auto& tensor_type = graph_output[graph_out_iter->second].type().tensor_type();
output_types[output_name] = tensor_type.elem_type();
}
}

// Save TRT engine, other TRT objects and input/output info to map
Expand Down
20 changes: 15 additions & 5 deletions src/tensorrt_execution_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,22 @@ namespace trt_ep {

class TensorrtLogger : public nvinfer1::ILogger {
nvinfer1::ILogger::Severity verbosity_;
const OrtLogger& ort_default_logger_;
const OrtLogger* ort_default_logger_ = nullptr;
const OrtApi* ort_api_ = nullptr;

public:
TensorrtLogger(const OrtLogger& ort_default_logger,
const OrtApi* ort_api,
Severity verbosity = Severity::kWARNING)
: ort_default_logger_{ort_default_logger}, ort_api_{ort_api}, verbosity_(verbosity) {}
: ort_default_logger_{&ort_default_logger}, ort_api_{ort_api}, verbosity_(verbosity) {}

// Update the ORT logger reference (needed because the static TensorrtLogger
// outlives individual EP/session instances whose OrtLogger may be destroyed).
void update_logger(const OrtLogger& ort_default_logger, const OrtApi* ort_api) {
ort_default_logger_ = &ort_default_logger;
ort_api_ = ort_api;
}

void log(Severity severity, const char* msg) noexcept override {
if (severity <= verbosity_) {
time_t rawtime = std::time(0);
Expand All @@ -60,9 +68,11 @@ class TensorrtLogger : public nvinfer1::ILogger {

std::string message = "[" + std::string(buf) + " " + std::string(sevstr) + "] " + std::string(msg);

Ort::ThrowOnError(ort_api_->Logger_LogMessage(&ort_default_logger_,
ort_severity,
message.c_str(), ORT_FILE, __LINE__, __FUNCTION__));
if (ort_default_logger_ && ort_api_) {
Ort::ThrowOnError(ort_api_->Logger_LogMessage(ort_default_logger_,
ort_severity,
message.c_str(), ORT_FILE, __LINE__, __FUNCTION__));
}
}
}
void set_level(Severity verbosity) {
Expand Down
Loading
Loading