aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2009-05-17 20:34:33 -0400
committerDavid S. Miller <davem@davemloft.net>2009-05-18 18:15:06 -0400
commit7004bf252c53da18f6b55103e0c92f777f846806 (patch)
tree29868ce170599fbed3471f53afe3a20f23fb31c3
parentba98898eb3fc07ee54566fcc3626354a44355acb (diff)
net: add tx_packets/tx_bytes/tx_dropped counters in struct netdev_queue
offsetof(struct net_device, features)=0x44 offsetof(struct net_device, stats.tx_packets)=0x54 offsetof(struct net_device, stats.tx_bytes)=0x5c offsetof(struct net_device, stats.tx_dropped)=0x6c Network drivers that touch dev->stats.tx_packets/stats.tx_bytes in their tx path can slow down SMP operations, since they dirty a cache line that should stay shared (dev->features is needed in rx and tx paths) We could move away stats field in net_device but it wont help that much. (Two cache lines dirtied in tx path, we can do one only) Better solution is to add tx_packets/tx_bytes/tx_dropped in struct netdev_queue because this structure is already touched in tx path and counters updates will then be free (no increase in size) Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/dev.c23
2 files changed, 23 insertions, 3 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index cd547d04a8ce..f8574e76b743 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -474,6 +474,9 @@ struct netdev_queue {
474 * please use this field instead of dev->trans_start 474 * please use this field instead of dev->trans_start
475 */ 475 */
476 unsigned long trans_start; 476 unsigned long trans_start;
477 unsigned long tx_bytes;
478 unsigned long tx_packets;
479 unsigned long tx_dropped;
477} ____cacheline_aligned_in_smp; 480} ____cacheline_aligned_in_smp;
478 481
479 482
diff --git a/net/core/dev.c b/net/core/dev.c
index 14dd725aaab7..6d3630d16271 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4943,13 +4943,30 @@ void netdev_run_todo(void)
4943 * the internal statistics structure is used. 4943 * the internal statistics structure is used.
4944 */ 4944 */
4945const struct net_device_stats *dev_get_stats(struct net_device *dev) 4945const struct net_device_stats *dev_get_stats(struct net_device *dev)
4946 { 4946{
4947 const struct net_device_ops *ops = dev->netdev_ops; 4947 const struct net_device_ops *ops = dev->netdev_ops;
4948 4948
4949 if (ops->ndo_get_stats) 4949 if (ops->ndo_get_stats)
4950 return ops->ndo_get_stats(dev); 4950 return ops->ndo_get_stats(dev);
4951 else 4951 else {
4952 return &dev->stats; 4952 unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
4953 struct net_device_stats *stats = &dev->stats;
4954 unsigned int i;
4955 struct netdev_queue *txq;
4956
4957 for (i = 0; i < dev->num_tx_queues; i++) {
4958 txq = netdev_get_tx_queue(dev, i);
4959 tx_bytes += txq->tx_bytes;
4960 tx_packets += txq->tx_packets;
4961 tx_dropped += txq->tx_dropped;
4962 }
4963 if (tx_bytes || tx_packets || tx_dropped) {
4964 stats->tx_bytes = tx_bytes;
4965 stats->tx_packets = tx_packets;
4966 stats->tx_dropped = tx_dropped;
4967 }
4968 return stats;
4969 }
4953} 4970}
4954EXPORT_SYMBOL(dev_get_stats); 4971EXPORT_SYMBOL(dev_get_stats);
4955 4972