From 5da14042f70711ea5cf66e034699730335462f66 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 May 2024 14:08:03 +0200 Subject: Merging upstream version 1.45.3+dfsg. Signed-off-by: Daniel Baumann --- src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c | 249 +++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c (limited to 'src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c') diff --git a/src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c b/src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c new file mode 100644 index 000000000..48e702f3f --- /dev/null +++ b/src/fluent-bit/lib/librdkafka-2.1.0/tests/rusage.c @@ -0,0 +1,249 @@ +/* + * librdkafka - The Apache Kafka C/C++ library + * + * Copyright (c) 2019 Magnus Edenhill + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @name Track test resource usage. + */ + +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE /* required for rusage.ru_maxrss, etc. */ +#endif + +#include "test.h" + +#if HAVE_GETRUSAGE + +#include +#include +#include "rdfloat.h" + + +/** + * @brief Call getrusage(2) + */ +static int test_getrusage(struct rusage *ru) { + if (getrusage(RUSAGE_SELF, ru) == -1) { + TEST_WARN("getrusage() failed: %s\n", rd_strerror(errno)); + return -1; + } + + return 0; +} + +/* Convert timeval to seconds */ +#define _tv2s(TV) \ + (double)((double)(TV).tv_sec + ((double)(TV).tv_usec / 1000000.0)) + +/* Convert timeval to CPU usage percentage (5 = 5%, 130.3 = 130.3%) */ +#define _tv2cpu(TV, DURATION) ((_tv2s(TV) / (DURATION)) * 100.0) + + +/** + * @brief Calculate difference between \p end and \p start rusage. + * + * @returns the delta + */ +static struct rusage test_rusage_calc(const struct rusage *start, + const struct rusage *end, + double duration) { + struct rusage delta = RD_ZERO_INIT; + + timersub(&end->ru_utime, &start->ru_utime, &delta.ru_utime); + timersub(&end->ru_stime, &start->ru_stime, &delta.ru_stime); + /* FIXME: maxrss doesn't really work when multiple tests are + * run in the same process since it only registers the + * maximum RSS, not the current one. + * Read this from /proc//.. instead */ + delta.ru_maxrss = end->ru_maxrss - start->ru_maxrss; + delta.ru_nvcsw = end->ru_nvcsw - start->ru_nvcsw; + /* skip fields we're not interested in */ + + TEST_SAY(_C_MAG + "Test resource usage summary: " + "%.3fs (%.1f%%) User CPU time, " + "%.3fs (%.1f%%) Sys CPU time, " + "%.3fMB RSS memory increase, " + "%ld Voluntary context switches\n", + _tv2s(delta.ru_utime), _tv2cpu(delta.ru_utime, duration), + _tv2s(delta.ru_stime), _tv2cpu(delta.ru_stime, duration), + (double)delta.ru_maxrss / (1024.0 * 1024.0), delta.ru_nvcsw); + + return delta; +} + + +/** + * @brief Check that test ran within threshold levels + */ +static int test_rusage_check_thresholds(struct test *test, + const struct rusage *ru, + double duration) { + static const struct rusage_thres defaults = { + .ucpu = 5.0, /* min value, see below */ + .scpu = 2.5, /* min value, see below */ + .rss = 10.0, /* 10 megs */ + .ctxsw = 100, /* this is the default number of context switches + * per test second. + * note: when ctxsw is specified on a test + * it should be specified as the total + * number of context switches. */ + }; + /* CPU usage thresholds are too blunt for very quick tests. + * Use a forgiving default CPU threshold for any test that + * runs below a certain duration. */ + const double min_duration = 2.0; /* minimum test duration for + * CPU thresholds to have effect. */ + const double lax_cpu = 1000.0; /* 1000% CPU usage (e.g 10 cores + * at full speed) allowed for any + * test that finishes in under 2s */ + const struct rusage_thres *thres = &test->rusage_thres; + double cpu, mb, uthres, uthres_orig, sthres, rssthres; + int csthres; + char reasons[3][128]; + int fails = 0; + + if (duration < min_duration) + uthres = lax_cpu; + else if (rd_dbl_zero((uthres = thres->ucpu))) + uthres = defaults.ucpu; + + uthres_orig = uthres; + uthres *= test_rusage_cpu_calibration; + + cpu = _tv2cpu(ru->ru_utime, duration); + if (cpu > uthres) { + rd_snprintf(reasons[fails], sizeof(reasons[fails]), + "User CPU time (%.3fs) exceeded: %.1f%% > %.1f%%", + _tv2s(ru->ru_utime), cpu, uthres); + TEST_WARN("%s\n", reasons[fails]); + fails++; + } + + /* Let the default Sys CPU be the maximum of the defaults.cpu + * and 20% of the User CPU. */ + if (rd_dbl_zero((sthres = thres->scpu))) + sthres = duration < min_duration + ? lax_cpu + : RD_MAX(uthres_orig * 0.20, defaults.scpu); + + sthres *= test_rusage_cpu_calibration; + + cpu = _tv2cpu(ru->ru_stime, duration); + if (cpu > sthres) { + rd_snprintf(reasons[fails], sizeof(reasons[fails]), + "Sys CPU time (%.3fs) exceeded: %.1f%% > %.1f%%", + _tv2s(ru->ru_stime), cpu, sthres); + TEST_WARN("%s\n", reasons[fails]); + fails++; + } + + rssthres = thres->rss > 0.0 ? thres->rss : defaults.rss; + if ((mb = (double)ru->ru_maxrss / (1024.0 * 1024.0)) > rssthres) { + rd_snprintf(reasons[fails], sizeof(reasons[fails]), + "RSS memory exceeded: %.2fMB > %.2fMB", mb, + rssthres); + TEST_WARN("%s\n", reasons[fails]); + fails++; + } + + + if (!(csthres = thres->ctxsw)) + csthres = duration < min_duration + ? defaults.ctxsw * 100 + : (int)(duration * (double)defaults.ctxsw); + + /* FIXME: not sure how to use this */ + if (0 && ru->ru_nvcsw > csthres) { + TEST_WARN( + "Voluntary context switches exceeded: " + "%ld > %d\n", + ru->ru_nvcsw, csthres); + fails++; + } + + TEST_ASSERT(fails <= (int)RD_ARRAYSIZE(reasons), + "reasons[] array not big enough (needs %d slots)", fails); + + if (!fails || !test_rusage) + return 0; + + TEST_FAIL("Test resource usage exceeds %d threshold(s): %s%s%s%s%s", + fails, reasons[0], fails > 1 ? ", " : "", + fails > 1 ? reasons[1] : "", fails > 2 ? ", " : "", + fails > 2 ? reasons[2] : ""); + + + return -1; +} +#endif + + + +void test_rusage_start(struct test *test) { +#if HAVE_GETRUSAGE + /* Can't do per-test rusage checks when tests run in parallel. */ + if (test_concurrent_max > 1) + return; + + if (test_getrusage(&test->rusage) == -1) + return; +#endif +} + + +/** + * @brief Stop test rusage and check if thresholds were exceeded. + * Call when test has finished. + * + * @returns -1 if thresholds were exceeded, else 0. + */ +int test_rusage_stop(struct test *test, double duration) { +#if HAVE_GETRUSAGE + struct rusage start, end; + + /* Can't do per-test rusage checks when tests run in parallel. */ + if (test_concurrent_max > 1) + return 0; + + if (test_getrusage(&end) == -1) + return 0; + + /* Let duration be at least 1ms to avoid + * too-close-to-zero comparisons */ + if (duration < 0.001) + duration = 0.001; + + start = test->rusage; + test->rusage = test_rusage_calc(&start, &end, duration); + + return test_rusage_check_thresholds(test, &test->rusage, duration); +#else + return 0; +#endif +} -- cgit v1.2.3