chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Has been cancelled
Docker Image CI / build-ubuntu2004 (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TENSORRT_SAFE_COMMON_H
|
||||
#define TENSORRT_SAFE_COMMON_H
|
||||
|
||||
#include "NvInferRuntimeBase.h"
|
||||
#include "NvInferSafeRecorder.h"
|
||||
#include "NvInferSafeRuntime.h"
|
||||
#include "cuda_runtime.h"
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// For safeLoadLibrary
|
||||
#ifdef _MSC_VER
|
||||
// Needed so that the max/min definitions in windows.h do not conflict with std::max/min.
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#if IS_QNX_SAFE
|
||||
#include <cuda_runtime_api_safe_ex.h>
|
||||
#include <sys/procmgr.h>
|
||||
#endif // IS_QNX_SAFE
|
||||
|
||||
using namespace nvinfer1;
|
||||
|
||||
#undef CHECK_WITH_STREAM
|
||||
#define CHECK_WITH_STREAM(status, stream) \
|
||||
do \
|
||||
{ \
|
||||
if ((status) != cudaSuccess) \
|
||||
{ \
|
||||
stream << "Cuda failure at " << __FILE__ << ":" << __LINE__ << ": " << cudaGetErrorString(status) \
|
||||
<< std::endl; \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#undef CUDA_CHECK
|
||||
#define CUDA_CHECK(status) CHECK_WITH_STREAM(status, std::cerr)
|
||||
|
||||
#define SAFE_LOG std::cerr
|
||||
|
||||
inline std::string getTimestampStr()
|
||||
{
|
||||
std::time_t timestamp = std::time(nullptr);
|
||||
tm* tm_local = std::localtime(×tamp);
|
||||
std::stringstream ss;
|
||||
ss << "[";
|
||||
ss << std::setw(2) << std::setfill('0') << 1 + tm_local->tm_mon << "/";
|
||||
ss << std::setw(2) << std::setfill('0') << tm_local->tm_mday << "/";
|
||||
ss << std::setw(4) << std::setfill('0') << 1900 + tm_local->tm_year << "-";
|
||||
ss << std::setw(2) << std::setfill('0') << tm_local->tm_hour << ":";
|
||||
ss << std::setw(2) << std::setfill('0') << tm_local->tm_min << ":";
|
||||
ss << std::setw(2) << std::setfill('0') << tm_local->tm_sec << "] ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline void safeLogDebug(nvinfer2::safe::ISafeRecorder& recorder, std::string desc)
|
||||
{
|
||||
desc = getTimestampStr() + "[D] " + desc;
|
||||
recorder.reportDebug(desc.c_str());
|
||||
}
|
||||
|
||||
inline void safeLogVerbose(nvinfer2::safe::ISafeRecorder& recorder, std::string desc)
|
||||
{
|
||||
desc = getTimestampStr() + "[V] " + desc;
|
||||
recorder.reportVerbose(desc.c_str());
|
||||
}
|
||||
|
||||
inline void safeLogInfo(nvinfer2::safe::ISafeRecorder& recorder, std::string desc)
|
||||
{
|
||||
desc = getTimestampStr() + "[I] " + desc;
|
||||
recorder.reportInfo(desc.c_str());
|
||||
}
|
||||
|
||||
inline void safeLogWarning(nvinfer2::safe::ISafeRecorder& recorder, std::string desc)
|
||||
{
|
||||
desc = getTimestampStr() + "[W] " + desc;
|
||||
recorder.reportWarn(desc.c_str());
|
||||
}
|
||||
|
||||
inline void safeLogError(
|
||||
nvinfer2::safe::ISafeRecorder& recorder, std::string desc, ErrorCode val = ErrorCode::kFAILED_EXECUTION)
|
||||
{
|
||||
desc = getTimestampStr() + "[E] " + desc;
|
||||
recorder.reportError(val, desc.c_str());
|
||||
}
|
||||
|
||||
#undef SAFE_ASSERT
|
||||
#define SAFE_ASSERT(condition) \
|
||||
do \
|
||||
{ \
|
||||
if (!(condition)) \
|
||||
{ \
|
||||
std::cerr << "Assertion failure: " << #condition << std::endl; \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SAFE_API_CALL(api_call, recorder) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
const ErrorCode ret = (api_call); \
|
||||
if (ret != ErrorCode::kSUCCESS) \
|
||||
{ \
|
||||
ss << "SAFE API Error: [" << #api_call << "]: " << toString(ret); \
|
||||
safeLogError(recorder, ss.str(), ret); \
|
||||
throw ErrorCode{ret}; \
|
||||
} \
|
||||
ss << "SAFE API:[" << #api_call << "]: PASSED"; \
|
||||
safeLogVerbose(recorder, ss.str()); \
|
||||
} while (0)
|
||||
|
||||
#define CUDA_CALL(cuda_api_call, recorder) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
cudaError_t error = (cuda_api_call); \
|
||||
if (error != cudaSuccess) \
|
||||
{ \
|
||||
ss << "CUDA Error: [" << #cuda_api_call << "]: " << cudaGetErrorString(error); \
|
||||
auto ret = ErrorCode::kFAILED_EXECUTION; \
|
||||
safeLogError(recorder, ss.str(), ret); \
|
||||
throw ErrorCode{ret}; \
|
||||
} \
|
||||
ss << "CUDA:[" << #cuda_api_call << "]: PASSED"; \
|
||||
safeLogVerbose(recorder, ss.str()); \
|
||||
} while (0)
|
||||
|
||||
inline std::string toString(ErrorCode ec)
|
||||
{
|
||||
static const auto ecStrings = [] {
|
||||
std::unordered_map<ErrorCode, std::string> result;
|
||||
#define INSERT_ELEMENT(p, s) result.emplace(p, s);
|
||||
INSERT_ELEMENT(ErrorCode::kSUCCESS, "SUCCESS")
|
||||
INSERT_ELEMENT(ErrorCode::kUNSPECIFIED_ERROR, "UNSPECIFIED_ERROR")
|
||||
INSERT_ELEMENT(ErrorCode::kINTERNAL_ERROR, "INTERNAL_ERROR")
|
||||
INSERT_ELEMENT(ErrorCode::kINVALID_ARGUMENT, "INVALID_ARGUMENT")
|
||||
INSERT_ELEMENT(ErrorCode::kINVALID_CONFIG, "INVALID_CONFIG")
|
||||
INSERT_ELEMENT(ErrorCode::kFAILED_ALLOCATION, "FAILED_ALLOCATION")
|
||||
INSERT_ELEMENT(ErrorCode::kFAILED_INITIALIZATION, "FAILED_INITIALIZATION")
|
||||
INSERT_ELEMENT(ErrorCode::kFAILED_EXECUTION, "FAILED_EXECUTION")
|
||||
INSERT_ELEMENT(ErrorCode::kFAILED_COMPUTATION, "FAILED_COMPUTATION")
|
||||
INSERT_ELEMENT(ErrorCode::kINVALID_STATE, "INVALID_STATE")
|
||||
INSERT_ELEMENT(ErrorCode::kUNSUPPORTED_STATE, "UNSUPPORTED_STATE")
|
||||
#undef INSERT_ELEMENT
|
||||
return result;
|
||||
}();
|
||||
return ecStrings.at(ec);
|
||||
}
|
||||
|
||||
//! Locate path to file, given its filename or filepath suffix and possible dirs it might lie in.
|
||||
//! Function will also walk back MAX_DEPTH dirs from CWD to check for such a file path.
|
||||
inline std::string locateFile(
|
||||
const std::string& filepathSuffix, const std::vector<std::string>& directories, bool reportError = true)
|
||||
{
|
||||
const int MAX_DEPTH{10};
|
||||
bool found{false};
|
||||
std::string filepath;
|
||||
|
||||
for (auto& dir : directories)
|
||||
{
|
||||
if (!dir.empty() && dir.back() != '/')
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
filepath = dir + "\\" + filepathSuffix;
|
||||
#else
|
||||
filepath = dir + "/" + filepathSuffix;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
filepath = dir + filepathSuffix;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_DEPTH && !found; i++)
|
||||
{
|
||||
const std::ifstream checkFile(filepath);
|
||||
found = checkFile.is_open();
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
filepath = "../" + filepath; // Try again in parent dir
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
filepath.clear();
|
||||
}
|
||||
|
||||
// Could not find the file
|
||||
if (filepath.empty())
|
||||
{
|
||||
const std::string dirList = std::accumulate(directories.begin() + 1, directories.end(), directories.front(),
|
||||
[](const std::string& a, const std::string& b) { return a + "\n\t" + b; });
|
||||
std::cout << "Could not find " << filepathSuffix << " in data directories:\n\t" << dirList << std::endl;
|
||||
|
||||
if (reportError)
|
||||
{
|
||||
std::cout << "&&&& FAILED" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
inline void readPGMFile(const std::string& fileName, uint8_t* buffer, int32_t inH, int32_t inW)
|
||||
{
|
||||
std::ifstream infile(fileName, std::ifstream::binary);
|
||||
SAFE_ASSERT(infile.is_open() && "Attempting to read from a file that is not open.");
|
||||
std::string magic, w, h, max;
|
||||
infile >> magic >> w >> h >> max;
|
||||
infile.seekg(1, infile.cur);
|
||||
infile.read(reinterpret_cast<char*>(buffer), inH * inW);
|
||||
}
|
||||
|
||||
namespace samplesSafeCommon
|
||||
{
|
||||
//! Represents the compute capability of a device.
|
||||
//! This pertains to virtual architectures represented by the intermediate PTX format.
|
||||
//! This is distinct from the SM version.
|
||||
//! See https://forums.developer.nvidia.com/t/how-should-i-use-correctly-the-sm-xx-and-compute-xx/219160
|
||||
struct ComputeCapability
|
||||
{
|
||||
int32_t major{};
|
||||
int32_t minor{};
|
||||
|
||||
//! \return the compute capability of the CUDA device with the given \p deviceIndex.
|
||||
[[nodiscard]] static ComputeCapability forDevice(int32_t deviceIndex)
|
||||
{
|
||||
int32_t major{0};
|
||||
int32_t minor{0};
|
||||
CUDA_CHECK(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, deviceIndex));
|
||||
CUDA_CHECK(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, deviceIndex));
|
||||
return {major, minor};
|
||||
}
|
||||
};
|
||||
|
||||
inline int32_t getSmVersion()
|
||||
{
|
||||
int32_t deviceIndex{};
|
||||
CUDA_CHECK(cudaGetDevice(&deviceIndex));
|
||||
|
||||
auto const cc = ComputeCapability::forDevice(deviceIndex);
|
||||
return ((cc.major << 8) | cc.minor);
|
||||
}
|
||||
|
||||
inline bool isSmSafe()
|
||||
{
|
||||
int32_t const smVersion = getSmVersion();
|
||||
return smVersion == 0x0705 || smVersion == 0x0800 || smVersion == 0x0806 || smVersion == 0x0807
|
||||
|| smVersion == 0x0A00 || smVersion == 0x0B00;
|
||||
}
|
||||
|
||||
inline int32_t calculateSoftmax(float* const prob, int32_t const numDigits)
|
||||
{
|
||||
SAFE_ASSERT(prob != nullptr);
|
||||
SAFE_ASSERT(numDigits == 10);
|
||||
float sum{0.0F};
|
||||
std::transform(prob, prob + numDigits, prob, [&sum](float v) -> float {
|
||||
sum += exp(v);
|
||||
return exp(v);
|
||||
});
|
||||
|
||||
SAFE_ASSERT(sum != 0.0F);
|
||||
std::transform(prob, prob + numDigits, prob, [sum](float v) -> float { return v / sum; });
|
||||
int32_t idx = std::max_element(prob, prob + numDigits) - prob;
|
||||
return idx;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief generate a command line string from the given (argc, argv) values
|
||||
//! Note: It simply joins the arguments without proper escaping. If spaces is part
|
||||
//! of an argument, they will be joined with single space.
|
||||
//!
|
||||
static std::string genCmdlineString(int32_t argc, char const* const* argv)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (int32_t i = 0; i < argc; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
ss << argv[i];
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//!
|
||||
//! \enum TestResult
|
||||
//! \brief Represents the state of a given test
|
||||
//!
|
||||
enum class TestResult
|
||||
{
|
||||
kFAILED, //!< The test failed
|
||||
kPASSED, //!< The test passed
|
||||
};
|
||||
|
||||
|
||||
//!
|
||||
//! \brief method that implements logging test start
|
||||
//!
|
||||
inline void reportTestStart(std::string testName, int32_t argc, char const* const* argv)
|
||||
{
|
||||
SAFE_LOG << "&&&& RUNNING " << testName << " [TensorRT v" << std::to_string(NV_TENSORRT_VERSION) << "] [b"
|
||||
<< std::to_string(NV_TENSORRT_BUILD) << "]" << " # " << genCmdlineString(argc, argv) << std::endl;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \brief method that implements logging test results
|
||||
//!
|
||||
inline void reportTestResult(std::string testName, TestResult result, int32_t argc, char const* const* argv)
|
||||
{
|
||||
SAFE_LOG << "&&&& " << (result == TestResult::kPASSED ? "PASSED" : "FAILED") << " " << testName << " [TensorRT v"
|
||||
<< std::to_string(NV_TENSORRT_VERSION) << "] [b" << std::to_string(NV_TENSORRT_BUILD) << "]"
|
||||
<< " # " << genCmdlineString(argc, argv) << std::endl;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \class TrtCudaGraphSafe
|
||||
//! \brief Managed CUDA graph
|
||||
//!
|
||||
class TrtCudaGraphSafe
|
||||
{
|
||||
public:
|
||||
explicit TrtCudaGraphSafe() = default;
|
||||
|
||||
TrtCudaGraphSafe(const TrtCudaGraphSafe&) = delete;
|
||||
|
||||
TrtCudaGraphSafe& operator=(const TrtCudaGraphSafe&) = delete;
|
||||
|
||||
TrtCudaGraphSafe(TrtCudaGraphSafe&&) = delete;
|
||||
|
||||
TrtCudaGraphSafe& operator=(TrtCudaGraphSafe&&) = delete;
|
||||
|
||||
~TrtCudaGraphSafe()
|
||||
{
|
||||
if (mGraphExec)
|
||||
{
|
||||
cudaGraphExecDestroy(mGraphExec);
|
||||
}
|
||||
}
|
||||
|
||||
void beginCapture(cudaStream_t& stream)
|
||||
{
|
||||
CUDA_CHECK(cudaStreamBeginCapture(stream, cudaStreamCaptureModeThreadLocal));
|
||||
}
|
||||
|
||||
bool launch(cudaStream_t& stream)
|
||||
{
|
||||
return cudaGraphLaunch(mGraphExec, stream) == cudaSuccess;
|
||||
}
|
||||
|
||||
void endCapture(cudaStream_t& stream)
|
||||
{
|
||||
CUDA_CHECK(cudaStreamEndCapture(stream, &mGraph));
|
||||
CUDA_CHECK(cudaGraphInstantiate(&mGraphExec, mGraph, nullptr, nullptr, 0));
|
||||
CUDA_CHECK(cudaGraphDestroy(mGraph));
|
||||
}
|
||||
|
||||
void endCaptureOnError(cudaStream_t& stream)
|
||||
{
|
||||
// There are two possibilities why stream capture would fail:
|
||||
// (1) stream is in cudaErrorStreamCaptureInvalidated state.
|
||||
// (2) TRT reports a failure.
|
||||
// In case (1), the returning mGraph should be nullptr.
|
||||
// In case (2), the returning mGraph is not nullptr, but it should not be used.
|
||||
const auto ret = cudaStreamEndCapture(stream, &mGraph);
|
||||
if (ret == cudaErrorStreamCaptureInvalidated)
|
||||
{
|
||||
SAFE_ASSERT(mGraph == nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_ASSERT(ret == cudaSuccess);
|
||||
SAFE_ASSERT(mGraph != nullptr);
|
||||
CUDA_CHECK(cudaGraphDestroy(mGraph));
|
||||
mGraph = nullptr;
|
||||
}
|
||||
// Clean up any CUDA error.
|
||||
cudaGetLastError();
|
||||
SAFE_LOG << "The CUDA graph capture on the stream has failed." << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
cudaGraph_t mGraph{};
|
||||
cudaGraphExec_t mGraphExec{};
|
||||
};
|
||||
|
||||
inline void* safeLoadLibrary(const std::string& path)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
void* handle = LoadLibraryA(path.c_str());
|
||||
#else
|
||||
int32_t flags{RTLD_LAZY};
|
||||
void* handle = dlopen(path.c_str(), flags);
|
||||
#endif
|
||||
if (handle == nullptr)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
sample::gLogError << "Could not load plugin library: " << path << std::endl;
|
||||
#else
|
||||
SAFE_LOG << "Could not load plugin library: " << path << ", due to: " << dlerror() << std::endl;
|
||||
#endif
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
//!
|
||||
//! \class SafetyPluginAttribute
|
||||
//! \brief Represents a safety plugin with its namespace and name
|
||||
//!
|
||||
class SafetyPluginAttribute
|
||||
{
|
||||
public:
|
||||
std::string pluginNamespace; //!< Plugin namespace (optional, can be empty)
|
||||
std::string pluginName; //!< Plugin name
|
||||
};
|
||||
|
||||
//!
|
||||
//! \class SafetyPluginLibraryArgument
|
||||
//! \brief Represents a safety plugin library with its name and associated plugin attributes
|
||||
//! Used for parsing command line arguments in the format: libraryName[namespace::pluginName1,pluginName2]
|
||||
//!
|
||||
class SafetyPluginLibraryArgument
|
||||
{
|
||||
public:
|
||||
std::string libraryName; //!< Name of the plugin library
|
||||
std::vector<SafetyPluginAttribute> pluginAttrs; //!< Vector of plugin attributes contained in this library
|
||||
};
|
||||
|
||||
inline std::vector<std::string> safeSplitString(std::string str, char delimiter = ',')
|
||||
{
|
||||
std::vector<std::string> splitVect;
|
||||
std::stringstream ss(str);
|
||||
std::string substr;
|
||||
|
||||
while (ss.good())
|
||||
{
|
||||
getline(ss, substr, delimiter);
|
||||
splitVect.emplace_back(std::move(substr));
|
||||
}
|
||||
return splitVect;
|
||||
}
|
||||
|
||||
// Safety plugin cmd argument example: safetyPluginLibrary[namespace::pluginName1,pluginName2]
|
||||
inline bool parseSafetyPluginArgument(std::string const& option, SafetyPluginLibraryArgument& args)
|
||||
{
|
||||
auto const leftBracketIdx = option.find('[');
|
||||
auto const rightBracketIdx = option.find(']');
|
||||
if (leftBracketIdx == std::string::npos || rightBracketIdx == std::string::npos || leftBracketIdx > rightBracketIdx)
|
||||
{
|
||||
SAFE_LOG << "Invalid safety plugin argument: " << option << std::endl;
|
||||
return false;
|
||||
}
|
||||
args.libraryName = option.substr(0, leftBracketIdx);
|
||||
auto const pluginOptionStr = option.substr(leftBracketIdx + 1, rightBracketIdx - leftBracketIdx - 1);
|
||||
auto const pluginOptions = safeSplitString(pluginOptionStr, ',');
|
||||
if (args.libraryName.empty() || pluginOptions.empty())
|
||||
{
|
||||
SAFE_LOG << "Invalid safety plugin argument: " << option << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parsePluginOption = [](std::string const& pluginOption) {
|
||||
SafetyPluginAttribute attr{};
|
||||
// Check if namespace is used, leave as empty if not exist
|
||||
auto const sepratorIdx = pluginOption.find("::");
|
||||
if (sepratorIdx == std::string::npos)
|
||||
{
|
||||
attr.pluginName = pluginOption;
|
||||
}
|
||||
else
|
||||
{
|
||||
attr.pluginNamespace = pluginOption.substr(0, sepratorIdx);
|
||||
attr.pluginName = pluginOption.substr(sepratorIdx + 2, pluginOption.length() - sepratorIdx - 2);
|
||||
}
|
||||
return attr;
|
||||
};
|
||||
|
||||
for (auto const& pluginOption : pluginOptions)
|
||||
{
|
||||
auto attr = parsePluginOption(pluginOption);
|
||||
if (!attr.pluginName.empty())
|
||||
{
|
||||
args.pluginAttrs.push_back(attr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! \brief Check if arg is a command-line option with a value, and get the value.
|
||||
//! If arg matches the form --OPTION=VALUE (or -C=VALUE if singleChar is provided)
|
||||
//! and OPTION matches the provided name (or C matches the provided singleChar),
|
||||
//! extract the option VALUE.
|
||||
//! \param arg The argument to attempt to parse
|
||||
//! \param name The option name to match
|
||||
//! \param singleChar Single-character option, or std::nullopt if full name is required.
|
||||
//! \return If name matched, parsed string VALUE; otherwise std::nullopt.
|
||||
inline std::optional<std::string> parseString(std::string const& arg, std::string const& name, std::optional<char> singleChar = std::nullopt)
|
||||
{
|
||||
for (std::string const& prefix : {
|
||||
"--" + name + "=",
|
||||
singleChar ? std::string{'-', *singleChar, '='} : "",
|
||||
})
|
||||
{
|
||||
if (!prefix.empty() && prefix == arg.substr(0, prefix.size()))
|
||||
{
|
||||
return arg.substr(prefix.size());
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
//! \brief Check if arg is command-line option without a value.
|
||||
//! Check whether arg matches the form --OPT (or -C if singleChar is provided)
|
||||
//! and OPT matches the provided name.
|
||||
//! \param arg The argument to attempt to parse
|
||||
//! \param name The option name to match
|
||||
//! \param singleChar Single-character version of OPT, or std::nullopt if full name is required.
|
||||
//! \return true on match, false otherwise.
|
||||
inline bool parseBool(std::string const& arg, std::string const& name, std::optional<char> singleChar = std::nullopt)
|
||||
{
|
||||
return arg == "--" + name || (singleChar && arg == std::string{'-', *singleChar});
|
||||
}
|
||||
|
||||
inline bool hasCpuOnlyInternalOption(std::string const& internalOptions)
|
||||
{
|
||||
std::istringstream optionStream{internalOptions};
|
||||
for (std::string option; optionStream >> option;)
|
||||
{
|
||||
if (option == "--cpu_only" || option.rfind("--cpu_only=", 0) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool applyCpuOnlyMode()
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
// The use of TRT_INTERNAL_OPTIONS is special to TensorRT 11.0 and will disappear in later releases.
|
||||
char const* internalOptions = std::getenv("TRT_INTERNAL_OPTIONS");
|
||||
std::string internalOptionsStr{internalOptions != nullptr ? internalOptions : ""};
|
||||
if (hasCpuOnlyInternalOption(internalOptionsStr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
internalOptionsStr += " --cpu_only=1";
|
||||
if (setenv("TRT_INTERNAL_OPTIONS", internalOptionsStr.c_str(), 1) != 0)
|
||||
{
|
||||
SAFE_LOG << "Failed to set TRT_INTERNAL_OPTIONS for CPU-only mode: " << std::strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//! \brief Allocate \p graph's auxiliary CUDA streams and register them via setAuxStreams.
|
||||
//!
|
||||
//! The returned scope guard owns the streams; when the last reference is dropped, each
|
||||
//! stream is destroyed via cudaStreamDestroy. The pointed-to value (nullptr) is purposely
|
||||
//! opaque; only the deleter matters. The caller must keep the guard alive during the graph
|
||||
//! inference runs.
|
||||
[[nodiscard]] inline std::shared_ptr<std::nullptr_t> setUpAuxStreamsOn(
|
||||
nvinfer2::safe::ITRTGraph& graph, nvinfer2::safe::ISafeRecorder& recorder)
|
||||
{
|
||||
int32_t nbAuxStreams{};
|
||||
SAFE_API_CALL(graph.getNbAuxStreams(nbAuxStreams), recorder);
|
||||
std::vector<cudaStream_t> streams(nbAuxStreams);
|
||||
for (auto& s : streams)
|
||||
{
|
||||
CUDA_CHECK(cudaStreamCreateWithFlags(&s, cudaStreamNonBlocking));
|
||||
}
|
||||
SAFE_API_CALL(graph.setAuxStreams(streams.data(), nbAuxStreams), recorder);
|
||||
return {nullptr, [streams = std::move(streams)](void*) {
|
||||
for (cudaStream_t s : streams)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
(void) cudaStreamDestroy(s);
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
} // namespace samplesSafeCommon
|
||||
|
||||
namespace safetyCompliance
|
||||
{
|
||||
inline void initSafeCuda()
|
||||
{
|
||||
// According to CUDA initialization in NVIDIA CUDA SAFETY API REFERENCE FOR DRIVE OS
|
||||
// We will need to do the following in order
|
||||
// 1. Initialize the calling thread with CUDA specific information (Call any CUDA RT API identified as init)
|
||||
// 2. Query/Configure and choose the desired CUDA device
|
||||
// 3. CUDA context initialization. (Call cudaDeviceGetLimit or cuCtxCreate)
|
||||
size_t stackSizeLimit = 0;
|
||||
int32_t deviceIndex = 0;
|
||||
CUDA_CHECK(cudaGetDevice(&deviceIndex));
|
||||
CUDA_CHECK(cudaDeviceGetLimit(&stackSizeLimit, cudaLimitStackSize));
|
||||
#if IS_QNX_SAFE
|
||||
CUDA_CHECK(cudaSafeExSelectAPIMode(cudaSafeExAPIModeAsilB));
|
||||
#endif // IS_QNX_SAFE
|
||||
}
|
||||
|
||||
inline void setPromgrAbility()
|
||||
{
|
||||
#if IS_QNX_SAFE
|
||||
// Comply with DEEPLRN_RES_117 on QNX-safe by dropping PROCMGR_AID_MEM_PHYS ability and locking out any further
|
||||
// changes
|
||||
procmgr_ability(
|
||||
0, PROCMGR_ADN_NONROOT | PROCMGR_AOP_DENY | PROCMGR_AOP_LOCK | PROCMGR_AID_MEM_PHYS, PROCMGR_AID_EOL);
|
||||
#endif // IS_QNX_SAFE
|
||||
}
|
||||
|
||||
} // namespace safetyCompliance
|
||||
|
||||
#endif // TENSORRT_SAFE_COMMON_H
|
||||
Reference in New Issue
Block a user