1
- // Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1
+ // Copyright 2023-2024 , NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
2
//
3
3
// Redistribution and use in source and binary forms, with or without
4
4
// modification, are permitted provided that the following conditions
32
32
33
33
namespace triton { namespace backend { namespace python {
34
34
35
- Metric::Metric (const std::string& labels, void * metric_family_address)
36
- : labels_(labels), operation_value_(0 ), metric_address_(nullptr ),
37
- metric_family_address_ (metric_family_address), is_cleared_(false )
35
+ Metric::Metric (
36
+ const std::string& labels, std::optional<const std::vector<double >> buckets,
37
+ void * metric_family_address)
38
+ : labels_(labels), buckets_(buckets), operation_value_(0 ),
39
+ metric_address_ (nullptr ), metric_family_address_(metric_family_address),
40
+ is_cleared_(false )
38
41
{
39
42
#ifdef TRITON_PB_STUB
40
43
SendCreateMetricRequest ();
@@ -62,6 +65,20 @@ Metric::SaveToSharedMemory(std::unique_ptr<SharedMemoryManager>& shm_pool)
62
65
custom_metric_shm_ptr_->metric_family_address = metric_family_address_;
63
66
custom_metric_shm_ptr_->metric_address = metric_address_;
64
67
68
+ // Histogram specific case
69
+ if (buckets_.has_value ()) {
70
+ auto buckets_size = buckets_.value ().size () * sizeof (double );
71
+ std::unique_ptr<PbMemory> buckets_shm = PbMemory::Create (
72
+ shm_pool, TRITONSERVER_MemoryType::TRITONSERVER_MEMORY_CPU, 0 ,
73
+ buckets_size, reinterpret_cast <char *>(buckets_.value ().data ()),
74
+ false /* copy_gpu */ );
75
+ custom_metric_shm_ptr_->buckets_shm_handle = buckets_shm->ShmHandle ();
76
+ buckets_shm_ = std::move (buckets_shm);
77
+ } else {
78
+ custom_metric_shm_ptr_->buckets_shm_handle = 0 ;
79
+ buckets_shm_ = nullptr ;
80
+ }
81
+
65
82
// Save the references to shared memory.
66
83
custom_metric_shm_ = std::move (custom_metric_shm);
67
84
labels_shm_ = std::move (labels_shm);
@@ -80,17 +97,40 @@ Metric::LoadFromSharedMemory(
80
97
std::unique_ptr<PbString> labels_shm = PbString::LoadFromSharedMemory (
81
98
shm_pool, custom_metric_shm_ptr->labels_shm_handle );
82
99
83
- return std::unique_ptr<Metric>(new Metric (custom_metric_shm, labels_shm));
100
+ std::unique_ptr<PbMemory> buckets_shm = nullptr ;
101
+ if (custom_metric_shm_ptr->buckets_shm_handle != 0 ) {
102
+ buckets_shm = PbMemory::LoadFromSharedMemory (
103
+ shm_pool, custom_metric_shm_ptr->buckets_shm_handle ,
104
+ false /* open_cuda_handle */ );
105
+ }
106
+
107
+ return std::unique_ptr<Metric>(
108
+ new Metric (custom_metric_shm, labels_shm, buckets_shm));
84
109
}
85
110
86
111
Metric::Metric (
87
112
AllocatedSharedMemory<MetricShm>& custom_metric_shm,
88
- std::unique_ptr<PbString>& labels_shm)
113
+ std::unique_ptr<PbString>& labels_shm,
114
+ std::unique_ptr<PbMemory>& buckets_shm)
89
115
: custom_metric_shm_(std::move(custom_metric_shm)),
90
- labels_shm_ (std::move(labels_shm))
116
+ labels_shm_ (std::move(labels_shm)), buckets_shm_(std::move(buckets_shm))
91
117
{
92
118
custom_metric_shm_ptr_ = custom_metric_shm_.data_ .get ();
119
+
120
+ // FIXME: This constructor is called during each
121
+ // set/increment/observe/get_value call. It only needs the pointers.
93
122
labels_ = labels_shm_->String ();
123
+ if (buckets_shm_ != nullptr ) { // Histogram
124
+ size_t bucket_size = buckets_shm_->ByteSize () / sizeof (double );
125
+ std::vector<double > buckets;
126
+ buckets.reserve (bucket_size);
127
+ for (size_t i = 0 ; i < bucket_size; ++i) {
128
+ buckets.emplace_back (
129
+ reinterpret_cast <double *>(buckets_shm_->DataPtr ())[i]);
130
+ }
131
+ buckets_ = std::move (buckets);
132
+ }
133
+
94
134
operation_value_ = custom_metric_shm_ptr_->operation_value ;
95
135
metric_family_address_ = custom_metric_shm_ptr_->metric_family_address ;
96
136
metric_address_ = custom_metric_shm_ptr_->metric_address ;
@@ -161,6 +201,24 @@ Metric::SendSetValueRequest(const double& value)
161
201
}
162
202
}
163
203
204
+ void
205
+ Metric::SendObserveRequest (const double & value)
206
+ {
207
+ try {
208
+ CheckIfCleared ();
209
+ std::unique_ptr<Stub>& stub = Stub::GetOrCreateInstance ();
210
+ operation_value_ = value;
211
+ SaveToSharedMemory (stub->ShmPool ());
212
+ AllocatedSharedMemory<CustomMetricsMessage> custom_metrics_shm;
213
+ stub->SendMessage <CustomMetricsMessage>(
214
+ custom_metrics_shm, PYTHONSTUB_MetricRequestObserve, shm_handle_);
215
+ }
216
+ catch (const PythonBackendException& pb_exception) {
217
+ throw PythonBackendException (
218
+ " Failed to observe metric value: " + std::string (pb_exception.what ()));
219
+ }
220
+ }
221
+
164
222
double
165
223
Metric::SendGetValueRequest ()
166
224
{
@@ -222,14 +280,35 @@ Metric::InitializeTritonMetric()
222
280
{
223
281
std::vector<const TRITONSERVER_Parameter*> labels_params;
224
282
ParseLabels (labels_params, labels_);
283
+ TRITONSERVER_MetricKind kind;
284
+ THROW_IF_TRITON_ERROR (TRITONSERVER_GetMetricFamilyKind (
285
+ reinterpret_cast <TRITONSERVER_MetricFamily*>(metric_family_address_),
286
+ &kind));
287
+ TRITONSERVER_MetricArgs* args = nullptr ;
288
+ switch (kind) {
289
+ case TRITONSERVER_METRIC_KIND_COUNTER:
290
+ case TRITONSERVER_METRIC_KIND_GAUGE:
291
+ break ;
292
+ case TRITONSERVER_METRIC_KIND_HISTOGRAM: {
293
+ const std::vector<double >& buckets = buckets_.value ();
294
+ THROW_IF_TRITON_ERROR (TRITONSERVER_MetricArgsNew (&args));
295
+ THROW_IF_TRITON_ERROR (TRITONSERVER_MetricArgsSetHistogram (
296
+ args, buckets.data (), buckets.size ()));
297
+ break ;
298
+ }
299
+ default :
300
+ break ;
301
+ }
302
+
225
303
TRITONSERVER_Metric* triton_metric = nullptr ;
226
- THROW_IF_TRITON_ERROR (TRITONSERVER_MetricNew (
304
+ THROW_IF_TRITON_ERROR (TRITONSERVER_MetricNewWithArgs (
227
305
&triton_metric,
228
306
reinterpret_cast <TRITONSERVER_MetricFamily*>(metric_family_address_),
229
- labels_params.data (), labels_params.size ()));
307
+ labels_params.data (), labels_params.size (), args ));
230
308
for (const auto label : labels_params) {
231
309
TRITONSERVER_ParameterDelete (const_cast <TRITONSERVER_Parameter*>(label));
232
310
}
311
+ THROW_IF_TRITON_ERROR (TRITONSERVER_MetricArgsDelete (args));
233
312
return reinterpret_cast <void *>(triton_metric);
234
313
}
235
314
@@ -262,6 +341,8 @@ Metric::HandleMetricOperation(
262
341
Increment (operation_value_);
263
342
} else if (command_type == PYTHONSTUB_MetricRequestSet) {
264
343
SetValue (operation_value_);
344
+ } else if (command_type == PYTHONSTUB_MetricRequestObserve) {
345
+ Observe (operation_value_);
265
346
} else {
266
347
throw PythonBackendException (" Unknown metric operation" );
267
348
}
@@ -281,6 +362,13 @@ Metric::SetValue(const double& value)
281
362
THROW_IF_TRITON_ERROR (TRITONSERVER_MetricSet (triton_metric, value));
282
363
}
283
364
365
+ void
366
+ Metric::Observe (const double & value)
367
+ {
368
+ auto triton_metric = reinterpret_cast <TRITONSERVER_Metric*>(metric_address_);
369
+ THROW_IF_TRITON_ERROR (TRITONSERVER_MetricObserve (triton_metric, value));
370
+ }
371
+
284
372
double
285
373
Metric::GetValue ()
286
374
{
0 commit comments