From patchwork Tue May 17 10:01:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Armitage X-Patchwork-Id: 111237 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 16CB4A04FF; Tue, 17 May 2022 12:01:49 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E73A040042; Tue, 17 May 2022 12:01:48 +0200 (CEST) Received: from nabal.armitage.org.uk (host-92-27-6-192.static.as13285.net [92.27.6.192]) by mails.dpdk.org (Postfix) with ESMTP id 5C84940041; Tue, 17 May 2022 12:01:47 +0200 (CEST) Received: from localhost (nabal.armitage.org.uk [127.0.0.1]) by nabal.armitage.org.uk (Postfix) with ESMTP id A11132E4316; Tue, 17 May 2022 11:01:46 +0100 (BST) Authentication-Results: nabal.armitage.org.uk (amavisd-new); dkim=pass (1024-bit key) reason="pass (just generated, assumed good)" header.d=armitage.org.uk DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=armitage.org.uk; h=content-transfer-encoding:mime-version:references:in-reply-to :x-mailer:message-id:date:date:subject:subject:from:from :received; s=20200110; t=1652781688; x=1653645689; bh=RUxSw7JIfd yOwXP4BLn2X/pK5uRCHtlwsxpk8hIYKx8=; b=HmlQIC1l67nE9nWB7VEAdModyg gXFbUBo3h2i2YGzaeFeRm0sEjnQyV7BSxQKb1oB/8lo3iXPXBGTq6CHBf5wIk7Uw Pc8R9820Yt/U59ho3l8wn7j75JM83EHKyA01cPiO3c91o0rej1Wn8QGPRSz8eyAV VFeUKKLTvu9x9sJqo= X-Virus-Scanned: amavisd-new at armitage.org.uk Received: from samson.armitage.org.uk (samson.armitage.org.uk [IPv6:2001:470:69dd:35::210]) by nabal.armitage.org.uk (Postfix) with ESMTPSA id 6AB892E40E1; Tue, 17 May 2022 11:01:28 +0100 (BST) From: Quentin Armitage To: Reshma Pattan , Stephen Hemminger , Ray Kinsella Cc: dev@dpdk.org, Quentin Armitage , stable@dpdk.org Subject: [PATCH v2] libpcapng: fix timestamp wrapping in output files Date: Tue, 17 May 2022 11:01:15 +0100 Message-Id: <20220517100115.157888-1-quentin@armitage.org.uk> X-Mailer: git-send-email 2.34.3 In-Reply-To: <20220511094655.4f885c84@hermes.local> References: <20220511094655.4f885c84@hermes.local> MIME-Version: 1.0 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 In pcap_tsc_to_ns(), delta * NSEC_PER_SEC will overflow approx 8 seconds after pcap_init is called when using a TSC with a frequency of 2.5GHz. To avoid the overflow, update the saved time and TSC value once delta >= tsc_hz. Fixes: 8d23ce8f5ee ("pcapng: add new library for writing pcapng files") Cc: stable@dpdk.org Signed-off-by: Quentin Armitage Acked-by: Stephen Hemminger --- v2: - Don't call clock_gettime() in fast path - Update pcapng_time.ns and pcapng_time.cycles to ensure delta < tsc_hz - Stop using constructor to initialise pcapng_time.tsc_hz since it is not initialised until rte_eal_init() is called - use mean value of TSC before and after call to clock_gettime() - only call rte_get_tsc_hz() once - use rte_reciprocal functions instead of division lib/pcapng/rte_pcapng.c | 47 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c index 90b2f5bc69..06ad712bd1 100644 --- a/lib/pcapng/rte_pcapng.c +++ b/lib/pcapng/rte_pcapng.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "pcapng_proto.h" @@ -34,27 +35,63 @@ struct rte_pcapng { }; /* For converting TSC cycles to PCAPNG ns format */ -struct pcapng_time { +static struct pcapng_time { uint64_t ns; uint64_t cycles; + uint64_t tsc_hz; + struct rte_reciprocal_u64 tsc_hz_inverse; } pcapng_time; -RTE_INIT(pcapng_init) +static inline void +pcapng_init(void) { struct timespec ts; pcapng_time.cycles = rte_get_tsc_cycles(); clock_gettime(CLOCK_REALTIME, &ts); + pcapng_time.cycles = (pcapng_time.cycles + rte_get_tsc_cycles()) / 2; pcapng_time.ns = rte_timespec_to_ns(&ts); + + pcapng_time.tsc_hz = rte_get_tsc_hz(); + pcapng_time.tsc_hz_inverse = rte_reciprocal_value_u64(pcapng_time.tsc_hz); } /* PCAPNG timestamps are in nanoseconds */ static uint64_t pcapng_tsc_to_ns(uint64_t cycles) { - uint64_t delta; - + uint64_t delta, secs; + + if (!pcapng_time.tsc_hz) + pcapng_init(); + + /* In essence the calculation is: + * delta = (cycles - pcapng_time.cycles) * NSEC_PRE_SEC / rte_get_tsc_hz() + * but this overflows within 4 to 8 seconds depending on TSC frequency. + * Instead, if delta >= pcapng_time.tsc_hz: + * Increase pcapng_time.ns and pcapng_time.cycles by the number of + * whole seconds in delta and reduce delta accordingly. + * delta will therefore always lie in the interval [0, pcapng_time.tsc_hz), + * which will not overflow when multiplied by NSEC_PER_SEC provided the + * TSC frequency < approx 18.4GHz. + * + * Currently all TSCs operate below 5GHz. + */ delta = cycles - pcapng_time.cycles; - return pcapng_time.ns + (delta * NSEC_PER_SEC) / rte_get_tsc_hz(); + if (unlikely(delta >= pcapng_time.tsc_hz)) { + if (likely(delta < pcapng_time.tsc_hz * 2)) { + delta -= pcapng_time.tsc_hz; + pcapng_time.cycles += pcapng_time.tsc_hz; + pcapng_time.ns += NSEC_PER_SEC; + } else { + secs = rte_reciprocal_divide_u64(delta, &pcapng_time.tsc_hz_inverse); + delta -= secs * pcapng_time.tsc_hz; + pcapng_time.cycles += secs * pcapng_time.tsc_hz; + pcapng_time.ns += secs * NSEC_PER_SEC; + } + } + + return pcapng_time.ns + rte_reciprocal_divide_u64(delta * NSEC_PER_SEC, + &pcapng_time.tsc_hz_inverse); } /* length of option including padding */