Excellent !
This is problematic. softnet_data used to be only used by local cpu.
With RPS, other cpus are going to access csd, input_pkt_queue, backlog
and dirty cache lines.
Maybe we should split sofnet_data in two cache lines, one private,
one chared, and
DEFINE_PER_CPU(struct softnet_data, softnet_data);
->
DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
Also you need to change comment at start of struct softnet_data,
since it is wrong after RPS.
/*
* Incoming packets are placed on per-cpu queues so that
* no locking is needed.
*/
adding a __read_mostly here could help :)
If called from netif_receive_skb(), we already are in a rcu protected section,
but this could be a cleanup patch, because many other parts in stack could
be changed as well.
could reduce to :
percpu_add(netdev_rx_stat.total, 1);
spin_lock_irqsave(&queue->input_pkt_queue.lock, flags);
Is it legal (or wanter at all) to call napi_schedule_prep() on remote cpu backlog ?
Why not the more easy :
if (cpu != smp_processor_id())
cpu_set(cpu, get_cpu_var(rps_remote_softirq_cpus));
else
napi_schedule(&queue->backlog);
This way we dont touch to remote backlog (and this backlog could stay in the private
cache line of remote cpu)
->
spin_unlock_irqrestore(&queue->input_pkt_queue.lock, flags);
percpu_add(netdev_rx_stat.dropped, 1);
+/*
+ * net_rps_action sends any pending IPI's for rps. This is only called from
+ * softirq and interrupts must be enabled.
+ */
+static void net_rps_action(void)
+{
+ int cpu;
+
+ /* Send pending IPI's to kick RPS processing on remote cpus. */
+ for_each_cpu_mask_nr(cpu, __get_cpu_var(rps_remote_softirq_cpus)) {
+ struct softnet_data *queue = &per_cpu(softnet_data, cpu);
+ __smp_call_function_single(cpu, &queue->csd, 0);
+ }
+ cpus_clear(__get_cpu_var(rps_remote_softirq_cpus));
+}
net_rps_action() might be not very descriptive name and bit expensive...
Did you tried smp_call_function_many() ?
(I suspect you did, but found it was not that optimized ?)
CC Andi to get feedback from him :)
static void net_rps_remcpus_fire(void)
{
smp_call_function_many(__get_cpu_var(rps_remote_softirq_cpus),
trigger_softirq, NULL, 0);
}
Of course you would have to use following code as well :
(eg ignore void *data argument)
static void trigger_softirq(void *data)
{
/* kind of :
* __napi_schedule(__get_cpu_var(softnet_data).backlog);
* without local_irq_save(flags);/local_irq_restore(flags);
*/
list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list);
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
Thanks Herbert
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html