chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Waiting to run
Docker Image CI / build-ubuntu2004 (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2025-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.
|
||||
#
|
||||
|
||||
add_executable(sample_cudla sampleCudla.cpp)
|
||||
target_link_libraries(sample_cudla PRIVATE trt_samples_common TRT_SAMPLES::tensorrt CUDA::cudla)
|
||||
target_compile_definitions(sample_cudla PRIVATE ENABLE_DLA=1)
|
||||
add_dependencies(tensorrt_samples sample_cudla)
|
||||
|
||||
installLibraries(
|
||||
TARGETS sample_cudla
|
||||
OPTIONAL
|
||||
COMPONENT internal
|
||||
)
|
||||
@@ -0,0 +1,107 @@
|
||||
# Using The CuDLA API To Run A TensorRT Engine
|
||||
|
||||
|
||||
**Table Of Contents**
|
||||
- [Description](#description)
|
||||
- [How does this sample work?](#how-does-this-sample-work)
|
||||
* [TensorRT API layers and ops](#tensorrt-api-layers-and-ops)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Running the sample](#running-the-sample)
|
||||
* [Sample `--help` options](#sample-help-options)
|
||||
- [Additional resources](#additional-resources)
|
||||
- [License](#license)
|
||||
- [Changelog](#changelog)
|
||||
- [Known issues](#known-issues)
|
||||
|
||||
## Description
|
||||
|
||||
This sample, sampleCudla, uses an API to construct a network of a single ElementWise layer and builds the engine. The engine runs in DLA standalone mode using cuDLA runtime. In order to do that, the sample uses cuDLA APIs to do engine conversion and cuDLA runtime preparation, as well as inference.
|
||||
|
||||
## How does this sample work?
|
||||
|
||||
After the construction of a network, the module with cuDLA is loaded from the network data. The input and output tensors are then allocated and registered with cuDLA. When the input tensors are copied from CPU to GPU, the cuDLA task can be submitted and executed. Then we wait for stream operations to finish and bring output buffer to CPU to be verified for correctness.
|
||||
|
||||
Specifically:
|
||||
- The single-layered network is built by TensorRT.
|
||||
- `cudlaCreateDevice` is called to create DLA device.
|
||||
- `cudlaModuleLoadFromMemory` is called to load the engine memory for DLA use.
|
||||
- `cudaMalloc` and `cudlaMemRegister` are called to first allocate memory on GPU, then let the CUDA pointer be registered with the DLA.
|
||||
- `cudlaModuleGetAttributes` is called to get module attributes from the loaded module.
|
||||
- `cudlaSubmitTask` is called to submit the inference task.
|
||||
|
||||
|
||||
### TensorRT API layers and ops
|
||||
|
||||
In this sample, the [ElementWise](https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#elementwise-layer) layer is used. For more information, see the [TensorRT Developer Guide: Layers](https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#layers) documentation.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Platform**: This sample can only be built and run on aarch64 platforms with DLA hardware (Jetson or DRIVE). It is not supported on x86.
|
||||
- **cuDLA library**: The `cudla` library must be available in your CUDA toolkit installation.
|
||||
- **CMake flag**: The sample requires `-DTRT_BUILD_ENABLE_DLA=ON` to be included in the build.
|
||||
|
||||
If built without the DLA flag enabled, this sample will print the following error message:
|
||||
```
|
||||
DLA is not enabled, please compile with ENABLE_DLA=1
|
||||
```
|
||||
and quit.
|
||||
|
||||
## Running the sample
|
||||
|
||||
1. Compile this sample using CMake with the DLA flag enabled:
|
||||
```
|
||||
cd <TensorRT root directory>
|
||||
mkdir -p build && cd build
|
||||
cmake .. -DTRT_BUILD_ENABLE_DLA=ON
|
||||
make sample_cudla
|
||||
```
|
||||
|
||||
Where `<TensorRT root directory>` is where you installed TensorRT.
|
||||
|
||||
2. Run the sample to perform inference on DLA.
|
||||
`./sample_cudla`
|
||||
|
||||
3. Verify that the sample ran successfully. If the sample runs successfully you should see an output similar to the following:
|
||||
```
|
||||
&&&& RUNNING TensorRT.sample_cudla # ./sample_cudla
|
||||
[I] [TRT]
|
||||
[I] [TRT] --------------- Layers running on DLA:
|
||||
[I] [TRT] [DlaLayer] {ForeignNode[(Unnamed Layer* 0) [ElementWise]]},
|
||||
[I] [TRT] --------------- Layers running on GPU:
|
||||
[I] [TRT]
|
||||
…(omit messages)
|
||||
&&&& PASSED TensorRT.sample_cudla
|
||||
```
|
||||
|
||||
This output shows that the sample ran successfully; `PASSED`.
|
||||
|
||||
|
||||
### Sample `--help` options
|
||||
|
||||
To see the full list of available options and their descriptions, use the `./sample_cudla -h` command line option.
|
||||
|
||||
|
||||
## Additional resources
|
||||
|
||||
The following resources provide a deeper understanding of sampleCudla.
|
||||
|
||||
**Documentation**
|
||||
- [Introduction To NVIDIA’s TensorRT Samples](https://docs.nvidia.com/deeplearning/sdk/tensorrt-sample-support-guide/index.html#samples)
|
||||
- [Working With TensorRT Using The C++ API](https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#c_topics)
|
||||
- [NVIDIA’s TensorRT Documentation Library](https://docs.nvidia.com/deeplearning/sdk/tensorrt-archived/index.html)
|
||||
- [Developer Guide for cuDLA APIs](https://docs.nvidia.com/cuda/cuda-for-tegra-appnote/index.html#cudla-intro)
|
||||
|
||||
## License
|
||||
|
||||
For terms and conditions for use, reproduction, and distribution, see the [TensorRT Software License Agreement](https://docs.nvidia.com/deeplearning/sdk/tensorrt-sla/index.html) documentation.
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
June 2022
|
||||
This is the first release of the `README.md` file.
|
||||
|
||||
|
||||
## Known issues
|
||||
|
||||
There are no known issues with this tool.
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 1993-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.
|
||||
*/
|
||||
|
||||
//! \file SampleCuDLA.cpp
|
||||
//! \brief This file contains the implementation of the cuDLA sample.
|
||||
//!
|
||||
|
||||
// Define TRT entrypoints used in common code
|
||||
#define DEFINE_TRT_ENTRYPOINTS 1
|
||||
#define DEFINE_TRT_ONNX_PARSER_ENTRYPOINT 0
|
||||
|
||||
#include "NvInfer.h"
|
||||
#include "argsParser.h"
|
||||
#include "buffers.h"
|
||||
#include "common.h"
|
||||
#include "half.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "cudla.h"
|
||||
|
||||
#include <cuda_runtime_api.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace samplesCommon;
|
||||
|
||||
#define CHECK_CUDLA(expr) \
|
||||
do { \
|
||||
auto const status = (expr); \
|
||||
if (status != cudlaSuccess) \
|
||||
{ \
|
||||
sample::gLogError << "Error in " << expr << " = " << status << std::endl; \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
std::string const gSampleName = "TensorRT.sample_cudla";
|
||||
|
||||
bool isDLAHeader(void const* ptr)
|
||||
{
|
||||
CHECK_RETURN(ptr, false);
|
||||
char const* p = static_cast<char const*>(ptr);
|
||||
return p[4] == 'N' && p[5] == 'V' && p[6] == 'D' && p[7] == 'A';
|
||||
}
|
||||
|
||||
#if ENABLE_DLA
|
||||
|
||||
class DlaContext
|
||||
{
|
||||
public:
|
||||
DlaContext(void* data, size_t const size)
|
||||
{
|
||||
// Initialize CUDA.
|
||||
CHECK(cudaFree(0));
|
||||
CHECK(cudaSetDevice(0));
|
||||
CHECK_CUDLA(cudlaCreateDevice(0, &mDevHandle, CUDLA_CUDA_DLA));
|
||||
|
||||
// Get available devices.
|
||||
uint64_t numEngines{0};
|
||||
CHECK_CUDLA(cudlaDeviceGetCount(&numEngines));
|
||||
ASSERT(numEngines >= 1);
|
||||
|
||||
// Create CUDA stream.
|
||||
CHECK(cudaStreamCreateWithFlags(&mStream, cudaStreamNonBlocking));
|
||||
|
||||
// Load the module with cuDLA from the loadable data.
|
||||
deserialize(data, size);
|
||||
|
||||
// Create and allocate I/O tensors with the GPU momory registered with cuDLA.
|
||||
createIoTensors();
|
||||
}
|
||||
|
||||
~DlaContext()
|
||||
{
|
||||
// Unregister the memory with cuDLA and clear vectors.
|
||||
for (auto& elem : mTensorIn)
|
||||
{
|
||||
CHECK_CUDLA(cudlaMemUnregister(mDevHandle, elem));
|
||||
}
|
||||
mTensorIn.clear();
|
||||
|
||||
for (auto& elem : mTensorOut)
|
||||
{
|
||||
CHECK_CUDLA(cudlaMemUnregister(mDevHandle, elem));
|
||||
}
|
||||
mTensorOut.clear();
|
||||
|
||||
// Free the buffers on GPU and clear vectors.
|
||||
for (auto& elem : mBufferGPUIn)
|
||||
{
|
||||
CHECK(cudaFree(elem));
|
||||
}
|
||||
mBufferGPUIn.clear();
|
||||
|
||||
for (auto& elem : mBufferGPUOut)
|
||||
{
|
||||
CHECK(cudaFree(elem));
|
||||
}
|
||||
mBufferGPUOut.clear();
|
||||
|
||||
mInputTensorDesc.clear();
|
||||
mOutputTensorDesc.clear();
|
||||
CHECK(cudaStreamDestroy(mStream));
|
||||
|
||||
// Unload the module with cuDLA and destroy the device.
|
||||
CHECK_CUDLA(cudlaModuleUnload(mModuleHandle, 0));
|
||||
sample::gLogInfo << "Successfully unloaded module" << std::endl;
|
||||
CHECK_CUDLA(cudlaDestroyDevice(mDevHandle));
|
||||
sample::gLogInfo << "Device destroyed successfully" << std::endl;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Enqueue and execute the current task.
|
||||
//!
|
||||
using BufRef = std::reference_wrapper<std::vector<half_float::half>>;
|
||||
using BufRefConst = std::reference_wrapper<std::vector<half_float::half> const>;
|
||||
void submit(std::vector<BufRefConst> const& inputBufVec, std::vector<BufRef> const& outputBufVec)
|
||||
{
|
||||
// Copy data from CPU buffers to GPU buffers.
|
||||
uint32_t const inputBufVecSize = inputBufVec.size();
|
||||
for (uint32_t i = 0; i < inputBufVecSize; ++i)
|
||||
{
|
||||
auto const& inputBuf = inputBufVec.at(i).get();
|
||||
void* inputBufferGPU = mBufferGPUIn.at(i);
|
||||
CHECK(cudaMemcpyAsync(inputBufferGPU, inputBuf.data(), mInputTensorDesc.at(i).size,
|
||||
cudaMemcpyHostToDevice, mStream));
|
||||
}
|
||||
// Consist of the input and output tensors in the form of the addresses registered with the DLA.
|
||||
// Ensure the registered pointers are visible to the DLA before the execution.
|
||||
mTask.moduleHandle = mModuleHandle;
|
||||
mTask.outputTensor = mTensorOut.data();
|
||||
mTask.numOutputTensors = getNbOutputTensors();
|
||||
mTask.numInputTensors = getNbInputTensors();
|
||||
mTask.inputTensor = mTensorIn.data();
|
||||
mTask.waitEvents = NULL;
|
||||
mTask.signalEvents = NULL;
|
||||
CHECK_CUDLA(cudlaSubmitTask(mDevHandle, &mTask, 1, mStream, 0));
|
||||
sample::gLogInfo << "Submitted task to DLA successfully" << std::endl;
|
||||
// Bring output buffer to CPU.
|
||||
uint32_t const outputBufVecSize = outputBufVec.size();
|
||||
for (uint32_t i = 0; i < outputBufVecSize; ++i)
|
||||
{
|
||||
auto& outputBuf = outputBufVec.at(i).get();
|
||||
void* outputBufferGPU = mBufferGPUOut.at(i);
|
||||
CHECK(cudaMemcpyAsync(outputBuf.data(), outputBufferGPU, mOutputTensorDesc.at(i).size,
|
||||
cudaMemcpyDeviceToHost, mStream));
|
||||
}
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Wait for stream operations to finish.
|
||||
//!
|
||||
void synchronize()
|
||||
{
|
||||
CHECK(cudaStreamSynchronize(mStream));
|
||||
}
|
||||
|
||||
private:
|
||||
cudlaDevHandle mDevHandle; //!< Device handler
|
||||
cudlaModule mModuleHandle; //!< Module handler
|
||||
cudlaTask mTask; //!< CuDLA task
|
||||
cudaStream_t mStream; //!< CUDA stream
|
||||
std::vector<cudlaModuleTensorDescriptor> mInputTensorDesc; //!< Input tensor descriptors
|
||||
std::vector<cudlaModuleTensorDescriptor> mOutputTensorDesc; //!< Output tensor descriptors
|
||||
std::vector<uint64_t*> mTensorIn; //!< Input registered pointers
|
||||
std::vector<uint64_t*> mTensorOut; //!< Output registered pointers
|
||||
std::vector<void*> mBufferGPUIn; //!< Input allocated buffers
|
||||
std::vector<void*> mBufferGPUOut; //!< Output allocated buffers
|
||||
|
||||
//!
|
||||
//! \brief Load the module with cuDLA from the loadable data.
|
||||
//!
|
||||
void deserialize(void* data, size_t const size)
|
||||
{
|
||||
ASSERT(isDLAHeader(static_cast<char*>(data)));
|
||||
CHECK_CUDLA(cudlaModuleLoadFromMemory(mDevHandle, static_cast<unsigned char*>(data), size, &mModuleHandle, 0));
|
||||
sample::gLogInfo << "Successfully loaded module" << std::endl;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Get the number of input tensors.
|
||||
//!
|
||||
uint32_t getNbInputTensors() const
|
||||
{
|
||||
cudlaModuleAttribute attribute;
|
||||
CHECK_CUDLA(cudlaModuleGetAttributes(mModuleHandle, CUDLA_NUM_INPUT_TENSORS, &attribute));
|
||||
return attribute.numInputTensors;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Get the number of output tensors.
|
||||
//!
|
||||
uint32_t getNbOutputTensors() const
|
||||
{
|
||||
cudlaModuleAttribute attribute;
|
||||
CHECK_CUDLA(cudlaModuleGetAttributes(mModuleHandle, CUDLA_NUM_OUTPUT_TENSORS, &attribute));
|
||||
return attribute.numOutputTensors;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Allocate memory for a buffer on GPU and register the required pointer with cuDLA.
|
||||
//!
|
||||
void createMemDLA(std::vector<uint64_t*>& mTensor, std::vector<void*>& mBufferGPU, uint64_t const size, int32_t const idx)
|
||||
{
|
||||
void* bufferGPU = nullptr;
|
||||
uint64_t* bufferRegisteredPtr = nullptr;
|
||||
// Allocate memory on GPU.
|
||||
CHECK(cudaMalloc(&bufferGPU, size));
|
||||
// Register the CUDA-allocated buffers.
|
||||
CHECK_CUDLA(cudlaMemRegister(mDevHandle, static_cast<uint64_t*>(bufferGPU), size, &bufferRegisteredPtr, 0));
|
||||
CHECK(cudaMemsetAsync(bufferGPU, 0, size, mStream));
|
||||
mTensor.emplace_back(bufferRegisteredPtr);
|
||||
mBufferGPU.emplace_back(bufferGPU);
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Create and allocate I/O tensors with the GPU momory registered with cuDLA.
|
||||
//!
|
||||
void createIoTensors()
|
||||
{
|
||||
// Prepare I/O tensors
|
||||
uint32_t const numInputTensors = getNbInputTensors();
|
||||
uint32_t const numOutputTensors = getNbOutputTensors();
|
||||
|
||||
// Allocate memory for input and output tensor descriptors.
|
||||
mInputTensorDesc.resize(numInputTensors);
|
||||
mOutputTensorDesc.resize(numOutputTensors);
|
||||
|
||||
// Get module attributes from the loaded module.
|
||||
// Fill in the input and output tensor descriptors.
|
||||
cudlaModuleAttribute attribute;
|
||||
attribute.inputTensorDesc = mInputTensorDesc.data();
|
||||
CHECK_CUDLA(cudlaModuleGetAttributes(mModuleHandle, CUDLA_INPUT_TENSOR_DESCRIPTORS, &attribute));
|
||||
|
||||
attribute.outputTensorDesc = mOutputTensorDesc.data();
|
||||
CHECK_CUDLA(cudlaModuleGetAttributes(mModuleHandle, CUDLA_OUTPUT_TENSOR_DESCRIPTORS, &attribute));
|
||||
|
||||
// Get each tensor size, allocate GPU memory and register that memory with cuDLA.
|
||||
for (uint32_t i = 0; i < numInputTensors; ++i)
|
||||
{
|
||||
uint64_t const inputDescSize = mInputTensorDesc.at(i).size;
|
||||
createMemDLA(mTensorIn, mBufferGPUIn, inputDescSize, i);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < numOutputTensors; ++i)
|
||||
{
|
||||
uint64_t const outputDescSize = mOutputTensorDesc.at(i).size;
|
||||
createMemDLA(mTensorOut, mBufferGPUOut, outputDescSize, i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//!
|
||||
//! \brief Create the single layer Network and marks the output layers.
|
||||
//!
|
||||
void constructNetwork(nvinfer1::INetworkDefinition& network)
|
||||
{
|
||||
nvinfer1::Dims const inputDims{4, {1, 32, 32, 32}};
|
||||
|
||||
auto inA = network.addInput("inputA", nvinfer1::DataType::kHALF, inputDims);
|
||||
auto inB = network.addInput("inputB", nvinfer1::DataType::kHALF, inputDims);
|
||||
|
||||
auto layer = network.addElementWise(*inA, *inB, nvinfer1::ElementWiseOperation::kSUM);
|
||||
nvinfer1::ITensor* out = layer->getOutput(0);
|
||||
|
||||
out->setName("output");
|
||||
network.markOutput(*out);
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Explicitly set network I/O formats.
|
||||
//!
|
||||
void setNetworkIOFormats(nvinfer1::INetworkDefinition& network)
|
||||
{
|
||||
nvinfer1::TensorFormat const formats = nvinfer1::TensorFormat::kCHW16;
|
||||
uint32_t const numInputs = network.getNbInputs();
|
||||
for (uint32_t i = 0; i < numInputs; i++)
|
||||
{
|
||||
auto input = network.getInput(i);
|
||||
input->setAllowedFormats(static_cast<nvinfer1::TensorFormats>(1U << static_cast<int32_t>(formats)));
|
||||
}
|
||||
|
||||
uint32_t const numOutputs = network.getNbOutputs();
|
||||
for (uint32_t i = 0; i < numOutputs; i++)
|
||||
{
|
||||
auto output = network.getOutput(i);
|
||||
output->setAllowedFormats(static_cast<nvinfer1::TensorFormats>(1U << static_cast<int32_t>(formats)));
|
||||
}
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Randomly initializes buffer.
|
||||
//!
|
||||
template <typename T>
|
||||
void randomInit(std::vector<T>& buffer)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
std::uniform_int_distribution<int32_t> dist(0, 63);
|
||||
|
||||
auto gen = [&dist, &mt]() { return T(dist(mt)); };
|
||||
std::generate(buffer.begin(), buffer.end(), gen);
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Verifies that the output is correct.
|
||||
//!
|
||||
template <typename T>
|
||||
bool verifyOutput(std::vector<T> const& ref, std::vector<T> const& output)
|
||||
{
|
||||
return std::equal(ref.begin(), ref.end(), output.begin());
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief Creates the network, configures the builder, and creates the network engine.
|
||||
//!
|
||||
//! \details This function creates a network and builds an engine to run in DLA safe mode.
|
||||
//! The network consists of only one elementwise sum layer with FP16 precision.
|
||||
//!
|
||||
//! \return true if the engine was created successfully and false otherwise.
|
||||
//!
|
||||
bool build(std::unique_ptr<nvinfer1::IHostMemory>& mLoadable, nvinfer1::Dims& mInputDims, nvinfer1::Dims& mOutputDims,
|
||||
std::string const& timingCacheFile)
|
||||
{
|
||||
auto builder = std::unique_ptr<nvinfer1::IBuilder>(nvinfer1::createInferBuilder(sample::gLogger.getTRTLogger()));
|
||||
CHECK_RETURN(builder.get(), false);
|
||||
|
||||
auto network = std::unique_ptr<nvinfer1::INetworkDefinition>(builder->createNetworkV2(0));
|
||||
CHECK_RETURN(network.get(), false);
|
||||
|
||||
auto config = std::unique_ptr<nvinfer1::IBuilderConfig>(builder->createBuilderConfig());
|
||||
CHECK_RETURN(config.get(), false);
|
||||
|
||||
constructNetwork(*network);
|
||||
setNetworkIOFormats(*network);
|
||||
|
||||
samplesCommon::enableDLA(builder.get(), config.get(), 0);
|
||||
|
||||
config->clearFlag(nvinfer1::BuilderFlag::kGPU_FALLBACK);
|
||||
config->setEngineCapability(nvinfer1::EngineCapability::kDLA_STANDALONE);
|
||||
|
||||
std::unique_ptr<nvinfer1::ITimingCache> timingCache{};
|
||||
|
||||
// Load timing cache
|
||||
if (!timingCacheFile.empty())
|
||||
{
|
||||
timingCache = samplesCommon::buildTimingCacheFromFile(sample::gLogger.getTRTLogger(), *config, timingCacheFile);
|
||||
}
|
||||
|
||||
mLoadable = std::unique_ptr<nvinfer1::IHostMemory>(builder->buildSerializedNetwork(*network, *config));
|
||||
if (!mLoadable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timingCache != nullptr && !timingCacheFile.empty())
|
||||
{
|
||||
samplesCommon::updateTimingCacheFile(
|
||||
sample::gLogger.getTRTLogger(), timingCacheFile, timingCache.get(), *builder);
|
||||
}
|
||||
|
||||
mInputDims = network->getInput(0)->getDimensions();
|
||||
mOutputDims = network->getOutput(0)->getDimensions();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_DLA
|
||||
|
||||
//!
|
||||
//! \brief Prints the help information for running this sample.
|
||||
//!
|
||||
void printHelpInfo()
|
||||
{
|
||||
sample::gLogInfo << "Usage: ./sample_cudla [-h or --help] [--timingCacheFile=<path to timing cache file>]\n";
|
||||
sample::gLogInfo << "--help Display help information\n";
|
||||
sample::gLogInfo
|
||||
<< "--timingCacheFile Specify path to a timing cache file. If it does not already exist, it will be "
|
||||
<< "created." << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
samplesCommon::Args args;
|
||||
bool argsOK = samplesCommon::parseArgs(args, argc, argv);
|
||||
if (!argsOK)
|
||||
{
|
||||
sample::gLogError << "Invalid arguments " << std::endl;
|
||||
printHelpInfo();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (args.help)
|
||||
{
|
||||
printHelpInfo();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
auto sampleTest = sample::gLogger.defineTest(gSampleName, argc, argv);
|
||||
|
||||
sample::gLogger.reportTestStart(sampleTest);
|
||||
|
||||
#if ENABLE_DLA
|
||||
std::unique_ptr<nvinfer1::IHostMemory> mLoadable{nullptr}; //!< The DLA loadable.
|
||||
nvinfer1::Dims mInputDims; //!< The dimensions of the input to the network.
|
||||
nvinfer1::Dims mOutputDims; //!< The dimensions of the output to the network.
|
||||
CHECK_RETURN(
|
||||
build(mLoadable, mInputDims, mOutputDims, args.timingCacheFile), sample::gLogger.reportFail(sampleTest));
|
||||
|
||||
int64_t const inputBufSize = samplesCommon::volume(mInputDims, 0, mInputDims.nbDims);
|
||||
int64_t const expectedOutputSize = samplesCommon::volume(mOutputDims, 0, mOutputDims.nbDims);
|
||||
|
||||
// Allocate and initialize input and output buffers
|
||||
// The allocation and initialization only needs to be done once
|
||||
std::vector<half_float::half> inputBufA(inputBufSize);
|
||||
std::vector<half_float::half> inputBufB(inputBufSize);
|
||||
std::vector<half_float::half> referenceBuf(expectedOutputSize);
|
||||
std::vector<half_float::half> outputBuf(expectedOutputSize);
|
||||
|
||||
randomInit(inputBufA);
|
||||
randomInit(inputBufB);
|
||||
|
||||
// Create a DlaContext
|
||||
DlaContext context(mLoadable->data(), mLoadable->size());
|
||||
|
||||
// The cuDLA task can be submitted more than once
|
||||
context.submit({inputBufA, inputBufB}, {outputBuf});
|
||||
|
||||
context.synchronize();
|
||||
|
||||
// Compute the reference output for comparision
|
||||
std::transform(
|
||||
inputBufA.begin(), inputBufA.end(), inputBufB.begin(), referenceBuf.begin(), std::plus<half_float::half>());
|
||||
CHECK_RETURN(verifyOutput(referenceBuf, outputBuf), sample::gLogger.reportFail(sampleTest));
|
||||
#else // ENABLE_DLA
|
||||
sample::gLogError << "DLA is not enabled, please compile with ENABLE_DLA=1" << std::endl;
|
||||
#endif // ENABLE_DLA
|
||||
|
||||
return sample::gLogger.reportPass(sampleTest);
|
||||
}
|
||||
Reference in New Issue
Block a user