#ifdef TRITON_ENABLE_METRICS
#include <iostream>
#include <thread>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "metric_family.h"
#include "triton/common/logging.h"
#include "triton/core/tritonserver.h"
namespace tc = triton::core;
namespace {
using ::testing::HasSubstr;
#define FAIL_TEST_IF_ERR(X, MSG) \
do { \
std::shared_ptr<TRITONSERVER_Error> err__((X), TRITONSERVER_ErrorDelete); \
ASSERT_TRUE((err__ == nullptr)) \
<< "error: " << (MSG) << ": " \
<< TRITONSERVER_ErrorCodeString(err__.get()) << " - " \
<< TRITONSERVER_ErrorMessage(err__.get()); \
} while (false)
void
GetMetrics(TRITONSERVER_Server* server, std::string* metrics_str)
{
ASSERT_NE(server, nullptr);
TRITONSERVER_Metrics* metrics = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerMetrics(server, &metrics), "fetch metrics");
const char* base;
size_t byte_size;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricsFormatted(
metrics, TRITONSERVER_METRIC_PROMETHEUS, &base, &byte_size),
"format metrics string");
*metrics_str = std::string(base, byte_size);
TRITONSERVER_MetricsDelete(metrics);
}
int
CountMatches(const std::string s, const std::string substr)
{
int num_matches = 0;
std::string::size_type pos = 0;
while ((pos = s.find(substr, pos)) != std::string::npos) {
num_matches++;
pos += substr.length();
}
return num_matches;
}
int
NumMetricMatches(TRITONSERVER_Server* server, const std::string substr)
{
std::string metrics_str;
GetMetrics(server, &metrics_str);
const int num_matches = CountMatches(metrics_str, substr);
return num_matches;
}
void
DupeMetricHelper(
TRITONSERVER_Server* server,
std::vector<const TRITONSERVER_Parameter*> labels)
{
TRITONSERVER_MetricFamily* family = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "dupe_metric_test";
const char* description = "dupe metric description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family1");
TRITONSERVER_Metric* metric1 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric1, family, labels.data(), labels.size()),
"Creating new metric");
TRITONSERVER_Metric* metric2 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric2, family, labels.data(), labels.size()),
"Creating new metric");
double value1 = -1;
double value2 = -1;
double inc = 7.5;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric1, &value1),
"query metric value after increment");
ASSERT_EQ(value1, 0);
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric2, &value2),
"query metric value after increment");
ASSERT_EQ(value2, 0);
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricIncrement(metric1, inc), "increase metric value");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric1, &value1),
"query metric value after increment");
ASSERT_EQ(value1, inc);
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric2, &value2),
"query metric value after increment");
ASSERT_EQ(value1, value2);
std::cout << "metric1 value: " << value1 << " == metric2 value: " << value2
<< std::endl;
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric1), "delete metric1");
ASSERT_EQ(NumMetricMatches(server, description), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric2), "delete metric2");
ASSERT_EQ(NumMetricMatches(server, description), 0);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family), "delete family");
}
void
MetricAPIHelper(TRITONSERVER_Metric* metric, TRITONSERVER_MetricKind kind)
{
double value = -1;
double prev_value = -1;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric, &value), "query metric initial value");
ASSERT_EQ(value, 0.0);
double increment = 1729.0;
prev_value = value;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricIncrement(metric, increment), "increase metric value");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric, &value),
"query metric value after positive increment");
ASSERT_EQ(value, prev_value + increment);
double decrement = -3.14;
prev_value = value;
auto err = TRITONSERVER_MetricIncrement(metric, decrement);
switch (kind) {
case TRITONSERVER_METRIC_KIND_COUNTER: {
ASSERT_NE(err, nullptr);
break;
}
case TRITONSERVER_METRIC_KIND_GAUGE: {
ASSERT_EQ(err, nullptr);
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric, &value),
"query metric value after negative increment");
ASSERT_EQ(value, prev_value + decrement);
break;
}
default:
ASSERT_TRUE(false);
break;
}
double set_value = 42.0;
err = TRITONSERVER_MetricSet(metric, set_value);
switch (kind) {
case TRITONSERVER_METRIC_KIND_COUNTER: {
ASSERT_NE(err, nullptr);
break;
}
case TRITONSERVER_METRIC_KIND_GAUGE: {
ASSERT_EQ(err, nullptr);
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricValue(metric, &value),
"query metric value after set");
ASSERT_EQ(value, set_value);
break;
}
default:
ASSERT_TRUE(false);
break;
}
TRITONSERVER_MetricKind kind_tmp;
FAIL_TEST_IF_ERR(
TRITONSERVER_GetMetricKind(metric, &kind_tmp), "query metric kind");
ASSERT_EQ(kind_tmp, kind);
TRITONSERVER_ErrorDelete(err);
}
std::vector<std::uint64_t>
GetCumulativeCounts(
const std::vector<double>& data, const std::vector<double>& buckets)
{
std::vector<std::uint64_t> cumulative_counts(buckets.size() + 1, 0);
for (double datum : data) {
int i = 0;
for (; i < buckets.size(); ++i) {
if (datum <= buckets[i]) {
cumulative_counts[i]++;
break;
}
}
if (i == buckets.size()) {
cumulative_counts[i]++;
}
}
for (int i = 1; i < cumulative_counts.size(); ++i) {
cumulative_counts[i] += cumulative_counts[i - 1];
}
return cumulative_counts;
}
void
HistogramAPIHelper(
TRITONSERVER_Server* server, TRITONSERVER_Metric* metric,
std::vector<double> buckets, std::string metric_name,
std::string labels_str)
{
std::vector<double> data{0.05, 1.5, 6.0};
double sum = 0.0;
for (auto datum : data) {
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricObserve(metric, datum), "observe metric value");
sum += datum;
}
std::vector<std::uint64_t> cumulative_counts =
GetCumulativeCounts(data, buckets);
std::string metrics_str;
GetMetrics(server, &metrics_str);
std::ostringstream count_ss;
count_ss << metric_name << "_count{" << labels_str << "} " << data.size();
ASSERT_EQ(NumMetricMatches(server, count_ss.str()), 1);
std::ostringstream sum_ss;
sum_ss << metric_name << "_sum{" << labels_str << "} " << sum;
ASSERT_EQ(NumMetricMatches(server, sum_ss.str()), 1);
std::ostringstream bucket_partial_ss;
bucket_partial_ss << metric_name << "_bucket{" << labels_str;
ASSERT_EQ(
NumMetricMatches(server, bucket_partial_ss.str()),
cumulative_counts.size());
for (uint64_t i = 0; i < cumulative_counts.size(); ++i) {
std::ostringstream le_ss;
if (i < buckets.size()) {
le_ss << "\"" << buckets[i] << "\"";
} else {
le_ss << "\"+Inf\"";
}
std::ostringstream bucket_ss;
bucket_ss << metric_name << "_bucket{" << labels_str
<< ",le=" << le_ss.str() << "} " << cumulative_counts[i];
ASSERT_EQ(NumMetricMatches(server, bucket_ss.str()), 1);
}
}
class MetricsApiTest : public ::testing::Test {
protected:
static void SetUpTestSuite() {}
static void TearDownTestSuite() {}
void SetUp() override
{
TRITONSERVER_ServerOptions* server_options = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerOptionsNew(&server_options),
"creating server options");
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerOptionsSetLogInfo(server_options, false),
"disabling log INFO for brevity");
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerOptionsSetModelRepositoryPath(server_options, "."),
"setting model repository path");
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerOptionsSetModelControlMode(
server_options, TRITONSERVER_MODEL_CONTROL_EXPLICIT),
"setting model control mode");
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerNew(&server_, server_options), "creating server");
FAIL_TEST_IF_ERR(
TRITONSERVER_ServerOptionsDelete(server_options),
"deleting server options");
}
void TearDown() override
{
FAIL_TEST_IF_ERR(TRITONSERVER_ServerDelete(server_), "deleting server");
}
static TRITONSERVER_Server* server_;
};
TRITONSERVER_Server* MetricsApiTest::server_ = nullptr;
TEST_F(MetricsApiTest, TestCounterEndToEnd)
{
TRITONSERVER_MetricFamily* family;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "custom_counter_example";
const char* description = "this is an example counter metric added via API.";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
TRITONSERVER_Metric* metric;
std::vector<const TRITONSERVER_Parameter*> labels;
labels.emplace_back(TRITONSERVER_ParameterNew(
"example1", TRITONSERVER_PARAMETER_STRING, "counter_label1"));
labels.emplace_back(TRITONSERVER_ParameterNew(
"example2", TRITONSERVER_PARAMETER_STRING, "counter_label2"));
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric, family, labels.data(), labels.size()),
"Creating new metric");
for (const auto label : labels) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
MetricAPIHelper(metric, kind);
ASSERT_EQ(NumMetricMatches(server_, description), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric), "delete metric");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyDelete(family), "delete metric family");
ASSERT_EQ(NumMetricMatches(server_, description), 0);
}
TEST_F(MetricsApiTest, TestGaugeEndToEnd)
{
TRITONSERVER_MetricFamily* family;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_GAUGE;
const char* name = "custom_gauge_example";
const char* description = "this is an example gauge metric added via API.";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
TRITONSERVER_Metric* metric;
std::vector<const TRITONSERVER_Parameter*> labels;
labels.emplace_back(TRITONSERVER_ParameterNew(
"example1", TRITONSERVER_PARAMETER_STRING, "gauge_label1"));
labels.emplace_back(TRITONSERVER_ParameterNew(
"example2", TRITONSERVER_PARAMETER_STRING, "gauge_label2"));
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric, family, labels.data(), labels.size()),
"Creating new metric");
for (const auto label : labels) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
MetricAPIHelper(metric, kind);
ASSERT_EQ(NumMetricMatches(server_, description), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric), "delete metric");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyDelete(family), "delete metric family");
ASSERT_EQ(NumMetricMatches(server_, description), 0);
}
TEST_F(MetricsApiTest, TestHistogramEndToEnd)
{
TRITONSERVER_MetricFamily* family;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_HISTOGRAM;
const char* name = "custom_histogram_example";
const char* description =
"this is an example histogram metric added via API.";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
TRITONSERVER_Metric* metric;
std::vector<const TRITONSERVER_Parameter*> labels;
labels.emplace_back(TRITONSERVER_ParameterNew(
"example1", TRITONSERVER_PARAMETER_STRING, "histogram_label1"));
labels.emplace_back(TRITONSERVER_ParameterNew(
"example2", TRITONSERVER_PARAMETER_STRING, "histogram_label2"));
std::vector<double> buckets = {0.1, 1.0, 2.5, 5.0, 10.0};
TRITONSERVER_MetricArgs* args;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricArgsNew(&args), "Creating new metric args");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricArgsSetHistogram(args, buckets.data(), buckets.size()),
"setting histogram metric args");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNewWithArgs(
&metric, family, labels.data(), labels.size(), args),
"Creating new metric");
for (const auto label : labels) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
FAIL_TEST_IF_ERR(TRITONSERVER_MetricArgsDelete(args), "delete metric args");
std::string labels_str =
"example1=\"histogram_label1\",example2=\"histogram_label2\"";
HistogramAPIHelper(server_, metric, buckets, name, labels_str);
ASSERT_EQ(NumMetricMatches(server_, description), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric), "delete metric");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyDelete(family), "delete metric family");
ASSERT_EQ(NumMetricMatches(server_, description), 0);
}
TEST_F(MetricsApiTest, TestHistogramNoMetricArgs)
{
TRITONSERVER_MetricFamily* family;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_HISTOGRAM;
const char* name = "no_metric_args";
const char* description = "no metric args description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
TRITONSERVER_MetricArgs* args = nullptr;
std::vector<const TRITONSERVER_Parameter*> labels;
TRITONSERVER_Metric* metric = nullptr;
auto err = TRITONSERVER_MetricNewWithArgs(
&metric, family, labels.data(), labels.size(), args);
EXPECT_THAT(
TRITONSERVER_ErrorMessage(err),
HasSubstr("Bucket boundaries not found in Metric args"));
FAIL_TEST_IF_ERR(TRITONSERVER_MetricArgsDelete(args), "delete metric args");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyDelete(family), "delete metric family");
}
TEST_F(MetricsApiTest, TestHistogramMetricArgsNotset)
{
TRITONSERVER_MetricFamily* family;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_HISTOGRAM;
const char* name = "metric_args_not_set";
const char* description = "metric args not set description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
TRITONSERVER_MetricArgs* args;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricArgsNew(&args), "Creating new metric args");
std::vector<const TRITONSERVER_Parameter*> labels;
TRITONSERVER_Metric* metric = nullptr;
auto err = TRITONSERVER_MetricNewWithArgs(
&metric, family, labels.data(), labels.size(), args);
EXPECT_THAT(
TRITONSERVER_ErrorMessage(err),
HasSubstr("Metric args not set to histogram kind"));
FAIL_TEST_IF_ERR(TRITONSERVER_MetricArgsDelete(args), "delete metric args");
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyDelete(family), "delete metric family");
}
TEST_F(MetricsApiTest, TestDupeMetricFamilyDiffKind)
{
TRITONSERVER_MetricFamily* family1 = nullptr;
TRITONSERVER_MetricKind kind1 = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "diff_kind_test";
const char* description = "diff kind description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family1, kind1, name, description),
"Creating new metric family1");
TRITONSERVER_MetricFamily* family2 = nullptr;
TRITONSERVER_MetricKind kind2 = TRITONSERVER_METRIC_KIND_GAUGE;
auto err = TRITONSERVER_MetricFamilyNew(&family2, kind2, name, description);
ASSERT_NE(err, nullptr);
ASSERT_EQ(family2, nullptr);
TRITONSERVER_ErrorDelete(err);
}
TEST_F(MetricsApiTest, TestDupeMetricFamilyDiffDescription)
{
TRITONSERVER_MetricFamily* family1 = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "diff_description_test";
const char* description1 = "first description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family1, kind, name, description1),
"Creating new metric family1");
TRITONSERVER_MetricFamily* family2 = nullptr;
const char* description2 = "second description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family2, kind, name, description2),
"Creating new metric family2");
ASSERT_EQ(NumMetricMatches(server_, description1), 0);
ASSERT_EQ(NumMetricMatches(server_, description2), 0);
std::vector<const TRITONSERVER_Parameter*> labels;
TRITONSERVER_Metric* metric2 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric2, family2, labels.data(), labels.size()),
"Creating new metric2");
ASSERT_EQ(NumMetricMatches(server_, description1), 1);
ASSERT_EQ(NumMetricMatches(server_, description2), 0);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family1), "delete family1");
ASSERT_EQ(NumMetricMatches(server_, description1), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric2), "delete metric2");
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family2), "delete family2");
ASSERT_EQ(NumMetricMatches(server_, description1), 0);
ASSERT_EQ(NumMetricMatches(server_, description2), 0);
}
TEST_F(MetricsApiTest, TestDupeMetricFamily)
{
TRITONSERVER_MetricFamily* family1 = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "dupe_metric_family_test";
const char* description = "dupe metric family description";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family1, kind, name, description),
"Creating new metric family1");
TRITONSERVER_MetricFamily* family2 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family2, kind, name, description),
"Creating new metric family2");
ASSERT_EQ(NumMetricMatches(server_, description), 0);
const char* metric_key = "custom_metric_key";
std::vector<const TRITONSERVER_Parameter*> labels1;
labels1.emplace_back(TRITONSERVER_ParameterNew(
metric_key, TRITONSERVER_PARAMETER_STRING, "label1"));
TRITONSERVER_Metric* metric1 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric1, family1, labels1.data(), labels1.size()),
"Creating new metric1");
for (const auto label : labels1) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
std::vector<const TRITONSERVER_Parameter*> labels2;
labels2.emplace_back(TRITONSERVER_ParameterNew(
metric_key, TRITONSERVER_PARAMETER_STRING, "label2"));
TRITONSERVER_Metric* metric2 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric2, family2, labels2.data(), labels2.size()),
"Creating new metric2");
for (const auto label : labels2) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
ASSERT_EQ(NumMetricMatches(server_, description), 1);
ASSERT_EQ(NumMetricMatches(server_, metric_key), 2);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric1), "delete metric1");
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family1), "delete family1");
ASSERT_EQ(NumMetricMatches(server_, description), 1);
ASSERT_EQ(NumMetricMatches(server_, metric_key), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric2), "delete metric2");
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family2), "delete family2");
ASSERT_EQ(NumMetricMatches(server_, description), 0);
ASSERT_EQ(NumMetricMatches(server_, metric_key), 0);
}
TEST_F(MetricsApiTest, TestDupeMetricLabels)
{
std::vector<const TRITONSERVER_Parameter*> labels;
labels.emplace_back(TRITONSERVER_ParameterNew(
"example1", TRITONSERVER_PARAMETER_STRING, "label1"));
labels.emplace_back(TRITONSERVER_ParameterNew(
"example2", TRITONSERVER_PARAMETER_STRING, "label2"));
DupeMetricHelper(server_, labels);
for (const auto label : labels) {
TRITONSERVER_ParameterDelete(const_cast<TRITONSERVER_Parameter*>(label));
}
}
TEST_F(MetricsApiTest, TestDupeMetricEmptyLabels)
{
std::vector<const TRITONSERVER_Parameter*> labels;
DupeMetricHelper(server_, labels);
}
TEST_F(MetricsApiTest, TestOutOfOrderDelete)
{
TRITONSERVER_MetricFamily* family = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_COUNTER;
const char* name = "out_of_order_delete";
const char* description = "out of order delete test";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
std::vector<const TRITONSERVER_Parameter*> labels;
TRITONSERVER_Metric* metric = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric, family, labels.data(), labels.size()),
"Creating new metric");
auto err = TRITONSERVER_MetricFamilyDelete(family);
EXPECT_THAT(
TRITONSERVER_ErrorMessage(err), HasSubstr("Must call MetricDelete"));
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric), "deleting metric");
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family), "deleting family");
TRITONSERVER_ErrorDelete(err);
}
TEST_F(MetricsApiTest, TestMetricAfterFamilyDelete)
{
TRITONSERVER_MetricFamily* family = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_GAUGE;
const char* name = "use_metric_after_family_delete";
const char* description = "test using a metric after its family is deleted";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
std::vector<const TRITONSERVER_Parameter*> labels;
TRITONSERVER_Metric* metric = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric, family, labels.data(), labels.size()),
"Creating new metric");
auto err = TRITONSERVER_MetricFamilyDelete(family);
EXPECT_THAT(
TRITONSERVER_ErrorMessage(err), HasSubstr("Must call MetricDelete"));
delete reinterpret_cast<tc::MetricFamily*>(family);
double value = -1;
err = TRITONSERVER_MetricValue(metric, &value);
EXPECT_THAT(TRITONSERVER_ErrorMessage(err), HasSubstr("invalidated"));
err = TRITONSERVER_MetricIncrement(metric, 1.0);
EXPECT_THAT(TRITONSERVER_ErrorMessage(err), HasSubstr("invalidated"));
err = TRITONSERVER_MetricSet(metric, 1.0);
EXPECT_THAT(TRITONSERVER_ErrorMessage(err), HasSubstr("invalidated"));
TRITONSERVER_ErrorDelete(err);
}
TEST_F(MetricsApiTest, TestCoreMetricAccess)
{
TRITONSERVER_MetricFamily* family = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_GAUGE;
const char* name = "nv_gpu_power_limit";
const char* description = "";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family), "delete family");
}
TEST_F(MetricsApiTest, TestChildMetricTracking)
{
TRITONSERVER_MetricFamily* family = nullptr;
TRITONSERVER_MetricKind kind = TRITONSERVER_METRIC_KIND_GAUGE;
const char* name = "test_ref_counting";
const char* description = "test using metric ref counting";
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricFamilyNew(&family, kind, name, description),
"Creating new metric family");
auto tc_family = reinterpret_cast<tc::MetricFamily*>(family);
TRITONSERVER_Metric* metric1 = nullptr;
std::vector<const TRITONSERVER_Parameter*> labels;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric1, family, labels.data(), labels.size()),
"Creating new metric1");
ASSERT_EQ(tc_family->NumMetrics(), 1);
TRITONSERVER_Metric* metric2 = nullptr;
FAIL_TEST_IF_ERR(
TRITONSERVER_MetricNew(&metric2, family, labels.data(), labels.size()),
"Creating new metric2");
ASSERT_EQ(tc_family->NumMetrics(), 2);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric1), "delete metric1");
ASSERT_EQ(tc_family->NumMetrics(), 1);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricDelete(metric2), "delete metric2");
ASSERT_EQ(tc_family->NumMetrics(), 0);
FAIL_TEST_IF_ERR(TRITONSERVER_MetricFamilyDelete(family), "delete family");
}
}
int
main(int argc, char** argv)
{
#ifdef TRITON_ENABLE_LOGGING
LOG_SET_VERBOSE(1);
#endif
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#endif