#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <triton/core/tritonserver.h>
#include <iostream>
namespace py = pybind11;
namespace triton { namespace core { namespace python {
#define DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete;
#define DISALLOW_ASSIGN(TypeName) void operator=(const TypeName&) = delete;
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
DISALLOW_COPY(TypeName) \
DISALLOW_ASSIGN(TypeName)
#define DESTRUCTOR_WITH_LOG(TypeName, DeleteFunction) \
~TypeName() \
{ \
if (owned_ && triton_object_) { \
auto err__ = (DeleteFunction(triton_object_)); \
if (err__) { \
std::shared_ptr<TRITONSERVER_Error> managed_err( \
err__, TRITONSERVER_ErrorDelete); \
py::print(TRITONSERVER_ErrorMessage(err__)); \
} \
}}
struct TritonError : public std::runtime_error {
explicit TritonError(const std::string& what) : std::runtime_error(what) {}
};
struct UnknownError : public TritonError {
explicit UnknownError(const std::string& what) : TritonError(what) {}
};
struct InternalError : public TritonError {
explicit InternalError(const std::string& what) : TritonError(what) {}
};
struct NotFoundError : public TritonError {
explicit NotFoundError(const std::string& what) : TritonError(what) {}
};
struct InvalidArgumentError : public TritonError {
explicit InvalidArgumentError(const std::string& what) : TritonError(what) {}
};
struct UnavailableError : public TritonError {
explicit UnavailableError(const std::string& what) : TritonError(what) {}
};
struct UnsupportedError : public TritonError {
explicit UnsupportedError(const std::string& what) : TritonError(what) {}
};
struct AlreadyExistsError : public TritonError {
explicit AlreadyExistsError(const std::string& what) : TritonError(what) {}
};
TRITONSERVER_Error*
CreateTRITONSERVER_ErrorFrom(const py::error_already_set& ex)
{
static auto it = py::module::import("triton_bindings").attr("InternalError");
static auto nf = py::module::import("triton_bindings").attr("NotFoundError");
static auto ia =
py::module::import("triton_bindings").attr("InvalidArgumentError");
static auto ua =
py::module::import("triton_bindings").attr("UnavailableError");
static auto us =
py::module::import("triton_bindings").attr("UnsupportedError");
static auto ae =
py::module::import("triton_bindings").attr("AlreadyExistsError");
TRITONSERVER_Error_Code code = TRITONSERVER_ERROR_UNKNOWN;
if (ex.matches(it.ptr())) {
code = TRITONSERVER_ERROR_INTERNAL;
} else if (ex.matches(nf.ptr())) {
code = TRITONSERVER_ERROR_NOT_FOUND;
} else if (ex.matches(ia.ptr())) {
code = TRITONSERVER_ERROR_INVALID_ARG;
} else if (ex.matches(ua.ptr())) {
code = TRITONSERVER_ERROR_UNAVAILABLE;
} else if (ex.matches(us.ptr())) {
code = TRITONSERVER_ERROR_UNSUPPORTED;
} else if (ex.matches(ae.ptr())) {
code = TRITONSERVER_ERROR_ALREADY_EXISTS;
}
return TRITONSERVER_ErrorNew(code, ex.what());
}
void
ThrowIfError(TRITONSERVER_Error* err)
{
if (err == nullptr) {
return;
}
std::shared_ptr<TRITONSERVER_Error> managed_err(
err, TRITONSERVER_ErrorDelete);
std::string msg = TRITONSERVER_ErrorMessage(err);
switch (TRITONSERVER_ErrorCode(err)) {
case TRITONSERVER_ERROR_INTERNAL:
throw InternalError(std::move(msg));
case TRITONSERVER_ERROR_NOT_FOUND:
throw NotFoundError(std::move(msg));
case TRITONSERVER_ERROR_INVALID_ARG:
throw InvalidArgumentError(std::move(msg));
case TRITONSERVER_ERROR_UNAVAILABLE:
throw UnavailableError(std::move(msg));
case TRITONSERVER_ERROR_UNSUPPORTED:
throw UnsupportedError(std::move(msg));
case TRITONSERVER_ERROR_ALREADY_EXISTS:
throw AlreadyExistsError(std::move(msg));
default:
throw UnknownError(std::move(msg));
}
}
template <typename TritonStruct>
class PyWrapper {
public:
explicit PyWrapper(TritonStruct* triton_object, bool owned)
: triton_object_(triton_object), owned_(owned)
{
}
PyWrapper() = default;
TritonStruct* Ptr() { return triton_object_; }
DISALLOW_COPY_AND_ASSIGN(PyWrapper);
protected:
TritonStruct* triton_object_{nullptr};
bool owned_{false};
};
class PyParameter : public PyWrapper<struct TRITONSERVER_Parameter> {
public:
explicit PyParameter(struct TRITONSERVER_Parameter* p, const bool owned)
: PyWrapper(p, owned)
{
}
PyParameter(const char* name, const std::string& val)
: PyWrapper(
TRITONSERVER_ParameterNew(
name, TRITONSERVER_PARAMETER_STRING, val.c_str()),
true)
{
}
PyParameter(const char* name, int64_t val)
: PyWrapper(
TRITONSERVER_ParameterNew(name, TRITONSERVER_PARAMETER_INT, &val),
true)
{
}
PyParameter(const char* name, double val)
: PyWrapper(
TRITONSERVER_ParameterNew(
name, TRITONSERVER_PARAMETER_DOUBLE, &val),
true)
{
}
PyParameter(const char* name, bool val)
: PyWrapper(
TRITONSERVER_ParameterNew(name, TRITONSERVER_PARAMETER_BOOL, &val),
true)
{
}
PyParameter(const char* name, const void* byte_ptr, uint64_t size)
: PyWrapper(TRITONSERVER_ParameterBytesNew(name, byte_ptr, size), true)
{
}
~PyParameter()
{
if (owned_ && triton_object_) {
TRITONSERVER_ParameterDelete(triton_object_);
}
}
};
class PyBufferAttributes
: public PyWrapper<struct TRITONSERVER_BufferAttributes> {
public:
DESTRUCTOR_WITH_LOG(PyBufferAttributes, TRITONSERVER_BufferAttributesDelete);
PyBufferAttributes()
{
ThrowIfError(TRITONSERVER_BufferAttributesNew(&triton_object_));
owned_ = true;
}
explicit PyBufferAttributes(
struct TRITONSERVER_BufferAttributes* ba, const bool owned)
: PyWrapper(ba, owned)
{
}
void SetMemoryTypeId(int64_t memory_type_id)
{
ThrowIfError(TRITONSERVER_BufferAttributesSetMemoryTypeId(
triton_object_, memory_type_id));
}
void SetMemoryType(TRITONSERVER_MemoryType memory_type)
{
ThrowIfError(TRITONSERVER_BufferAttributesSetMemoryType(
triton_object_, memory_type));
}
void SetCudaIpcHandle(uintptr_t cuda_ipc_handle)
{
ThrowIfError(TRITONSERVER_BufferAttributesSetCudaIpcHandle(
triton_object_, reinterpret_cast<void*>(cuda_ipc_handle)));
}
void SetByteSize(size_t byte_size)
{
ThrowIfError(
TRITONSERVER_BufferAttributesSetByteSize(triton_object_, byte_size));
}
int64_t MemoryTypeId()
{
int64_t memory_type_id = 0;
ThrowIfError(TRITONSERVER_BufferAttributesMemoryTypeId(
triton_object_, &memory_type_id));
return memory_type_id;
}
TRITONSERVER_MemoryType MemoryType()
{
TRITONSERVER_MemoryType memory_type = TRITONSERVER_MEMORY_CPU;
ThrowIfError(
TRITONSERVER_BufferAttributesMemoryType(triton_object_, &memory_type));
return memory_type;
}
uintptr_t CudaIpcHandle()
{
void* cuda_ipc_handle = nullptr;
ThrowIfError(TRITONSERVER_BufferAttributesCudaIpcHandle(
triton_object_, &cuda_ipc_handle));
return reinterpret_cast<uintptr_t>(cuda_ipc_handle);
}
size_t ByteSize()
{
size_t byte_size;
ThrowIfError(
TRITONSERVER_BufferAttributesByteSize(triton_object_, &byte_size));
return byte_size;
}
};
class PyResponseAllocator
: public PyWrapper<struct TRITONSERVER_ResponseAllocator> {
public:
DESTRUCTOR_WITH_LOG(
PyResponseAllocator, TRITONSERVER_ResponseAllocatorDelete);
struct CallbackResource {
CallbackResource(const py::object& a, const py::object& uo)
: allocator(a), user_object(uo)
{
}
py::object allocator;
py::object user_object;
};
using AllocFn = std::function<
std::tuple<uintptr_t, py::object, TRITONSERVER_MemoryType, int64_t>(
py::object, std::string, size_t, TRITONSERVER_MemoryType, int64_t,
py::object)>;
using ReleaseFn = std::function<void(
py::object, uintptr_t, py::object, size_t, TRITONSERVER_MemoryType,
int64_t)>;
using StartFn = std::function<void(py::object, py::object)>;
using QueryFn = std::function<std::tuple<TRITONSERVER_MemoryType, int64_t>(
py::object, py::object, std::string, std::optional<size_t>,
TRITONSERVER_MemoryType, int64_t)>;
using BufferAttributesFn = std::function<py::object(
py::object, std::string, py::object, py::object, py::object)>;
PyResponseAllocator(AllocFn alloc, ReleaseFn release)
: alloc_fn_(alloc), release_fn_(release)
{
ThrowIfError(TRITONSERVER_ResponseAllocatorNew(
&triton_object_, PyTritonAllocFn, PyTritonReleaseFn, nullptr));
owned_ = true;
}
PyResponseAllocator(AllocFn alloc, ReleaseFn release, StartFn start)
: alloc_fn_(alloc), release_fn_(release), start_fn_(start)
{
ThrowIfError(TRITONSERVER_ResponseAllocatorNew(
&triton_object_, PyTritonAllocFn, PyTritonReleaseFn, PyTritonStartFn));
owned_ = true;
}
static TRITONSERVER_Error* PyTritonAllocFn(
struct TRITONSERVER_ResponseAllocator* allocator, const char* tensor_name,
size_t byte_size, TRITONSERVER_MemoryType memory_type,
int64_t memory_type_id, void* userp, void** buffer, void** buffer_userp,
TRITONSERVER_MemoryType* actual_memory_type,
int64_t* actual_memory_type_id)
{
py::gil_scoped_acquire gil;
struct TRITONSERVER_Error* err = nullptr;
auto cr = reinterpret_cast<CallbackResource*>(userp);
try {
auto res = cr->allocator.cast<PyResponseAllocator*>()->alloc_fn_(
cr->allocator, tensor_name, byte_size, memory_type, memory_type_id,
cr->user_object);
*buffer = reinterpret_cast<void*>(std::get<0>(res));
{
*buffer_userp = new CallbackResource(cr->allocator, std::get<1>(res));
}
*actual_memory_type = std::get<2>(res);
*actual_memory_type_id = std::get<3>(res);
}
catch (py::error_already_set& ex) {
err = CreateTRITONSERVER_ErrorFrom(ex);
}
return err;
}
static TRITONSERVER_Error* PyTritonReleaseFn(
struct TRITONSERVER_ResponseAllocator* allocator, void* buffer,
void* buffer_userp, size_t byte_size, TRITONSERVER_MemoryType memory_type,
int64_t memory_type_id)
{
py::gil_scoped_acquire gil;
struct TRITONSERVER_Error* err = nullptr;
auto cr = reinterpret_cast<CallbackResource*>(buffer_userp);
try {
cr->allocator.cast<PyResponseAllocator*>()->release_fn_(
cr->allocator, reinterpret_cast<uintptr_t>(buffer), cr->user_object,
byte_size, memory_type, memory_type_id);
}
catch (py::error_already_set& ex) {
err = CreateTRITONSERVER_ErrorFrom(ex);
}
delete cr;
return err;
}
static TRITONSERVER_Error* PyTritonStartFn(
struct TRITONSERVER_ResponseAllocator* allocator, void* userp)
{
py::gil_scoped_acquire gil;
struct TRITONSERVER_Error* err = nullptr;
auto cr = reinterpret_cast<CallbackResource*>(userp);
try {
cr->allocator.cast<PyResponseAllocator*>()->start_fn_(
cr->allocator, cr->user_object);
}
catch (py::error_already_set& ex) {
err = CreateTRITONSERVER_ErrorFrom(ex);
}
return err;
}
static TRITONSERVER_Error* PyTritonQueryFn(
struct TRITONSERVER_ResponseAllocator* allocator, void* userp,
const char* tensor_name, size_t* byte_size,
TRITONSERVER_MemoryType* memory_type, int64_t* memory_type_id)
{
py::gil_scoped_acquire gil;
struct TRITONSERVER_Error* err = nullptr;
auto cr = reinterpret_cast<CallbackResource*>(userp);
try {
std::optional<size_t> bs;
if (byte_size) {
bs = *byte_size;
}
auto res = cr->allocator.cast<PyResponseAllocator*>()->query_fn_(
cr->allocator, cr->user_object, tensor_name, bs, *memory_type,
*memory_type_id);
*memory_type = std::get<0>(res);
*memory_type_id = std::get<1>(res);
}
catch (py::error_already_set& ex) {
err = CreateTRITONSERVER_ErrorFrom(ex);
}
return err;
}
static TRITONSERVER_Error* PyTritonBufferAttributesFn(
struct TRITONSERVER_ResponseAllocator* allocator, const char* tensor_name,
struct TRITONSERVER_BufferAttributes* buffer_attributes, void* userp,
void* buffer_userp)
{
py::gil_scoped_acquire gil;
struct TRITONSERVER_Error* err = nullptr;
auto cr = reinterpret_cast<CallbackResource*>(userp);
auto bcr = reinterpret_cast<CallbackResource*>(buffer_userp);
PyBufferAttributes pba{buffer_attributes, false };
try {
auto res =
cr->allocator.cast<PyResponseAllocator*>()->buffer_attributes_fn_(
cr->allocator, tensor_name,
py::cast(pba, py::return_value_policy::reference),
cr->user_object, bcr->user_object);
auto res_pba = res.cast<PyBufferAttributes*>();
if (res_pba->Ptr() != buffer_attributes) {
pba.SetMemoryTypeId(res_pba->MemoryTypeId());
pba.SetMemoryType(res_pba->MemoryType());
pba.SetCudaIpcHandle(res_pba->CudaIpcHandle());
pba.SetByteSize(res_pba->ByteSize());
}
}
catch (py::error_already_set& ex) {
err = CreateTRITONSERVER_ErrorFrom(ex);
}
return err;
}
void SetBufferAttributesFunction(BufferAttributesFn baf)
{
buffer_attributes_fn_ = baf;
ThrowIfError(TRITONSERVER_ResponseAllocatorSetBufferAttributesFunction(
triton_object_, PyTritonBufferAttributesFn));
}
void SetQueryFunction(QueryFn qf)
{
query_fn_ = qf;
ThrowIfError(TRITONSERVER_ResponseAllocatorSetQueryFunction(
triton_object_, PyTritonQueryFn));
}
private:
AllocFn alloc_fn_{nullptr};
ReleaseFn release_fn_{nullptr};
StartFn start_fn_{nullptr};
QueryFn query_fn_{nullptr};
BufferAttributesFn buffer_attributes_fn_{nullptr};
};
class PyMessage : public PyWrapper<struct TRITONSERVER_Message> {
public:
DESTRUCTOR_WITH_LOG(PyMessage, TRITONSERVER_MessageDelete);
PyMessage(const std::string& serialized_json)
{
ThrowIfError(TRITONSERVER_MessageNewFromSerializedJson(
&triton_object_, serialized_json.c_str(), serialized_json.size()));
owned_ = true;
}
explicit PyMessage(struct TRITONSERVER_Message* m, const bool owned)
: PyWrapper(m, owned)
{
}
std::string SerializeToJson()
{
const char* base = nullptr;
size_t byte_size = 0;
ThrowIfError(
TRITONSERVER_MessageSerializeToJson(triton_object_, &base, &byte_size));
return std::string(base, byte_size);
}
};
class PyMetrics : public PyWrapper<struct TRITONSERVER_Metrics> {
public:
DESTRUCTOR_WITH_LOG(PyMetrics, TRITONSERVER_MetricsDelete);
explicit PyMetrics(struct TRITONSERVER_Metrics* metrics, bool owned)
: PyWrapper(metrics, owned)
{
}
std::string Formatted(TRITONSERVER_MetricFormat format)
{
const char* base = nullptr;
size_t byte_size = 0;
ThrowIfError(TRITONSERVER_MetricsFormatted(
triton_object_, format, &base, &byte_size));
return std::string(base, byte_size);
}
};
class PyTrace : public PyWrapper<struct TRITONSERVER_InferenceTrace> {
public:
DESTRUCTOR_WITH_LOG(PyTrace, TRITONSERVER_InferenceTraceDelete);
using TimestampActivityFn = std::function<void(
py::object, TRITONSERVER_InferenceTraceActivity, uint64_t, py::object)>;
using TensorActivityFn = std::function<void(
py::object, TRITONSERVER_InferenceTraceActivity, std::string,
TRITONSERVER_DataType, uintptr_t, size_t, py::array_t<int64_t>,
TRITONSERVER_MemoryType, int64_t, py::object)>;
using ReleaseFn = std::function<void(std::shared_ptr<PyTrace>, py::object)>;
struct CallbackResource {
CallbackResource(
TimestampActivityFn ts, TensorActivityFn t, ReleaseFn r,
const py::object& uo)
: timestamp_fn(ts), tensor_fn(t), release_fn(r), user_object(uo)
{
}
TimestampActivityFn timestamp_fn{nullptr};
TensorActivityFn tensor_fn{nullptr};
ReleaseFn release_fn{nullptr};
py::object user_object;
std::set<uintptr_t> seen_traces;
};
struct TRITONSERVER_InferenceTrace* Release()
{
owned_ = false;
callback_resource_.release();
return triton_object_;
}
PyTrace(
int level, uint64_t parent_id, TimestampActivityFn timestamp,
ReleaseFn release, const py::object& user_object)
: callback_resource_(
new CallbackResource(timestamp, nullptr, release, user_object))
{
ThrowIfError(TRITONSERVER_InferenceTraceNew(
&triton_object_, static_cast<TRITONSERVER_InferenceTraceLevel>(level),
parent_id, PyTritonTraceTimestampActivityFn, PyTritonTraceRelease,
callback_resource_.get()));
owned_ = true;
}
PyTrace(
int level, uint64_t parent_id, TimestampActivityFn timestamp,
TensorActivityFn tensor, ReleaseFn release, const py::object& user_object)
: callback_resource_(
new CallbackResource(timestamp, tensor, release, user_object))
{
ThrowIfError(TRITONSERVER_InferenceTraceTensorNew(
&triton_object_, static_cast<TRITONSERVER_InferenceTraceLevel>(level),
parent_id, PyTritonTraceTimestampActivityFn,
PyTritonTraceTensorActivityFn, PyTritonTraceRelease,
callback_resource_.get()));
owned_ = true;
}
explicit PyTrace(struct TRITONSERVER_InferenceTrace* t, const bool owned)
: PyWrapper(t, owned)
{
}
CallbackResource* ReleaseCallbackResource()
{
return callback_resource_.release();
}
uint64_t Id()
{
uint64_t val = 0;
ThrowIfError(TRITONSERVER_InferenceTraceId(triton_object_, &val));
return val;
}
uint64_t ParentId()
{
uint64_t val = 0;
ThrowIfError(TRITONSERVER_InferenceTraceParentId(triton_object_, &val));
return val;
}
std::string ModelName()
{
const char* val = nullptr;
ThrowIfError(TRITONSERVER_InferenceTraceModelName(triton_object_, &val));
return val;
}
int64_t ModelVersion()
{
int64_t val = 0;
ThrowIfError(TRITONSERVER_InferenceTraceModelVersion(triton_object_, &val));
return val;
}
std::string RequestId()
{
const char* val = nullptr;
ThrowIfError(TRITONSERVER_InferenceTraceRequestId(triton_object_, &val));
return val;
}
static void PyTritonTraceTimestampActivityFn(
struct TRITONSERVER_InferenceTrace* trace,
TRITONSERVER_InferenceTraceActivity activity, uint64_t timestamp_ns,
void* userp)
{
py::gil_scoped_acquire gil;
PyTrace pt(trace, false );
auto cr = reinterpret_cast<CallbackResource*>(userp);
cr->seen_traces.insert(reinterpret_cast<uintptr_t>(trace));
cr->timestamp_fn(
py::cast(pt, py::return_value_policy::reference), activity,
timestamp_ns, cr->user_object);
}
static void PyTritonTraceTensorActivityFn(
struct TRITONSERVER_InferenceTrace* trace,
TRITONSERVER_InferenceTraceActivity activity, const char* name,
TRITONSERVER_DataType datatype, const void* base, size_t byte_size,
const int64_t* shape, uint64_t dim_count,
TRITONSERVER_MemoryType memory_type, int64_t memory_type_id, void* userp)
{
py::gil_scoped_acquire gil;
PyTrace pt(trace, false );
auto cr = reinterpret_cast<CallbackResource*>(userp);
cr->seen_traces.insert(reinterpret_cast<uintptr_t>(trace));
cr->tensor_fn(
py::cast(pt, py::return_value_policy::reference), activity, name,
datatype, reinterpret_cast<uintptr_t>(base), byte_size,
py::array_t<int64_t>(dim_count, shape), memory_type, memory_type_id,
cr->user_object);
}
static void PyTritonTraceRelease(
struct TRITONSERVER_InferenceTrace* trace, void* userp)
{
py::gil_scoped_acquire gil;
auto managed_pt = std::make_shared<PyTrace>(trace, true );
auto cr = reinterpret_cast<CallbackResource*>(userp);
cr->release_fn(managed_pt, cr->user_object);
cr->seen_traces.erase(reinterpret_cast<uintptr_t>(trace));
if (cr->seen_traces.empty()) {
delete cr;
}
}
private:
std::unique_ptr<CallbackResource> callback_resource_{nullptr};
};
class PyInferenceResponse
: public PyWrapper<struct TRITONSERVER_InferenceResponse> {
public:
DESTRUCTOR_WITH_LOG(
PyInferenceResponse, TRITONSERVER_InferenceResponseDelete);
using CompleteFn = std::function<void(py::object, uint32_t, py::object)>;
struct CallbackResource {
CallbackResource(
CompleteFn c, PyResponseAllocator::CallbackResource* a,
const py::object& u)
: complete_fn(c), allocator_resource(a), user_object(u)
{
}
CompleteFn complete_fn;
PyResponseAllocator::CallbackResource* allocator_resource;
py::object user_object;
};
explicit PyInferenceResponse(
struct TRITONSERVER_InferenceResponse* response, bool owned)
: PyWrapper(response, owned)
{
}
void ThrowIfResponseError()
{
ThrowIfError(TRITONSERVER_InferenceResponseError(triton_object_));
}
std::tuple<std::string, int64_t> Model()
{
const char* model_name = nullptr;
int64_t model_version = 0;
ThrowIfError(TRITONSERVER_InferenceResponseModel(
triton_object_, &model_name, &model_version));
return {model_name, model_version};
}
std::string Id()
{
const char* val = nullptr;
ThrowIfError(TRITONSERVER_InferenceResponseId(triton_object_, &val));
return val;
}
uint32_t ParameterCount()
{
uint32_t val = 0;
ThrowIfError(
TRITONSERVER_InferenceResponseParameterCount(triton_object_, &val));
return val;
}
std::tuple<std::string, TRITONSERVER_ParameterType, py::object> Parameter(
uint32_t index)
{
const char* name = nullptr;
TRITONSERVER_ParameterType type = TRITONSERVER_PARAMETER_STRING;
const void* value = nullptr;
ThrowIfError(TRITONSERVER_InferenceResponseParameter(
triton_object_, index, &name, &type, &value));
py::object py_value;
switch (type) {
case TRITONSERVER_PARAMETER_STRING:
py_value = py::str(reinterpret_cast<const char*>(value));
break;
case TRITONSERVER_PARAMETER_INT:
py_value = py::int_(*reinterpret_cast<const int*>(value));
break;
case TRITONSERVER_PARAMETER_BOOL:
py_value = py::bool_(*reinterpret_cast<const bool*>(value));
break;
case TRITONSERVER_PARAMETER_DOUBLE:
py_value = py::float_(*reinterpret_cast<const double*>(value));
break;
default:
throw UnsupportedError(
std::string("Unexpected type '") +
TRITONSERVER_ParameterTypeString(type) +
"' received as response parameter");
break;
}
return {name, type, py_value};
}
uint32_t OutputCount()
{
uint32_t val = 0;
ThrowIfError(
TRITONSERVER_InferenceResponseOutputCount(triton_object_, &val));
return val;
}
std::tuple<
std::string, TRITONSERVER_DataType, py::array_t<int64_t>, uintptr_t,
size_t, TRITONSERVER_MemoryType, int64_t, py::object>
Output(uint32_t index)
{
const char* name = nullptr;
TRITONSERVER_DataType datatype = TRITONSERVER_TYPE_INVALID;
const int64_t* shape = nullptr;
uint64_t dim_count = 0;
const void* base = nullptr;
size_t byte_size = 0;
TRITONSERVER_MemoryType memory_type = TRITONSERVER_MEMORY_CPU;
int64_t memory_type_id = 0;
void* userp = nullptr;
ThrowIfError(TRITONSERVER_InferenceResponseOutput(
triton_object_, index, &name, &datatype, &shape, &dim_count, &base,
&byte_size, &memory_type, &memory_type_id, &userp));
return {
name,
datatype,
py::array_t<int64_t>(dim_count, shape),
reinterpret_cast<uintptr_t>(base),
byte_size,
memory_type,
memory_type_id,
reinterpret_cast<PyResponseAllocator::CallbackResource*>(userp)
->user_object};
}
std::string OutputClassificationLabel(uint32_t index, size_t class_index)
{
const char* val = nullptr;
ThrowIfError(TRITONSERVER_InferenceResponseOutputClassificationLabel(
triton_object_, index, class_index, &val));
return (val == nullptr) ? "" : val;
}
};
class PyServer;
class PyInferenceRequest
: public PyWrapper<struct TRITONSERVER_InferenceRequest> {
public:
DESTRUCTOR_WITH_LOG(PyInferenceRequest, TRITONSERVER_InferenceRequestDelete);
using ReleaseFn = std::function<void(
std::shared_ptr<PyInferenceRequest>, uint32_t, py::object)>;
PyInferenceRequest(
PyServer& server, const std::string& model_name,
const int64_t model_version);
explicit PyInferenceRequest(
struct TRITONSERVER_InferenceRequest* r, const bool owned)
: PyWrapper(r, owned)
{
}
struct TRITONSERVER_InferenceRequest* Release()
{
allocator_callback_resource_.release();
response_callback_resource_.release();
return triton_object_;
}
struct CallbackResource {
CallbackResource(ReleaseFn r, const py::object& uo)
: release_fn(r), user_object(uo)
{
}
ReleaseFn release_fn;
py::object user_object;
std::shared_ptr<PyInferenceRequest> request;
};
void SetReleaseCallback(ReleaseFn release, const py::object& user_object)
{
request_callback_resource_.reset(
new CallbackResource(release, user_object));
ThrowIfError(TRITONSERVER_InferenceRequestSetReleaseCallback(
triton_object_, PyTritonRequestReleaseCallback,
request_callback_resource_.get()));
}
static void PyTritonRequestReleaseCallback(
struct TRITONSERVER_InferenceRequest* request, const uint32_t flags,
void* userp)
{
py::gil_scoped_acquire gil;
auto cr = reinterpret_cast<CallbackResource*>(userp);
cr->release_fn(cr->request, flags, cr->user_object);
delete cr;
}
void SetResponseCallback(
const py::object& allocator, const py::object& allocater_user_object,
PyInferenceResponse::CompleteFn response,
const py::object& response_user_object)
{
allocator_callback_resource_.reset(
new PyResponseAllocator::CallbackResource(
allocator, allocater_user_object));
response_callback_resource_.reset(new PyInferenceResponse::CallbackResource(
response, allocator_callback_resource_.get(), response_user_object));
ThrowIfError(TRITONSERVER_InferenceRequestSetResponseCallback(
triton_object_, allocator.cast<PyResponseAllocator*>()->Ptr(),
allocator_callback_resource_.get(), PyTritonResponseCompleteCallback,
response_callback_resource_.get()));
}
static void PyTritonResponseCompleteCallback(
struct TRITONSERVER_InferenceResponse* response, const uint32_t flags,
void* userp)
{
py::gil_scoped_acquire gil;
auto managed_pt =
std::make_shared<PyInferenceResponse>(response, true );
auto cr = reinterpret_cast<PyInferenceResponse::CallbackResource*>(userp);
if (response == nullptr) {
cr->complete_fn(py::none(), flags, cr->user_object);
} else {
cr->complete_fn(py::cast(managed_pt), flags, cr->user_object);
}
if (flags & TRITONSERVER_RESPONSE_COMPLETE_FINAL) {
delete cr->allocator_resource;
delete cr;
}
}
void SetId(const std::string& id)
{
ThrowIfError(
TRITONSERVER_InferenceRequestSetId(triton_object_, id.c_str()));
}
std::string Id()
{
const char* val = nullptr;
ThrowIfError(TRITONSERVER_InferenceRequestId(triton_object_, &val));
return val;
}
void SetFlags(uint32_t flags)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetFlags(triton_object_, flags));
}
uint32_t Flags()
{
uint32_t val = 0;
ThrowIfError(TRITONSERVER_InferenceRequestFlags(triton_object_, &val));
return val;
}
void SetCorrelationId(uint64_t correlation_id)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetCorrelationId(
triton_object_, correlation_id));
}
uint64_t CorrelationId()
{
uint64_t val = 0;
ThrowIfError(
TRITONSERVER_InferenceRequestCorrelationId(triton_object_, &val));
return val;
}
void SetCorrelationIdString(const std::string& correlation_id)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetCorrelationIdString(
triton_object_, correlation_id.c_str()));
}
std::string CorrelationIdString()
{
const char* val = nullptr;
ThrowIfError(
TRITONSERVER_InferenceRequestCorrelationIdString(triton_object_, &val));
return val;
}
void SetPriority(uint32_t priority)
{
ThrowIfError(
TRITONSERVER_InferenceRequestSetPriority(triton_object_, priority));
}
void SetPriorityUint64(uint64_t priority)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetPriorityUInt64(
triton_object_, priority));
}
uint32_t Priority()
{
uint32_t val = 0;
ThrowIfError(TRITONSERVER_InferenceRequestPriority(triton_object_, &val));
return val;
}
uint64_t PriorityUint64()
{
uint64_t val = 0;
ThrowIfError(
TRITONSERVER_InferenceRequestPriorityUInt64(triton_object_, &val));
return val;
}
void SetTimeoutMicroseconds(uint64_t timeout_us)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetTimeoutMicroseconds(
triton_object_, timeout_us));
}
uint64_t TimeoutMicroseconds()
{
uint64_t val = 0;
ThrowIfError(
TRITONSERVER_InferenceRequestTimeoutMicroseconds(triton_object_, &val));
return val;
}
void AddInput(
const std::string& name, TRITONSERVER_DataType data_type,
std::vector<int64_t> shape)
{
ThrowIfError(TRITONSERVER_InferenceRequestAddInput(
triton_object_, name.c_str(), data_type, shape.data(), shape.size()));
}
void AddRawInput(const std::string& name)
{
ThrowIfError(
TRITONSERVER_InferenceRequestAddRawInput(triton_object_, name.c_str()));
}
void RemoveInput(const std::string& name)
{
ThrowIfError(
TRITONSERVER_InferenceRequestRemoveInput(triton_object_, name.c_str()));
}
void RemoveAllInputs()
{
ThrowIfError(TRITONSERVER_InferenceRequestRemoveAllInputs(triton_object_));
}
void AppendInputData(
const std::string& name, uintptr_t base, size_t byte_size,
TRITONSERVER_MemoryType memory_type, int64_t memory_type_id)
{
ThrowIfError(TRITONSERVER_InferenceRequestAppendInputData(
triton_object_, name.c_str(), reinterpret_cast<const char*>(base),
byte_size, memory_type, memory_type_id));
}
void AppendInputDataWithHostPolicy(
const std::string name, uintptr_t base, size_t byte_size,
TRITONSERVER_MemoryType memory_type, int64_t memory_type_id,
const std::string& host_policy_name)
{
ThrowIfError(TRITONSERVER_InferenceRequestAppendInputDataWithHostPolicy(
triton_object_, name.c_str(), reinterpret_cast<const char*>(base),
byte_size, memory_type, memory_type_id, host_policy_name.c_str()));
}
void AppendInputDataWithBufferAttributes(
const std::string& name, uintptr_t base,
PyBufferAttributes* buffer_attributes)
{
ThrowIfError(
TRITONSERVER_InferenceRequestAppendInputDataWithBufferAttributes(
triton_object_, name.c_str(), reinterpret_cast<const char*>(base),
buffer_attributes->Ptr()));
}
void RemoveAllInputData(const std::string& name)
{
ThrowIfError(TRITONSERVER_InferenceRequestRemoveAllInputData(
triton_object_, name.c_str()));
}
void AddRequestedOutput(const std::string& name)
{
ThrowIfError(TRITONSERVER_InferenceRequestAddRequestedOutput(
triton_object_, name.c_str()));
}
void RemoveRequestedOutput(const std::string& name)
{
ThrowIfError(TRITONSERVER_InferenceRequestRemoveRequestedOutput(
triton_object_, name.c_str()));
}
void RemoveAllRequestedOutputs()
{
ThrowIfError(
TRITONSERVER_InferenceRequestRemoveAllRequestedOutputs(triton_object_));
}
void SetStringParameter(const std::string& key, const std::string& value)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetStringParameter(
triton_object_, key.c_str(), value.c_str()));
}
void SetIntParameter(const std::string& key, int64_t value)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetIntParameter(
triton_object_, key.c_str(), value));
}
void SetBoolParameter(const std::string& key, bool value)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetBoolParameter(
triton_object_, key.c_str(), value));
}
void SetDoubleParameter(const std::string& key, double value)
{
ThrowIfError(TRITONSERVER_InferenceRequestSetDoubleParameter(
triton_object_, key.c_str(), value));
}
void Cancel()
{
ThrowIfError(TRITONSERVER_InferenceRequestCancel(triton_object_));
}
public:
std::unique_ptr<CallbackResource> request_callback_resource_{nullptr};
private:
std::unique_ptr<PyResponseAllocator::CallbackResource>
allocator_callback_resource_{nullptr};
std::unique_ptr<PyInferenceResponse::CallbackResource>
response_callback_resource_{nullptr};
};
class PyServerOptions : public PyWrapper<struct TRITONSERVER_ServerOptions> {
public:
DESTRUCTOR_WITH_LOG(PyServerOptions, TRITONSERVER_ServerOptionsDelete);
PyServerOptions()
{
ThrowIfError(TRITONSERVER_ServerOptionsNew(&triton_object_));
owned_ = true;
}
void SetServerId(const std::string& server_id)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetServerId(
triton_object_, server_id.c_str()));
}
void SetModelRepositoryPath(const std::string& model_repository_path)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetModelRepositoryPath(
triton_object_, model_repository_path.c_str()));
}
void SetModelControlMode(TRITONSERVER_ModelControlMode mode)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetModelControlMode(triton_object_, mode));
}
void SetStartupModel(const std::string& model_name)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetStartupModel(
triton_object_, model_name.c_str()));
}
void SetStrictModelConfig(bool strict)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetStrictModelConfig(triton_object_, strict));
}
void SetRateLimiterMode(TRITONSERVER_RateLimitMode mode)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetRateLimiterMode(triton_object_, mode));
}
void AddRateLimiterResource(
const std::string& resource_name, size_t resource_count, int device)
{
ThrowIfError(TRITONSERVER_ServerOptionsAddRateLimiterResource(
triton_object_, resource_name.c_str(), resource_count, device));
}
void SetPinnedMemoryPoolByteSize(uint64_t size)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetPinnedMemoryPoolByteSize(
triton_object_, size));
}
void SetCudaMemoryPoolByteSize(int gpu_device, uint64_t size)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetCudaMemoryPoolByteSize(
triton_object_, gpu_device, size));
}
void SetResponseCacheByteSize(uint64_t size)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetResponseCacheByteSize(
triton_object_, size));
}
void SetCacheConfig(
const std::string& cache_name, const std::string& config_json)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetCacheConfig(
triton_object_, cache_name.c_str(), config_json.c_str()));
}
void SetCacheDirectory(const std::string& cache_dir)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetCacheDirectory(
triton_object_, cache_dir.c_str()));
}
void SetMinSupportedComputeCapability(double cc)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetMinSupportedComputeCapability(
triton_object_, cc));
}
void SetExitOnError(bool exit)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetExitOnError(triton_object_, exit));
}
void SetStrictReadiness(bool strict)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetStrictReadiness(triton_object_, strict));
}
void SetExitTimeout(unsigned int timeout)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetExitTimeout(triton_object_, timeout));
}
void SetBufferManagerThreadCount(unsigned int thread_count)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetBufferManagerThreadCount(
triton_object_, thread_count));
}
void SetModelLoadThreadCount(unsigned int thread_count)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetModelLoadThreadCount(
triton_object_, thread_count));
}
void SetModelLoadRetryCount(unsigned int retry_count)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetModelLoadRetryCount(
triton_object_, retry_count));
}
void SetModelNamespacing(bool enable_namespace)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetModelNamespacing(
triton_object_, enable_namespace));
}
void SetEnablePeerAccess(bool enable_peer_access)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetEnablePeerAccess(
triton_object_, enable_peer_access));
}
void SetLogFile(const std::string& file)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetLogFile(triton_object_, file.c_str()));
}
void SetLogInfo(bool log)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetLogInfo(triton_object_, log));
}
void SetLogWarn(bool log)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetLogWarn(triton_object_, log));
}
void SetLogError(bool log)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetLogError(triton_object_, log));
}
void SetLogFormat(TRITONSERVER_LogFormat format)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetLogFormat(triton_object_, format));
}
void SetLogVerbose(int level)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetLogVerbose(triton_object_, level));
}
void SetMetrics(bool metrics)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetMetrics(triton_object_, metrics));
}
void SetGpuMetrics(bool gpu_metrics)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetGpuMetrics(triton_object_, gpu_metrics));
}
void SetCpuMetrics(bool cpu_metrics)
{
ThrowIfError(
TRITONSERVER_ServerOptionsSetCpuMetrics(triton_object_, cpu_metrics));
}
void SetMetricsInterval(uint64_t metrics_interval_ms)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetMetricsInterval(
triton_object_, metrics_interval_ms));
}
void SetBackendDirectory(const std::string& backend_dir)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetBackendDirectory(
triton_object_, backend_dir.c_str()));
}
void SetRepoAgentDirectory(const std::string& repoagent_dir)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetRepoAgentDirectory(
triton_object_, repoagent_dir.c_str()));
}
void SetModelLoadDeviceLimit(
TRITONSERVER_InstanceGroupKind kind, int device_id, double fraction)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetModelLoadDeviceLimit(
triton_object_, kind, device_id, fraction));
}
void SetBackendConfig(
const std::string& backend_name, const std::string& setting,
const std::string& value)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetBackendConfig(
triton_object_, backend_name.c_str(), setting.c_str(), value.c_str()));
}
void SetHostPolicy(
const std::string& policy_name, const std::string& setting,
const std::string& value)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetHostPolicy(
triton_object_, policy_name.c_str(), setting.c_str(), value.c_str()));
}
void SetMetricsConfig(
const std::string& name, const std::string& setting,
const std::string& value)
{
ThrowIfError(TRITONSERVER_ServerOptionsSetMetricsConfig(
triton_object_, name.c_str(), setting.c_str(), value.c_str()));
}
};
class PyServer : public PyWrapper<struct TRITONSERVER_Server> {
public:
DESTRUCTOR_WITH_LOG(PyServer, TRITONSERVER_ServerDelete);
PyServer(PyServerOptions& options)
{
ThrowIfError(TRITONSERVER_ServerNew(&triton_object_, options.Ptr()));
owned_ = true;
}
void Stop() const
{
py::gil_scoped_release release;
ThrowIfError(TRITONSERVER_ServerStop(triton_object_));
}
void RegisterModelRepository(
const std::string& repository_path,
const std::vector<std::shared_ptr<PyParameter>>& name_mapping) const
{
std::vector<const struct TRITONSERVER_Parameter*> params;
for (const auto& nm : name_mapping) {
params.emplace_back(nm->Ptr());
}
ThrowIfError(TRITONSERVER_ServerRegisterModelRepository(
triton_object_, repository_path.c_str(), params.data(), params.size()));
}
void UnregisterModelRepository(const std::string& repository_path) const
{
ThrowIfError(TRITONSERVER_ServerUnregisterModelRepository(
triton_object_, repository_path.c_str()));
}
void PollModelRepository() const
{
ThrowIfError(TRITONSERVER_ServerPollModelRepository(triton_object_));
}
bool IsLive() const
{
bool live;
ThrowIfError(TRITONSERVER_ServerIsLive(triton_object_, &live));
return live;
}
bool IsReady() const
{
bool ready;
ThrowIfError(TRITONSERVER_ServerIsReady(triton_object_, &ready));
return ready;
}
bool ModelIsReady(const std::string& model_name, int64_t model_version) const
{
bool ready;
ThrowIfError(TRITONSERVER_ServerModelIsReady(
triton_object_, model_name.c_str(), model_version, &ready));
return ready;
}
std::tuple<uint32_t, uintptr_t> ModelBatchProperties(
const std::string& model_name, int64_t model_version) const
{
uint32_t flags;
void* voidp;
ThrowIfError(TRITONSERVER_ServerModelBatchProperties(
triton_object_, model_name.c_str(), model_version, &flags, &voidp));
return {flags, reinterpret_cast<uintptr_t>(voidp)};
}
std::tuple<uint32_t, uintptr_t> ModelTransactionProperties(
const std::string& model_name, int64_t model_version) const
{
uint32_t txn_flags;
void* voidp;
ThrowIfError(TRITONSERVER_ServerModelTransactionProperties(
triton_object_, model_name.c_str(), model_version, &txn_flags, &voidp));
return {txn_flags, reinterpret_cast<uintptr_t>(voidp)};
}
std::shared_ptr<PyMessage> Metadata() const
{
struct TRITONSERVER_Message* server_metadata;
ThrowIfError(TRITONSERVER_ServerMetadata(triton_object_, &server_metadata));
return std::make_shared<PyMessage>(server_metadata, true );
}
std::shared_ptr<PyMessage> ModelMetadata(
const std::string& model_name, int64_t model_version) const
{
struct TRITONSERVER_Message* model_metadata;
ThrowIfError(TRITONSERVER_ServerModelMetadata(
triton_object_, model_name.c_str(), model_version, &model_metadata));
return std::make_shared<PyMessage>(model_metadata, true );
}
std::shared_ptr<PyMessage> ModelStatistics(
const std::string& model_name, int64_t model_version) const
{
struct TRITONSERVER_Message* model_stats;
ThrowIfError(TRITONSERVER_ServerModelStatistics(
triton_object_, model_name.c_str(), model_version, &model_stats));
return std::make_shared<PyMessage>(model_stats, true );
}
std::shared_ptr<PyMessage> ModelConfig(
const std::string& model_name, int64_t model_version,
uint32_t config_version = 1) const
{
struct TRITONSERVER_Message* model_config;
ThrowIfError(TRITONSERVER_ServerModelConfig(
triton_object_, model_name.c_str(), model_version, config_version,
&model_config));
return std::make_shared<PyMessage>(model_config, true );
}
std::shared_ptr<PyMessage> ModelIndex(uint32_t flags) const
{
struct TRITONSERVER_Message* model_index;
ThrowIfError(
TRITONSERVER_ServerModelIndex(triton_object_, flags, &model_index));
return std::make_shared<PyMessage>(model_index, true );
}
void LoadModel(const std::string& model_name)
{
py::gil_scoped_release release;
ThrowIfError(
TRITONSERVER_ServerLoadModel(triton_object_, model_name.c_str()));
}
void LoadModelWithParameters(
const std::string& model_name,
const std::vector<std::shared_ptr<PyParameter>>& parameters) const
{
std::vector<const struct TRITONSERVER_Parameter*> params;
for (const auto& p : parameters) {
params.emplace_back(p->Ptr());
}
py::gil_scoped_release release;
ThrowIfError(TRITONSERVER_ServerLoadModelWithParameters(
triton_object_, model_name.c_str(), params.data(), params.size()));
}
void UnloadModel(const std::string& model_name)
{
ThrowIfError(
TRITONSERVER_ServerUnloadModel(triton_object_, model_name.c_str()));
}
void UnloadModelAndDependents(const std::string& model_name)
{
ThrowIfError(TRITONSERVER_ServerUnloadModelAndDependents(
triton_object_, model_name.c_str()));
}
std::shared_ptr<PyMetrics> Metrics() const
{
struct TRITONSERVER_Metrics* metrics;
ThrowIfError(TRITONSERVER_ServerMetrics(triton_object_, &metrics));
return std::make_shared<PyMetrics>(metrics, true );
}
void InferAsync(
const std::shared_ptr<PyInferenceRequest>& request, PyTrace& trace)
{
static auto resource_handler =
[](PyInferenceRequest::CallbackResource* cr) {
if (cr != nullptr) {
cr->request->request_callback_resource_.reset(cr);
cr->request.reset();
}
};
std::unique_ptr<
PyInferenceRequest::CallbackResource, decltype(resource_handler)>
scoped_rh(
request->request_callback_resource_.release(), resource_handler);
scoped_rh->request = request;
ThrowIfError(TRITONSERVER_ServerInferAsync(
triton_object_, request->Ptr(), trace.Ptr()));
scoped_rh.release();
request->Release();
trace.Release();
}
void InferAsync(const std::shared_ptr<PyInferenceRequest>& request)
{
static auto resource_handler =
[](PyInferenceRequest::CallbackResource* cr) {
if (cr != nullptr) {
cr->request->request_callback_resource_.reset(cr);
cr->request.reset();
}
};
std::unique_ptr<
PyInferenceRequest::CallbackResource, decltype(resource_handler)>
scoped_rh(
request->request_callback_resource_.release(), resource_handler);
scoped_rh->request = request;
ThrowIfError(
TRITONSERVER_ServerInferAsync(triton_object_, request->Ptr(), nullptr));
scoped_rh.release();
request->Release();
}
};
class PyMetricFamily : public PyWrapper<struct TRITONSERVER_MetricFamily> {
public:
DESTRUCTOR_WITH_LOG(PyMetricFamily, TRITONSERVER_MetricFamilyDelete);
PyMetricFamily(
TRITONSERVER_MetricKind kind, const std::string& name,
const std::string& description)
{
TRITONSERVER_MetricFamilyNew(
&triton_object_, kind, name.c_str(), description.c_str());
owned_ = true;
}
};
class PyMetric : public PyWrapper<struct TRITONSERVER_Metric> {
public:
DESTRUCTOR_WITH_LOG(PyMetric, TRITONSERVER_MetricDelete);
PyMetric(
PyMetricFamily& family,
const std::vector<std::shared_ptr<PyParameter>>& labels)
{
std::vector<const struct TRITONSERVER_Parameter*> params;
for (const auto& label : labels) {
params.emplace_back(label->Ptr());
}
ThrowIfError(TRITONSERVER_MetricNew(
&triton_object_, family.Ptr(), params.data(), params.size()));
owned_ = true;
}
double Value() const
{
double val = 0;
ThrowIfError(TRITONSERVER_MetricValue(triton_object_, &val));
return val;
}
void Increment(double val) const
{
ThrowIfError(TRITONSERVER_MetricIncrement(triton_object_, val));
}
void SetValue(double val) const
{
ThrowIfError(TRITONSERVER_MetricSet(triton_object_, val));
}
TRITONSERVER_MetricKind Kind() const
{
TRITONSERVER_MetricKind val = TRITONSERVER_METRIC_KIND_COUNTER;
ThrowIfError(TRITONSERVER_GetMetricKind(triton_object_, &val));
return val;
}
};
PyInferenceRequest::PyInferenceRequest(
PyServer& server, const std::string& model_name,
const int64_t model_version)
{
ThrowIfError(TRITONSERVER_InferenceRequestNew(
&triton_object_, server.Ptr(), model_name.c_str(), model_version));
owned_ = true;
}
PYBIND11_MODULE(triton_bindings, m)
{
m.doc() = "Python bindings for Triton Inference Server";
m.def("api_version", []() {
uint32_t major = 0, minor = 0;
ThrowIfError(TRITONSERVER_ApiVersion(&major, &minor));
return py::make_tuple(major, minor);
});
auto te = pybind11::register_exception<TritonError>(m, "TritonError");
pybind11::register_exception<UnknownError>(m, "UnknownError", te.ptr());
pybind11::register_exception<InternalError>(m, "InternalError", te.ptr());
pybind11::register_exception<NotFoundError>(m, "NotFoundError", te.ptr());
pybind11::register_exception<InvalidArgumentError>(
m, "InvalidArgumentError", te.ptr());
pybind11::register_exception<UnavailableError>(
m, "UnavailableError", te.ptr());
pybind11::register_exception<UnsupportedError>(
m, "UnsupportedError", te.ptr());
pybind11::register_exception<AlreadyExistsError>(
m, "AlreadyExistsError", te.ptr());
py::enum_<TRITONSERVER_DataType>(m, "TRITONSERVER_DataType")
.value("INVALID", TRITONSERVER_TYPE_INVALID)
.value("BOOL", TRITONSERVER_TYPE_BOOL)
.value("UINT8", TRITONSERVER_TYPE_UINT8)
.value("UINT16", TRITONSERVER_TYPE_UINT16)
.value("UINT32", TRITONSERVER_TYPE_UINT32)
.value("UINT64", TRITONSERVER_TYPE_UINT64)
.value("INT8", TRITONSERVER_TYPE_INT8)
.value("INT16", TRITONSERVER_TYPE_INT16)
.value("INT32", TRITONSERVER_TYPE_INT32)
.value("INT64", TRITONSERVER_TYPE_INT64)
.value("FP16", TRITONSERVER_TYPE_FP16)
.value("FP32", TRITONSERVER_TYPE_FP32)
.value("FP64", TRITONSERVER_TYPE_FP64)
.value("BYTES", TRITONSERVER_TYPE_BYTES)
.value("BF16", TRITONSERVER_TYPE_BF16);
m.def("TRITONSERVER_DataTypeString", [](TRITONSERVER_DataType datatype) {
return TRITONSERVER_DataTypeString(datatype);
});
m.def("TRITONSERVER_StringToDataType", [](const char* dtype) {
return TRITONSERVER_StringToDataType(dtype);
});
m.def("TRITONSERVER_DataTypeByteSize", [](TRITONSERVER_DataType datatype) {
return TRITONSERVER_DataTypeByteSize(datatype);
});
py::enum_<TRITONSERVER_MemoryType>(m, "TRITONSERVER_MemoryType")
.value("CPU", TRITONSERVER_MEMORY_CPU)
.value("CPU_PINNED", TRITONSERVER_MEMORY_CPU_PINNED)
.value("GPU", TRITONSERVER_MEMORY_GPU);
m.def("TRITONSERVER_MemoryTypeString", [](TRITONSERVER_MemoryType memtype) {
return TRITONSERVER_MemoryTypeString(memtype);
});
py::enum_<TRITONSERVER_ParameterType>(m, "TRITONSERVER_ParameterType")
.value("STRING", TRITONSERVER_PARAMETER_STRING)
.value("INT", TRITONSERVER_PARAMETER_INT)
.value("DOUBLE", TRITONSERVER_PARAMETER_DOUBLE)
.value("BOOL", TRITONSERVER_PARAMETER_BOOL)
.value("BYTES", TRITONSERVER_PARAMETER_BYTES);
m.def(
"TRITONSERVER_ParameterTypeString",
[](TRITONSERVER_ParameterType paramtype) {
return TRITONSERVER_ParameterTypeString(paramtype);
});
py::class_<PyParameter, std::shared_ptr<PyParameter>>(
m, "TRITONSERVER_Parameter")
.def(py::init([](const char* name, py::bytes bytes) {
py::buffer_info info(py::buffer(bytes).request());
return std::make_unique<PyParameter>(name, info.ptr, info.size);
}))
.def(py::init<const char*, const std::string&>())
.def(py::init<const char*, int64_t>())
.def(py::init<const char*, bool>());
py::enum_<TRITONSERVER_InstanceGroupKind>(m, "TRITONSERVER_InstanceGroupKind")
.value("AUTO", TRITONSERVER_INSTANCEGROUPKIND_AUTO)
.value("CPU", TRITONSERVER_INSTANCEGROUPKIND_CPU)
.value("GPU", TRITONSERVER_INSTANCEGROUPKIND_GPU)
.value("MODEL", TRITONSERVER_INSTANCEGROUPKIND_MODEL);
m.def(
"TRITONSERVER_InstanceGroupKindString",
[](TRITONSERVER_InstanceGroupKind kind) {
return TRITONSERVER_InstanceGroupKindString(kind);
});
py::enum_<TRITONSERVER_LogLevel>(m, "TRITONSERVER_LogLevel")
.value("INFO", TRITONSERVER_LOG_INFO)
.value("WARN", TRITONSERVER_LOG_WARN)
.value("ERROR", TRITONSERVER_LOG_ERROR)
.value("VERBOSE", TRITONSERVER_LOG_VERBOSE);
py::enum_<TRITONSERVER_LogFormat>(m, "TRITONSERVER_LogFormat")
.value("DEFAULT", TRITONSERVER_LOG_DEFAULT)
.value("ISO8601", TRITONSERVER_LOG_ISO8601);
m.def("TRITONSERVER_LogIsEnabled", [](TRITONSERVER_LogLevel level) {
return TRITONSERVER_LogIsEnabled(level);
});
m.def(
"TRITONSERVER_LogMessage",
[](TRITONSERVER_LogLevel level, const char* filename, const int line,
const char* msg) {
ThrowIfError(TRITONSERVER_LogMessage(level, filename, line, msg));
});
py::class_<PyBufferAttributes>(m, "TRITONSERVER_BufferAttributes")
.def(py::init<>())
.def_property(
"memory_type_id", &PyBufferAttributes::MemoryTypeId,
&PyBufferAttributes::SetMemoryTypeId)
.def_property(
"memory_type", &PyBufferAttributes::MemoryType,
&PyBufferAttributes::SetMemoryType)
.def_property(
"cuda_ipc_handle", &PyBufferAttributes::CudaIpcHandle,
&PyBufferAttributes::SetCudaIpcHandle)
.def_property(
"byte_size", &PyBufferAttributes::ByteSize,
&PyBufferAttributes::SetByteSize);
py::class_<PyResponseAllocator>(m, "TRITONSERVER_ResponseAllocator")
.def(
py::init<
PyResponseAllocator::AllocFn, PyResponseAllocator::ReleaseFn,
PyResponseAllocator::StartFn>(),
py::arg("alloc_function"), py::arg("release_function"),
py::arg("start_function"))
.def(
py::init<
PyResponseAllocator::AllocFn, PyResponseAllocator::ReleaseFn>(),
py::arg("alloc_function"), py::arg("release_function"))
.def(
"set_buffer_attributes_function",
&PyResponseAllocator::SetBufferAttributesFunction,
py::arg("buffer_attributes_function"))
.def(
"set_query_function", &PyResponseAllocator::SetQueryFunction,
py::arg("query_function"));
py::class_<PyMessage, std::shared_ptr<PyMessage>>(m, "TRITONSERVER_Message")
.def(py::init<const std::string&>())
.def("serialize_to_json", &PyMessage::SerializeToJson);
py::enum_<TRITONSERVER_MetricFormat>(m, "TRITONSERVER_MetricFormat")
.value("PROMETHEUS", TRITONSERVER_METRIC_PROMETHEUS);
py::class_<PyMetrics, std::shared_ptr<PyMetrics>>(m, "TRITONSERVER_Metrics")
.def("formatted", &PyMetrics::Formatted);
py::enum_<TRITONSERVER_InferenceTraceLevel>(
m, "TRITONSERVER_InferenceTraceLevel")
.value("DISABLED", TRITONSERVER_TRACE_LEVEL_DISABLED)
.value("MIN", TRITONSERVER_TRACE_LEVEL_MIN)
.value("MAX", TRITONSERVER_TRACE_LEVEL_MAX)
.value("TIMESTAMPS", TRITONSERVER_TRACE_LEVEL_TIMESTAMPS)
.value("TENSORS", TRITONSERVER_TRACE_LEVEL_TENSORS)
.export_values();
m.def(
"TRITONSERVER_InferenceTraceLevelString",
&TRITONSERVER_InferenceTraceLevelString);
py::enum_<TRITONSERVER_InferenceTraceActivity>(
m, "TRITONSERVER_InferenceTraceActivity")
.value("REQUEST_START", TRITONSERVER_TRACE_REQUEST_START)
.value("QUEUE_START", TRITONSERVER_TRACE_QUEUE_START)
.value("COMPUTE_START", TRITONSERVER_TRACE_COMPUTE_START)
.value("COMPUTE_INPUT_END", TRITONSERVER_TRACE_COMPUTE_INPUT_END)
.value("COMPUTE_OUTPUT_START", TRITONSERVER_TRACE_COMPUTE_OUTPUT_START)
.value("COMPUTE_END", TRITONSERVER_TRACE_COMPUTE_END)
.value("REQUEST_END", TRITONSERVER_TRACE_REQUEST_END)
.value("TENSOR_QUEUE_INPUT", TRITONSERVER_TRACE_TENSOR_QUEUE_INPUT)
.value("TENSOR_BACKEND_INPUT", TRITONSERVER_TRACE_TENSOR_BACKEND_INPUT)
.value("TENSOR_BACKEND_OUTPUT", TRITONSERVER_TRACE_TENSOR_BACKEND_OUTPUT)
.export_values();
m.def(
"TRITONSERVER_InferenceTraceActivityString",
&TRITONSERVER_InferenceTraceActivityString);
py::class_<PyTrace, std::shared_ptr<PyTrace>>(
m, "TRITONSERVER_InferenceTrace")
.def(
py::init<
int, uint64_t, PyTrace::TimestampActivityFn,
PyTrace::TensorActivityFn, PyTrace::ReleaseFn,
const py::object&>(),
py::arg("level"), py::arg("parent_id"), py::arg("activity_function"),
py::arg("tensor_activity_function"), py::arg("release_function"),
py::arg("trace_userp"))
.def(
py::init<
int, uint64_t, PyTrace::TimestampActivityFn, PyTrace::ReleaseFn,
const py::object&>(),
py::arg("level"), py::arg("parent_id"), py::arg("activity_function"),
py::arg("release_function"), py::arg("trace_userp"))
.def_property_readonly("id", &PyTrace::Id)
.def_property_readonly("parent_id", &PyTrace::ParentId)
.def_property_readonly("model_name", &PyTrace::ModelName)
.def_property_readonly("model_version", &PyTrace::ModelVersion)
.def_property_readonly("request_id", &PyTrace::RequestId);
py::enum_<TRITONSERVER_RequestFlag>(m, "TRITONSERVER_RequestFlag")
.value("SEQUENCE_START", TRITONSERVER_REQUEST_FLAG_SEQUENCE_START)
.value("SEQUENCE_END", TRITONSERVER_REQUEST_FLAG_SEQUENCE_END)
.export_values();
py::enum_<TRITONSERVER_RequestReleaseFlag>(
m, "TRITONSERVER_RequestReleaseFlag")
.value("ALL", TRITONSERVER_REQUEST_RELEASE_ALL)
.export_values();
py::class_<PyInferenceRequest, std::shared_ptr<PyInferenceRequest>>(
m, "TRITONSERVER_InferenceRequest")
.def(
py::init<PyServer&, const std::string&, int64_t>(),
py::keep_alive<1, 2>())
.def("set_release_callback", &PyInferenceRequest::SetReleaseCallback)
.def("set_response_callback", &PyInferenceRequest::SetResponseCallback)
.def_property("id", &PyInferenceRequest::Id, &PyInferenceRequest::SetId)
.def_property(
"flags", &PyInferenceRequest::Flags, &PyInferenceRequest::SetFlags)
.def_property(
"correlation_id", &PyInferenceRequest::CorrelationId,
&PyInferenceRequest::SetCorrelationId)
.def_property(
"correlation_id_string", &PyInferenceRequest::CorrelationIdString,
&PyInferenceRequest::SetCorrelationIdString)
.def_property(
"priority", &PyInferenceRequest::Priority,
&PyInferenceRequest::SetPriority)
.def_property(
"priority_uint64", &PyInferenceRequest::PriorityUint64,
&PyInferenceRequest::SetPriorityUint64)
.def_property(
"timeout_microseconds", &PyInferenceRequest::TimeoutMicroseconds,
&PyInferenceRequest::SetTimeoutMicroseconds)
.def("add_input", &PyInferenceRequest::AddInput)
.def("add_raw_input", &PyInferenceRequest::AddRawInput)
.def("remove_input", &PyInferenceRequest::RemoveInput)
.def("remove_all_inputs", &PyInferenceRequest::RemoveAllInputs)
.def("append_input_data", &PyInferenceRequest::AppendInputData)
.def(
"append_input_data_with_host_policy",
&PyInferenceRequest::AppendInputDataWithHostPolicy)
.def(
"append_input_data_with_buffer_attributes",
&PyInferenceRequest::AppendInputDataWithBufferAttributes)
.def("remove_all_input_data", &PyInferenceRequest::RemoveAllInputData)
.def("add_requested_output", &PyInferenceRequest::AddRequestedOutput)
.def(
"remove_requested_output", &PyInferenceRequest::RemoveRequestedOutput)
.def(
"remove_all_requested_outputs",
&PyInferenceRequest::RemoveAllRequestedOutputs)
.def("set_string_parameter", &PyInferenceRequest::SetStringParameter)
.def("set_int_parameter", &PyInferenceRequest::SetIntParameter)
.def("set_bool_parameter", &PyInferenceRequest::SetBoolParameter)
.def("set_double_parameter", &PyInferenceRequest::SetDoubleParameter)
.def("cancel", &PyInferenceRequest::Cancel);
py::enum_<TRITONSERVER_ResponseCompleteFlag>(
m, "TRITONSERVER_ResponseCompleteFlag")
.value("FINAL", TRITONSERVER_RESPONSE_COMPLETE_FINAL)
.export_values();
py::class_<PyInferenceResponse, std::shared_ptr<PyInferenceResponse>>(
m, "TRITONSERVER_InferenceResponse")
.def(
"throw_if_response_error", &PyInferenceResponse::ThrowIfResponseError)
.def_property_readonly("model", &PyInferenceResponse::Model)
.def_property_readonly("id", &PyInferenceResponse::Id)
.def_property_readonly(
"parameter_count", &PyInferenceResponse::ParameterCount)
.def("parameter", &PyInferenceResponse::Parameter)
.def_property_readonly("output_count", &PyInferenceResponse::OutputCount)
.def("output", &PyInferenceResponse::Output)
.def(
"output_classification_label",
&PyInferenceResponse::OutputClassificationLabel);
py::enum_<TRITONSERVER_ModelControlMode>(m, "TRITONSERVER_ModelControlMode")
.value("NONE", TRITONSERVER_MODEL_CONTROL_NONE)
.value("POLL", TRITONSERVER_MODEL_CONTROL_POLL)
.value("EXPLICIT", TRITONSERVER_MODEL_CONTROL_EXPLICIT);
py::enum_<TRITONSERVER_RateLimitMode>(m, "TRITONSERVER_RateLimitMode")
.value("OFF", TRITONSERVER_RATE_LIMIT_OFF)
.value("EXEC_COUNT", TRITONSERVER_RATE_LIMIT_EXEC_COUNT);
py::class_<PyServerOptions>(m, "TRITONSERVER_ServerOptions")
.def(py::init<>())
.def("set_server_id", &PyServerOptions::SetServerId)
.def(
"set_model_repository_path", &PyServerOptions::SetModelRepositoryPath)
.def("set_model_control_mode", &PyServerOptions::SetModelControlMode)
.def("set_startup_model", &PyServerOptions::SetStartupModel)
.def("set_strict_model_config", &PyServerOptions::SetStrictModelConfig)
.def("set_rate_limiter_mode", &PyServerOptions::SetRateLimiterMode)
.def(
"add_rate_limiter_resource", &PyServerOptions::AddRateLimiterResource)
.def(
"set_pinned_memory_pool_byte_size",
&PyServerOptions::SetPinnedMemoryPoolByteSize)
.def(
"set_cuda_memory_pool_byte_size",
&PyServerOptions::SetCudaMemoryPoolByteSize)
.def(
"set_response_cache_byte_size",
&PyServerOptions::SetResponseCacheByteSize)
.def("set_cache_config", &PyServerOptions::SetCacheConfig)
.def("set_cache_directory", &PyServerOptions::SetCacheDirectory)
.def(
"set_min_supported_compute_capability",
&PyServerOptions::SetMinSupportedComputeCapability)
.def("set_exit_on_error", &PyServerOptions::SetExitOnError)
.def("set_strict_readiness", &PyServerOptions::SetStrictReadiness)
.def("set_exit_timeout", &PyServerOptions::SetExitTimeout)
.def(
"set_buffer_manager_thread_count",
&PyServerOptions::SetBufferManagerThreadCount)
.def(
"set_model_load_thread_count",
&PyServerOptions::SetModelLoadThreadCount)
.def(
"set_model_load_retry_count",
&PyServerOptions::SetModelLoadRetryCount)
.def("set_model_namespacing", &PyServerOptions::SetModelNamespacing)
.def("set_enable_peer_access", &PyServerOptions::SetEnablePeerAccess)
.def("set_log_file", &PyServerOptions::SetLogFile)
.def("set_log_info", &PyServerOptions::SetLogInfo)
.def("set_log_warn", &PyServerOptions::SetLogWarn)
.def("set_log_error", &PyServerOptions::SetLogError)
.def("set_log_format", &PyServerOptions::SetLogFormat)
.def("set_log_verbose", &PyServerOptions::SetLogVerbose)
.def("set_metrics", &PyServerOptions::SetMetrics)
.def("set_gpu_metrics", &PyServerOptions::SetGpuMetrics)
.def("set_cpu_metrics", &PyServerOptions::SetCpuMetrics)
.def("set_metrics_interval", &PyServerOptions::SetMetricsInterval)
.def("set_backend_directory", &PyServerOptions::SetBackendDirectory)
.def("set_repo_agent_directory", &PyServerOptions::SetRepoAgentDirectory)
.def(
"set_model_load_device_limit",
&PyServerOptions::SetModelLoadDeviceLimit)
.def("set_backend_config", &PyServerOptions::SetBackendConfig)
.def("set_host_policy", &PyServerOptions::SetHostPolicy)
.def("set_metrics_config", &PyServerOptions::SetMetricsConfig);
py::enum_<TRITONSERVER_ModelBatchFlag>(m, "TRITONSERVER_ModelBatchFlag")
.value("UNKNOWN", TRITONSERVER_BATCH_UNKNOWN)
.value("FIRST_DIM", TRITONSERVER_BATCH_FIRST_DIM)
.export_values();
py::enum_<TRITONSERVER_ModelIndexFlag>(m, "TRITONSERVER_ModelIndexFlag")
.value("READY", TRITONSERVER_INDEX_FLAG_READY)
.export_values();
py::enum_<TRITONSERVER_ModelTxnPropertyFlag>(
m, "TRITONSERVER_ModelTxnPropertyFlag")
.value("ONE_TO_ONE", TRITONSERVER_TXN_ONE_TO_ONE)
.value("DECOUPLED", TRITONSERVER_TXN_DECOUPLED)
.export_values();
py::class_<PyServer>(m, "TRITONSERVER_Server")
.def(py::init<PyServerOptions&>())
.def("stop", &PyServer::Stop)
.def("register_model_repository", &PyServer::RegisterModelRepository)
.def("unregister_model_repository", &PyServer::UnregisterModelRepository)
.def("poll_model_repository", &PyServer::PollModelRepository)
.def("is_live", &PyServer::IsLive)
.def("is_ready", &PyServer::IsReady)
.def("model_is_ready", &PyServer::ModelIsReady)
.def("model_batch_properties", &PyServer::ModelBatchProperties)
.def(
"model_transaction_properties", &PyServer::ModelTransactionProperties)
.def("metadata", &PyServer::Metadata)
.def("model_metadata", &PyServer::ModelMetadata)
.def("model_statistics", &PyServer::ModelStatistics)
.def("model_config", &PyServer::ModelConfig)
.def("model_index", &PyServer::ModelIndex)
.def("load_model", &PyServer::LoadModel)
.def("load_model_with_parameters", &PyServer::LoadModelWithParameters)
.def("unload_model", &PyServer::UnloadModel)
.def("unload_model_and_dependents", &PyServer::UnloadModelAndDependents)
.def("metrics", &PyServer::Metrics)
.def(
"infer_async",
py::overload_cast<
const std::shared_ptr<PyInferenceRequest>&, PyTrace&>(
&PyServer::InferAsync))
.def(
"infer_async",
py::overload_cast<const std::shared_ptr<PyInferenceRequest>&>(
&PyServer::InferAsync));
py::enum_<TRITONSERVER_MetricKind>(m, "TRITONSERVER_MetricKind")
.value("COUNTER", TRITONSERVER_METRIC_KIND_COUNTER)
.value("GAUGE", TRITONSERVER_METRIC_KIND_GAUGE);
py::class_<PyMetricFamily>(m, "TRITONSERVER_MetricFamily")
.def(py::init<
TRITONSERVER_MetricKind, const std::string&, const std::string&>());
py::class_<PyMetric>(m, "TRITONSERVER_Metric")
.def(
py::init<
PyMetricFamily&,
const std::vector<std::shared_ptr<PyParameter>>&>(),
py::keep_alive<1, 2>())
.def_property_readonly("value", &PyMetric::Value)
.def("increment", &PyMetric::Increment)
.def("set_value", &PyMetric::SetValue)
.def_property_readonly("kind", &PyMetric::Kind);
}
}}}