From: Koen Vandeputte <koen.vandeputte@citymesh.com>
To: netdev@vger.kernel.org
Cc: quic_subashab@quicinc.com, quic_stranche@quicinc.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, dnlplm@gmail.com,
linux-kernel@vger.kernel.org,
Koen Vandeputte <koen.vandeputte@citymesh.com>
Subject: [PATCH net-next 1/4] net: rmnet: use fast monotonic time for tx aggregation
Date: Fri, 2 Oct 2026 16:35:26 +0200 [thread overview]
Message-ID: <20261002143529.3217189-2-koen.vandeputte@citymesh.com> (raw)
In-Reply-To: <20261002143529.3217189-1-koen.vandeputte@citymesh.com>
The rmnet egress aggregation logic currently relies on ktime_get_real_ts64()
to determine if the aggregation bypass time threshold has been reached.
Calling a wall-clock time function on the transmit hot path introduces
significant performance bottlenecks, causing cacheline bouncing and pipeline
stalls when processing high packet volumes. Furthermore, manipulating and
comparing struct timespec64 fields adds unnecessary branching overhead.
Since the driver only needs to measure elapsed time between consecutive
packets to evaluate the aggregation bypass condition, absolute wall-clock
time is not required.
Replace ktime_get_real_ts64() with ktime_get_mono_fast_ns(). This reads a
lockless, per-CPU timestamp directly in nanoseconds, returning a simple u64.
Update the aggregation state variables (agg_time and agg_last) in
struct rmnet_port to u64 accordingly.
This optimization significantly reduces CPU overhead, eliminates struct
timespec64 math, and provides a much faster, cache-friendly timekeeping
mechanism for high-throughput egress traffic.
Signed-off-by: Koen Vandeputte <koen.vandeputte@citymesh.com>
---
.../ethernet/qualcomm/rmnet/rmnet_config.h | 4 ++--
.../ethernet/qualcomm/rmnet/rmnet_map_data.c | 22 ++++++++++---------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 5adda0323dda..78c0289b6583 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -47,8 +47,8 @@ struct rmnet_port {
struct sk_buff *skbagg_tail;
int agg_state;
u8 agg_count;
- struct timespec64 agg_time;
- struct timespec64 agg_last;
+ u64 agg_time;
+ u64 agg_last;
struct hrtimer hrtimer;
struct work_struct agg_wq;
};
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 39d6d084e73f..2eafb1d969c1 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -536,7 +536,7 @@ static void reset_aggr_params(struct rmnet_port *port)
port->skbagg_head = NULL;
port->agg_count = 0;
port->agg_state = 0;
- memset(&port->agg_time, 0, sizeof(struct timespec64));
+ port->agg_time = 0;
}
static void rmnet_send_skb(struct rmnet_port *port, struct sk_buff *skb)
@@ -591,21 +591,23 @@ static enum hrtimer_restart rmnet_map_flush_tx_packet_queue(struct hrtimer *t)
unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port,
struct net_device *orig_dev)
{
- struct timespec64 diff, last;
+ u64 diff, last, now;
unsigned int len = skb->len;
struct sk_buff *agg_skb;
int size;
spin_lock_bh(&port->agg_lock);
- memcpy(&last, &port->agg_last, sizeof(struct timespec64));
- ktime_get_real_ts64(&port->agg_last);
+ last = port->agg_last;
+
+ now = ktime_get_mono_fast_ns();
+ port->agg_last = now;
if (!port->skbagg_head) {
/* Check to see if we should agg first. If the traffic is very
* sparse, don't aggregate.
*/
new_packet:
- diff = timespec64_sub(port->agg_last, last);
+ diff = now - last;
size = port->egress_agg_params.bytes - skb->len;
if (size < 0) {
@@ -614,8 +616,7 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
return 0;
}
- if (diff.tv_sec > 0 || diff.tv_nsec > RMNET_AGG_BYPASS_TIME_NSEC ||
- size == 0)
+ if (diff > RMNET_AGG_BYPASS_TIME_NSEC || size == 0)
goto no_aggr;
port->skbagg_head = skb_copy_expand(skb, 0, size, GFP_ATOMIC);
@@ -625,11 +626,12 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
dev_kfree_skb_any(skb);
port->skbagg_head->protocol = htons(ETH_P_MAP);
port->agg_count = 1;
- ktime_get_real_ts64(&port->agg_time);
+ port->agg_time = now;
skb_frag_list_init(port->skbagg_head);
goto schedule;
}
- diff = timespec64_sub(port->agg_last, port->agg_time);
+
+ diff = now - port->agg_time;
size = port->egress_agg_params.bytes - port->skbagg_head->len;
if (skb->len > size) {
@@ -653,7 +655,7 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
port->skbagg_tail = skb;
port->agg_count++;
- if (diff.tv_sec > 0 || diff.tv_nsec > port->egress_agg_params.time_nsec ||
+ if (diff > port->egress_agg_params.time_nsec ||
port->agg_count >= port->egress_agg_params.count ||
port->skbagg_head->len == port->egress_agg_params.bytes) {
agg_skb = port->skbagg_head;
--
2.43.0
next prev parent reply other threads:[~2026-10-02 14:35 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 14:35 [PATCH net-next 0/4] net: rmnet: optimize hot paths to alleviate CPU/memory bottlenecks Koen Vandeputte
2026-10-02 14:35 ` Koen Vandeputte [this message]
2026-10-06 15:00 ` [PATCH net-next 1/4] net: rmnet: use fast monotonic time for tx aggregation netdev-bot+sashiko
2026-10-02 14:35 ` [PATCH net-next 2/4] net: rmnet: optimize rx deaggregation memory allocation Koen Vandeputte
2026-10-06 15:00 ` netdev-bot+sashiko
2026-10-02 14:35 ` [PATCH net-next 3/4] net: rmnet: conditionally expand skb headroom in ingress handler Koen Vandeputte
2026-10-06 15:00 ` netdev-bot+sashiko
2026-10-02 14:35 ` [PATCH net-next 4/4] net: rmnet: optimize rx handler by replacing skb_linearize with pskb_may_pull Koen Vandeputte
2026-10-02 20:48 ` Sean Tranchetti
2026-10-06 9:58 ` Koen Vandeputte
2026-10-06 15:00 ` netdev-bot+sashiko
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=20261002143529.3217189-2-koen.vandeputte@citymesh.com \
--to=koen.vandeputte@citymesh.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=dnlplm@gmail.com \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=quic_stranche@quicinc.com \
--cc=quic_subashab@quicinc.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