11#include <grpc_client.h>
12#include <grpc_service.pb.h>
23namespace tc = triton::client;
26#define TRITON_CHECK(EXP) \
28 const tc::Error err = EXP; \
30 ATH_MSG_ERROR("Failed to execute: " << #EXP \
33 return StatusCode::FAILURE; \
44 static constexpr const char*
value =
"FP32";
48 static constexpr const char*
value =
"INT64";
56 StatusCode
getClient(tc::InferenceServerGrpcClient*& client,
57 const std::string& url,
int port,
bool useSSL)
const {
59 thread_local std::unique_ptr<tc::InferenceServerGrpcClient> threadClient;
62 const std::string urlAndPort =
63 url +
":" + std::to_string(port);
67 &threadClient, urlAndPort,
verbose, useSSL));
69 ATH_MSG_INFO(
"Triton client created for url: " << urlAndPort);
71 client = threadClient.get();
73 return StatusCode::SUCCESS;
78 tc::Headers httpHeaders;
81 client.IsServerLive(&live, httpHeaders,
m_options->client_timeout_);
86 return tc::Error(
"Triton server is not live");
89 bool serverReady =
false;
90 err = client.IsServerReady(&serverReady, httpHeaders,
96 return tc::Error(
"Triton server is not ready");
99 bool modelReady =
false;
100 err = client.IsModelReady(&modelReady,
m_options->model_name_,
107 return tc::Error(
"Triton model " +
m_options->model_name_ +
" is not ready");
110 return tc::Error::Success;
114 if (retryDelayMs > 0) {
115 std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));
120 tc::InferenceServerGrpcClient& client,
121 const std::vector<tc::InferInput*>& rawInputs,
122 const int maxRetries,
const int retryDelayMs,
123 std::shared_ptr<tc::InferResult>& results)
const {
125 tc::Headers httpHeaders;
126 grpc_compression_algorithm compressionAlgorithm =
127 grpc_compression_algorithm::GRPC_COMPRESS_NONE;
130 for (
int attempt = 0; attempt <= maxRetries; ++attempt) {
132 tc::InferResult* rawResultPtr =
nullptr;
133 err = client.Infer(&rawResultPtr, *
m_options, rawInputs, {},
134 httpHeaders, compressionAlgorithm);
135 if (err.IsOk() && rawResultPtr !=
nullptr) {
136 results.reset(rawResultPtr);
137 err = results->RequestStatus();
138 }
else if (err.IsOk()) {
139 err = tc::Error(
"Triton synchronous inference returned no result");
142 using Promise_t = boost::fibers::promise<tc::InferResult*>;
143 using Future_t = boost::fibers::future<tc::InferResult*>;
145 Future_t future = promise.get_future();
146 auto callback = [&promise](tc::InferResult* resultPtr) {
147 promise.set_value(resultPtr);
149 err = client.AsyncInfer(callback, *
m_options, rawInputs, {},
150 httpHeaders, compressionAlgorithm);
152 results.reset(future.get());
154 if (results !=
nullptr) {
155 err = results->RequestStatus();
157 err = tc::Error(
"Triton asynchronous inference returned no "
164 return StatusCode::SUCCESS;
167 if (attempt == maxRetries) {
168 ATH_MSG_ERROR(
"Triton inference failed after " << (attempt + 1)
171 return StatusCode::FAILURE;
175 <<
" failed: " << err
180 return StatusCode::FAILURE;
183 template <
typename T>
185 const std::string& name,
const std::vector<int64_t>& shape,
186 const std::vector<T>& data,
187 std::vector<std::unique_ptr<tc::InferInput>>& inputs)
const {
190 tc::InferInput* rawInputPtr =
nullptr;
194 TRITON_CHECK(tc::InferInput::Create(&rawInputPtr, name, shape, dtype));
195 assert(rawInputPtr !=
nullptr);
203 std::unique_ptr<tc::InferInput> input{rawInputPtr};
204 TRITON_CHECK(input->AppendRaw(
reinterpret_cast<const uint8_t*
>(data.data()),
205 data.size() *
sizeof(T)));
207 inputs.push_back(std::move(input));
208 return StatusCode::SUCCESS;
211 template <
typename T>
213 const tc::InferResult& result,
214 std::vector<T>& outputVec)
const {
216 const uint8_t* rawData =
nullptr;
224 outputVec.resize(
size /
sizeof(T));
225 std::memcpy(outputVec.data(), rawData,
size);
226 return StatusCode::SUCCESS;
235 const IInterface* parent)
236 : base_class(
type, name, parent) {}
243 m_impl = std::make_unique<Impl>(name() +
"::Impl");
250 const IAlgTool* p =
dynamic_cast<const IAlgTool*
>(
this);
253 const IInterface* myParent =
nullptr;
254 while (p !=
nullptr) {
255 myParent = p->parent();
256 p =
dynamic_cast<const IAlgTool*
>(myParent);
260 m_impl->m_parentAsyncAlg =
262 if (
m_impl->m_parentAsyncAlg !=
nullptr) {
264 "Owned by an AthAsynchronousAlgorithm, using asynchronous inference");
267 "Not owned by an AthAsynchronousAlgorithm, not using asynchronous "
272 tc::InferenceServerGrpcClient* dummyClient =
nullptr;
276 tc::Error err =
m_impl->checkServerHealth(*dummyClient);
279 return StatusCode::FAILURE;
283 return StatusCode::SUCCESS;
293 std::vector<std::unique_ptr<tc::InferInput>> inputs;
294 inputs.reserve(inputData.size());
296 for (
auto& [inputName, inputInfo] : inputData) {
298 const std::vector<int64_t>& inputShape = inputInfo.first;
302 [&](
const auto& dataVec) {
303 using T = std::decay_t<
decltype(dataVec[0])>;
304 return m_impl->prepareInput<T>(inputName, inputShape, dataVec,
311 std::vector<tc::InferInput*> rawInputs;
312 for (
auto& input : inputs) {
313 rawInputs.push_back(input.get());
317 tc::InferenceServerGrpcClient* client =
nullptr;
319 assert(client !=
nullptr);
322 std::shared_ptr<tc::InferResult> results;
325 const int maxRetries = maxRetriesValue < 0 ? 0 : maxRetriesValue;
326 const int retryDelayMs = retryDelayMsValue < 0 ? 0 : retryDelayMsValue;
328 m_impl->runInference(*client, rawInputs, maxRetries, retryDelayMs,
330 assert(results !=
nullptr);
333 for (
auto& [outputName, outputInfo] : outputData) {
339 using T = std::decay_t<
decltype(dataVec[0])>;
340 return m_impl->extractOutput<T>(outputName, *results, dataVec);
346 return StatusCode::SUCCESS;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
size_t size() const
Number of registered mappings.
An algorithm that can be suspended while work is offloaded to an accelerator.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
std::map< std::string, InferenceData > OutputDataMap
std::variant< std::vector< float >, std::vector< int64_t > > DataVariant
std::map< std::string, InferenceData > InputDataMap
static constexpr const char * value
static constexpr const char * value