From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 68A0AA0032; Tue, 13 Sep 2022 15:48:43 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0CFAF4021E; Tue, 13 Sep 2022 15:48:43 +0200 (CEST) Received: from smartserver.smartsharesystems.com (smartserver.smartsharesystems.com [77.243.40.215]) by mails.dpdk.org (Postfix) with ESMTP id 9BA2540151 for ; Tue, 13 Sep 2022 15:48:41 +0200 (CEST) Content-class: urn:content-classes:message MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Subject: RE: [PATCH v6 1/4] eal: add lcore poll busyness telemetry X-MimeOLE: Produced By Microsoft Exchange V6.5 Date: Tue, 13 Sep 2022 15:48:39 +0200 Message-ID: <98CBD80474FA8B44BF855DF32C47DC35D8730A@smartserver.smartshare.dk> In-Reply-To: <20220913131941.582819-2-kevin.laatz@intel.com> X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: [PATCH v6 1/4] eal: add lcore poll busyness telemetry Thread-Index: AdjHcxBy8fZydHqUSz+yd3B42Bd9wwAAyPxQ References: <24c49429394294cfbf0d9c506b205029bac77c8b.1657890378.git.anatoly.burakov@intel.com> <20220913131941.582819-1-kevin.laatz@intel.com> <20220913131941.582819-2-kevin.laatz@intel.com> From: =?iso-8859-1?Q?Morten_Br=F8rup?= To: "Kevin Laatz" , Cc: , "Conor Walsh" , "David Hunt" , "Bruce Richardson" , "Nicolas Chautru" , "Fan Zhang" , "Ashish Gupta" , "Akhil Goyal" , "Chengwen Feng" , "Ray Kinsella" , "Thomas Monjalon" , "Ferruh Yigit" , "Andrew Rybchenko" , "Jerin Jacob" , "Sachin Saxena" , "Hemant Agrawal" , "Ori Kam" , "Honnappa Nagarahalli" , "Konstantin Ananyev" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org > From: Kevin Laatz [mailto:kevin.laatz@intel.com] > Sent: Tuesday, 13 September 2022 15.20 >=20 > From: Anatoly Burakov >=20 [...] Still a few missing renames... > diff --git a/lib/eal/common/eal_common_lcore_telemetry.c > b/lib/eal/common/eal_common_lcore_telemetry.c > new file mode 100644 > index 0000000000..abef1ff86d > --- /dev/null > +++ b/lib/eal/common/eal_common_lcore_telemetry.c eal_common_lcore_poll_telemetry.c > @@ -0,0 +1,303 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2022 Intel Corporation > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#ifdef RTE_LCORE_POLL_BUSYNESS > +#include > +#endif > + > +rte_atomic32_t __rte_lcore_telemetry_enabled; __rte_lcore_poll_telemetry_enabled > + > +#ifdef RTE_LCORE_POLL_BUSYNESS > + > +struct lcore_telemetry { This one is private, so suggestion only: struct lcore_poll_telemetry { > + int poll_busyness; > + /**< Calculated poll busyness (gets set/returned by the API) */ > + int raw_poll_busyness; > + /**< Calculated poll busyness times 100. */ > + uint64_t interval_ts; > + /**< when previous telemetry interval started */ > + uint64_t empty_cycles; > + /**< empty cycle count since last interval */ > + uint64_t last_poll_ts; > + /**< last poll timestamp */ > + bool last_empty; > + /**< if last poll was empty */ > + unsigned int contig_poll_cnt; > + /**< contiguous (always empty/non empty) poll counter */ > +} __rte_cache_aligned; > + > +static struct lcore_telemetry *telemetry_data; > + > +#define LCORE_POLL_BUSYNESS_MAX 100 > +#define LCORE_POLL_BUSYNESS_NOT_SET -1 > +#define LCORE_POLL_BUSYNESS_MIN 0 > + > +#define SMOOTH_COEFF 5 > +#define STATE_CHANGE_OPT 32 > + > +static void lcore_config_init(void) > +{ > + int lcore_id; > + > + RTE_LCORE_FOREACH(lcore_id) { > + struct lcore_telemetry *td =3D &telemetry_data[lcore_id]; > + > + td->interval_ts =3D 0; > + td->last_poll_ts =3D 0; > + td->empty_cycles =3D 0; > + td->last_empty =3D true; > + td->contig_poll_cnt =3D 0; > + td->poll_busyness =3D LCORE_POLL_BUSYNESS_NOT_SET; > + td->raw_poll_busyness =3D 0; > + } > +} > + > +int rte_lcore_poll_busyness(unsigned int lcore_id) > +{ > + const uint64_t tsc_ms =3D rte_get_timer_hz() / MS_PER_S; > + /* if more than 1000 busyness periods have passed, this core is > considered inactive */ > + const uint64_t active_thresh =3D RTE_LCORE_POLL_BUSYNESS_PERIOD_MS > * tsc_ms * 1000; > + struct lcore_telemetry *tdata; > + > + if (lcore_id >=3D RTE_MAX_LCORE) > + return -EINVAL; > + tdata =3D &telemetry_data[lcore_id]; > + > + /* if the lcore is not active */ > + if (tdata->interval_ts =3D=3D 0) > + return LCORE_POLL_BUSYNESS_NOT_SET; > + /* if the core hasn't been active in a while */ > + else if ((rte_rdtsc() - tdata->interval_ts) > active_thresh) > + return LCORE_POLL_BUSYNESS_NOT_SET; > + > + /* this core is active, report its poll busyness */ > + return telemetry_data[lcore_id].poll_busyness; > +} > + > +int rte_lcore_poll_busyness_enabled(void) > +{ > + return rte_atomic32_read(&__rte_lcore_telemetry_enabled); > +} > + > +void rte_lcore_poll_busyness_enabled_set(bool enable) > +{ > + int set =3D rte_atomic32_cmpset((volatile uint32_t > *)&__rte_lcore_telemetry_enabled, > + (int)!enable, (int)enable); > + > + /* Reset counters on successful disable */ > + if (set && !enable) > + lcore_config_init(); > +} > + > +static inline int calc_raw_poll_busyness(const struct lcore_telemetry > *tdata, > + const uint64_t empty, const uint64_t total) > +{ > + /* > + * We don't want to use floating point math here, but we want for > our poll > + * busyness to react smoothly to sudden changes, while still > keeping the > + * accuracy and making sure that over time the average follows > poll busyness > + * as measured just-in-time. Therefore, we will calculate the > average poll > + * busyness using integer math, but shift the decimal point two > places > + * to the right, so that 100.0 becomes 10000. This allows us to > report > + * integer values (0..100) while still allowing ourselves to > follow the > + * just-in-time measurements when we calculate our averages. > + */ > + const int max_raw_idle =3D LCORE_POLL_BUSYNESS_MAX * 100; > + > + const int prev_raw_idle =3D max_raw_idle - tdata- > >raw_poll_busyness; > + > + /* calculate rate of idle cycles, times 100 */ > + const int cur_raw_idle =3D (int)((empty * max_raw_idle) / total); > + > + /* smoothen the idleness */ > + const int smoothened_idle =3D > + (cur_raw_idle + prev_raw_idle * (SMOOTH_COEFF - 1)) / > SMOOTH_COEFF; > + > + /* convert idleness to poll busyness */ > + return max_raw_idle - smoothened_idle; > +} > + > +void __rte_lcore_poll_busyness_timestamp(uint16_t nb_rx) > +{ > + const unsigned int lcore_id =3D rte_lcore_id(); > + uint64_t interval_ts, empty_cycles, cur_tsc, last_poll_ts; > + struct lcore_telemetry *tdata; > + const bool empty =3D nb_rx =3D=3D 0; > + uint64_t diff_int, diff_last; > + bool last_empty; > + > + /* This telemetry is not supported for unregistered non-EAL > threads */ > + if (lcore_id >=3D RTE_MAX_LCORE) { > + RTE_LOG(DEBUG, EAL, > + "Lcore telemetry not supported on unregistered > non-EAL thread %d", > + lcore_id); > + return; > + } > + > + tdata =3D &telemetry_data[lcore_id]; > + last_empty =3D tdata->last_empty; > + > + /* optimization: don't do anything if status hasn't changed */ > + if (last_empty =3D=3D empty && tdata->contig_poll_cnt++ < > STATE_CHANGE_OPT) > + return; > + /* status changed or we're waiting for too long, reset counter */ > + tdata->contig_poll_cnt =3D 0; > + > + cur_tsc =3D rte_rdtsc(); > + > + interval_ts =3D tdata->interval_ts; > + empty_cycles =3D tdata->empty_cycles; > + last_poll_ts =3D tdata->last_poll_ts; > + > + diff_int =3D cur_tsc - interval_ts; > + diff_last =3D cur_tsc - last_poll_ts; > + > + /* is this the first time we're here? */ > + if (interval_ts =3D=3D 0) { > + tdata->poll_busyness =3D LCORE_POLL_BUSYNESS_MIN; > + tdata->raw_poll_busyness =3D 0; > + tdata->interval_ts =3D cur_tsc; > + tdata->empty_cycles =3D 0; > + tdata->contig_poll_cnt =3D 0; > + goto end; > + } > + > + /* update the empty counter if we got an empty poll earlier */ > + if (last_empty) > + empty_cycles +=3D diff_last; > + > + /* have we passed the interval? */ > + uint64_t interval =3D ((rte_get_tsc_hz() / MS_PER_S) * > RTE_LCORE_POLL_BUSYNESS_PERIOD_MS); > + if (diff_int > interval) { > + int raw_poll_busyness; > + > + /* get updated poll_busyness value */ > + raw_poll_busyness =3D calc_raw_poll_busyness(tdata, > empty_cycles, diff_int); > + > + /* set a new interval, reset empty counter */ > + tdata->interval_ts =3D cur_tsc; > + tdata->empty_cycles =3D 0; > + tdata->raw_poll_busyness =3D raw_poll_busyness; > + /* bring poll busyness back to 0..100 range, biased to > round up */ > + tdata->poll_busyness =3D (raw_poll_busyness + 50) / 100; > + } else > + /* we may have updated empty counter */ > + tdata->empty_cycles =3D empty_cycles; > + > +end: > + /* update status for next poll */ > + tdata->last_poll_ts =3D cur_tsc; > + tdata->last_empty =3D empty; > +} > + > +static int > +lcore_poll_busyness_enable(const char *cmd __rte_unused, > + const char *params __rte_unused, > + struct rte_tel_data *d) > +{ > + rte_lcore_poll_busyness_enabled_set(true); > + > + rte_tel_data_start_dict(d); > + > + rte_tel_data_add_dict_int(d, "poll_busyness_enabled", 1); > + > + return 0; > +} > + > +static int > +lcore_poll_busyness_disable(const char *cmd __rte_unused, > + const char *params __rte_unused, > + struct rte_tel_data *d) > +{ > + rte_lcore_poll_busyness_enabled_set(false); > + > + rte_tel_data_start_dict(d); > + > + rte_tel_data_add_dict_int(d, "poll_busyness_enabled", 0); > + > + return 0; > +} > + > +static int > +lcore_handle_poll_busyness(const char *cmd __rte_unused, > + const char *params __rte_unused, struct rte_tel_data > *d) > +{ > + char corenum[64]; > + int i; > + > + rte_tel_data_start_dict(d); > + > + RTE_LCORE_FOREACH(i) { > + if (!rte_lcore_is_enabled(i)) > + continue; > + snprintf(corenum, sizeof(corenum), "%d", i); > + rte_tel_data_add_dict_int(d, corenum, > rte_lcore_poll_busyness(i)); > + } > + > + return 0; > +} > + > +void > +lcore_telemetry_free(void) Not sure, but either: lcore_poll_telemetry_free or rte_lcore_poll_telemetry_free > +{ > + if (telemetry_data !=3D NULL) { > + free(telemetry_data); > + telemetry_data =3D NULL; > + } > +} > + > +RTE_INIT(lcore_init_telemetry) Not sure, but either: RTE_INIT(lcore_poll_init_telemetry) or RTE_INIT(rte_lcore_poll_init_telemetry) > +{ > + telemetry_data =3D calloc(RTE_MAX_LCORE, > sizeof(telemetry_data[0])); > + if (telemetry_data =3D=3D NULL) > + rte_panic("Could not init lcore telemetry data: Out of > memory\n"); > + > + lcore_config_init(); > + > + rte_telemetry_register_cmd("/eal/lcore/poll_busyness", > lcore_handle_poll_busyness, > + "return percentage poll busyness of cores"); > + > + rte_telemetry_register_cmd("/eal/lcore/poll_busyness_enable", > lcore_poll_busyness_enable, > + "enable lcore poll busyness measurement"); > + > + rte_telemetry_register_cmd("/eal/lcore/poll_busyness_disable", > lcore_poll_busyness_disable, > + "disable lcore poll busyness measurement"); > + > + rte_atomic32_set(&__rte_lcore_telemetry_enabled, true); > +} > + > +#else > + > +int rte_lcore_poll_busyness(unsigned int lcore_id __rte_unused) > +{ > + return -ENOTSUP; > +} > + > +int rte_lcore_poll_busyness_enabled(void) > +{ > + return -ENOTSUP; > +} > + > +void rte_lcore_poll_busyness_enabled_set(bool enable __rte_unused) > +{ > +} > + > +void __rte_lcore_poll_busyness_timestamp(uint16_t nb_rx __rte_unused) > +{ > +} > + > +void lcore_telemetry_free(void) > +{ > +} > + > +#endif