From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
Reshma Pattan <reshma.pattan@intel.com>
Subject: [PATCH 2/3] pcapng: use EAL TSC to epoch conversion
Date: Tue, 20 Oct 2026 10:55:43 -0700 [thread overview]
Message-ID: <20261020175732.1552406-3-stephen@networkplumber.org> (raw)
In-Reply-To: <20261020175732.1552406-1-stephen@networkplumber.org>
The pcapng library carried its own TSC to nanoseconds conversion along
with the reference point it needs: the TSC and wall clock sampled when
the capture file was opened. EAL now records an equivalent reference
point at init and exposes rte_tsc_to_ns(), so the local copy is
redundant.
Convert timestamps with rte_tsc_to_ns() and drop the per-handle
reference point. The interface statistics block still reports when the
file was opened rather than when EAL started, so that time is kept in
the handle, now derived from the TSC like every other timestamp.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_pcapng.c | 8 +++----
lib/pcapng/rte_pcapng.c | 52 +++++------------------------------------
2 files changed, 10 insertions(+), 50 deletions(-)
diff --git a/app/test/test_pcapng.c b/app/test/test_pcapng.c
index 688b58794e..060c479ba2 100644
--- a/app/test/test_pcapng.c
+++ b/app/test/test_pcapng.c
@@ -648,8 +648,8 @@ test_write_before_open(void)
mbuf1_prepare(&mbfs);
mbuf1_resize(&mbfs, rte_rand_max(MAX_DATA_SIZE));
- /* Copy packets BEFORE opening the pcapng file.
- * This exercises the negative TSC delta path.
+ /* Copy packets BEFORE opening the pcapng file, so their
+ * timestamps precede the capture start time.
*/
for (i = 0; i < (int)count; i++) {
clones[i] = rte_pcapng_copy(port_id, 0, &mbfs.mb[0], mp,
@@ -662,7 +662,7 @@ test_write_before_open(void)
}
}
- /* Small delay so fdopen's tsc_base is measurably after the copies */
+ /* Small delay so the capture start is measurably after the copies */
rte_delay_us_block(100);
now = current_timestamp();
@@ -689,7 +689,7 @@ test_write_before_open(void)
goto fail;
}
- /* Write the pre-captured packets — timestamps precede tsc_base */
+ /* Write the pre-captured packets */
len = rte_pcapng_write_packets(pcapng, clones, count);
rte_pktmbuf_free_bulk(clones, count);
if (len <= 0) {
diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c
index df38e4819c..f910896a61 100644
--- a/lib/pcapng/rte_pcapng.c
+++ b/lib/pcapng/rte_pcapng.c
@@ -40,8 +40,7 @@
struct rte_pcapng {
int outfd; /* output file */
unsigned int ports; /* number of interfaces added */
- uint64_t offset_ns; /* ns since 1/1/1970 when initialized */
- uint64_t tsc_base; /* TSC when started */
+ uint64_t start_time; /* ns since 1/1/1970 when opened */
/* DPDK port id to interface index in file */
uint32_t port_index[RTE_MAX_ETHPORTS];
@@ -97,39 +96,6 @@ static ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
#define if_indextoname(ifindex, ifname) NULL
#endif
-/*
- * Convert a count of cycles to nanoseconds.
- *
- * Compute the whole seconds first, so that the remainder is always
- * less than the frequency and scaling it by NS_PER_S cannot wrap.
- */
-static uint64_t
-pcapng_cycles_to_ns(uint64_t delta)
-{
- const uint64_t hz = rte_get_tsc_hz();
- uint64_t secs = delta / hz;
- uint64_t rem = delta % hz;
-
- return secs * NS_PER_S + (rem * NS_PER_S) / hz;
-}
-
-/* Convert from TSC (CPU cycles) to nanoseconds */
-static uint64_t
-pcapng_timestamp(const rte_pcapng_t *self, uint64_t cycles)
-{
- /*
- * A packet may be copied before the file was opened, so the TSC
- * can be behind the reference point. Handle both directions on
- * an unsigned magnitude.
- */
- if (unlikely(cycles < self->tsc_base))
- return self->offset_ns -
- pcapng_cycles_to_ns(self->tsc_base - cycles);
-
- return self->offset_ns +
- pcapng_cycles_to_ns(cycles - self->tsc_base);
-}
-
/* length of option including padding */
static uint16_t pcapng_optlen(uint16_t len)
{
@@ -361,7 +327,7 @@ rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id,
{
struct pcapng_statistics *hdr;
struct pcapng_option *opt;
- uint64_t start_time = self->offset_ns;
+ uint64_t start_time = self->start_time;
uint64_t sample_time;
uint32_t optlen, len;
uint32_t *buf;
@@ -414,7 +380,7 @@ rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id,
hdr->block_length = len;
hdr->interface_id = self->port_index[port_id];
- sample_time = pcapng_timestamp(self, rte_get_tsc_cycles());
+ sample_time = rte_tsc_to_ns(rte_get_tsc_cycles());
hdr->timestamp_hi = sample_time >> 32;
hdr->timestamp_lo = (uint32_t)sample_time;
@@ -702,7 +668,7 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
/* adjust timestamp recorded in packet */
cycles = (uint64_t)epb->timestamp_hi << 32;
cycles += epb->timestamp_lo;
- timestamp = pcapng_timestamp(self, cycles);
+ timestamp = rte_tsc_to_ns(cycles);
epb->timestamp_hi = timestamp >> 32;
epb->timestamp_lo = (uint32_t)timestamp;
@@ -748,8 +714,6 @@ rte_pcapng_fdopen(int fd,
{
unsigned int i;
rte_pcapng_t *self;
- struct timespec ts;
- uint64_t cycles;
int ret;
if ((osname && strlen(osname) > PCAPNG_STR_MAX) ||
@@ -769,17 +733,13 @@ rte_pcapng_fdopen(int fd,
self->outfd = fd;
self->ports = 0;
- /* If Hz is zero, something is seriously broken. */
+ /* Timestamps come from the TSC; if Hz is zero it is unusable. */
if (rte_get_tsc_hz() == 0) {
rte_errno = ENODEV;
goto fail;
}
- /* record start time in ns since 1/1/1970 */
- cycles = rte_get_tsc_cycles();
- clock_gettime(CLOCK_REALTIME, &ts);
- self->tsc_base = (cycles + rte_get_tsc_cycles()) / 2;
- self->offset_ns = rte_timespec_to_ns(&ts);
+ self->start_time = rte_tsc_to_ns(rte_get_tsc_cycles());
for (i = 0; i < RTE_MAX_ETHPORTS; i++)
self->port_index[i] = UINT32_MAX;
--
2.53.0
next prev parent reply other threads:[~2026-10-20 17:57 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 14:38 [PATCH v3 1/1] pcapng: add user-supplied timestamp support Dawid Wesierski
2026-06-18 15:22 ` Stephen Hemminger
2026-06-18 16:45 ` Morten Brørup
2026-06-18 18:51 ` Stephen Hemminger
2026-06-23 14:10 ` [PATCH v4] " Dawid Wesierski
2026-06-23 13:53 ` Stephen Hemminger
2026-06-24 21:57 ` [PATCH v5] " Dawid Wesierski
2026-06-24 22:07 ` Stephen Hemminger
2026-06-24 22:17 ` Stephen Hemminger
2026-06-26 10:22 ` [v5] " Dawid Wesierski
2026-06-26 15:04 ` Stephen Hemminger
2026-06-29 9:37 ` [PATCH v6 1/1] " Dawid Wesierski
2026-06-29 16:50 ` Stephen Hemminger
2026-10-14 17:21 ` [PATCH v7] " Dawid Wesierski
2026-10-14 17:38 ` Stephen Hemminger
2026-10-20 15:22 ` Dawid Wesierski
2026-10-20 15:29 ` [PATCH v8] " Dawid Wesierski
2026-10-20 17:55 ` [PATCH 0/3] pcapng timestamp conversion and user-supplied timestamps Stephen Hemminger
2026-10-20 17:55 ` [PATCH 1/3] eal: add function to convert TSC to epoch time Stephen Hemminger
2026-10-20 17:55 ` Stephen Hemminger [this message]
2026-10-20 17:55 ` [PATCH 3/3] pcapng: add user-supplied timestamp support Stephen Hemminger
2026-10-21 2:56 ` [PATCH 0/3] pcapng timestamp conversion and user-supplied timestamps Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261020175732.1552406-3-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
--cc=reshma.pattan@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox