diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-12-08 02:22:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-08 23:10:12 -0500 |
commit | 60d51134281fbeb352013d782a440fb338d31f01 (patch) | |
tree | 36df3a263cf024612e1c62c8210bfbfe2d67a0d3 /drivers/net | |
parent | 3421eecdee750bafc78b12ac25b3e980195265eb (diff) |
ixgbe: Fix TX stats accounting
Here is an updated version, because ixgbe_get_ethtool_stats()
needs to call dev_get_stats() or "ethtool -S" wont give
correct tx_bytes/tx_packets values.
Several cpus can update netdev->stats.tx_bytes & netdev->stats.tx_packets
in parallel. In this case, TX stats are under estimated and false sharing
takes place.
After a pktgen session sending exactly 200000000 packets :
# ifconfig fiber0 | grep TX
TX packets:198501982 errors:0 dropped:0 overruns:0 carrier:0
Multi queue devices should instead use txq->tx_bytes & txq->tx_packets
in their xmit() method (appropriate txq lock already held by caller, no
cache line miss), or use appropriate locking.
After patch, same pktgen session gives :
# ifconfig fiber0 | grep TX
TX packets:200000000 errors:0 dropped:0 overruns:0 carrier:0
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 20 |
2 files changed, 5 insertions, 16 deletions
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 06a9d18bbdbc..0bd49d3b9f65 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
@@ -990,6 +990,7 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, | |||
990 | char *p = NULL; | 990 | char *p = NULL; |
991 | 991 | ||
992 | ixgbe_update_stats(adapter); | 992 | ixgbe_update_stats(adapter); |
993 | dev_get_stats(netdev); | ||
993 | for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { | 994 | for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { |
994 | switch (ixgbe_gstrings_stats[i].type) { | 995 | switch (ixgbe_gstrings_stats[i].type) { |
995 | case NETDEV_STATS: | 996 | case NETDEV_STATS: |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 247ed2a24769..4374f441c426 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -435,8 +435,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, | |||
435 | tx_ring->total_packets += total_packets; | 435 | tx_ring->total_packets += total_packets; |
436 | tx_ring->stats.packets += total_packets; | 436 | tx_ring->stats.packets += total_packets; |
437 | tx_ring->stats.bytes += total_bytes; | 437 | tx_ring->stats.bytes += total_bytes; |
438 | netdev->stats.tx_bytes += total_bytes; | ||
439 | netdev->stats.tx_packets += total_packets; | ||
440 | return (count < tx_ring->work_limit); | 438 | return (count < tx_ring->work_limit); |
441 | } | 439 | } |
442 | 440 | ||
@@ -5327,6 +5325,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, | |||
5327 | { | 5325 | { |
5328 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | 5326 | struct ixgbe_adapter *adapter = netdev_priv(netdev); |
5329 | struct ixgbe_ring *tx_ring; | 5327 | struct ixgbe_ring *tx_ring; |
5328 | struct netdev_queue *txq; | ||
5330 | unsigned int first; | 5329 | unsigned int first; |
5331 | unsigned int tx_flags = 0; | 5330 | unsigned int tx_flags = 0; |
5332 | u8 hdr_len = 0; | 5331 | u8 hdr_len = 0; |
@@ -5424,6 +5423,9 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, | |||
5424 | tx_ring->atr_count = 0; | 5423 | tx_ring->atr_count = 0; |
5425 | } | 5424 | } |
5426 | } | 5425 | } |
5426 | txq = netdev_get_tx_queue(netdev, tx_ring->queue_index); | ||
5427 | txq->tx_bytes += skb->len; | ||
5428 | txq->tx_packets++; | ||
5427 | ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, | 5429 | ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, |
5428 | hdr_len); | 5430 | hdr_len); |
5429 | ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); | 5431 | ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); |
@@ -5438,19 +5440,6 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, | |||
5438 | } | 5440 | } |
5439 | 5441 | ||
5440 | /** | 5442 | /** |
5441 | * ixgbe_get_stats - Get System Network Statistics | ||
5442 | * @netdev: network interface device structure | ||
5443 | * | ||
5444 | * Returns the address of the device statistics structure. | ||
5445 | * The statistics are actually updated from the timer callback. | ||
5446 | **/ | ||
5447 | static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev) | ||
5448 | { | ||
5449 | /* only return the current stats */ | ||
5450 | return &netdev->stats; | ||
5451 | } | ||
5452 | |||
5453 | /** | ||
5454 | * ixgbe_set_mac - Change the Ethernet Address of the NIC | 5443 | * ixgbe_set_mac - Change the Ethernet Address of the NIC |
5455 | * @netdev: network interface device structure | 5444 | * @netdev: network interface device structure |
5456 | * @p: pointer to an address structure | 5445 | * @p: pointer to an address structure |
@@ -5580,7 +5569,6 @@ static const struct net_device_ops ixgbe_netdev_ops = { | |||
5580 | .ndo_stop = ixgbe_close, | 5569 | .ndo_stop = ixgbe_close, |
5581 | .ndo_start_xmit = ixgbe_xmit_frame, | 5570 | .ndo_start_xmit = ixgbe_xmit_frame, |
5582 | .ndo_select_queue = ixgbe_select_queue, | 5571 | .ndo_select_queue = ixgbe_select_queue, |
5583 | .ndo_get_stats = ixgbe_get_stats, | ||
5584 | .ndo_set_rx_mode = ixgbe_set_rx_mode, | 5572 | .ndo_set_rx_mode = ixgbe_set_rx_mode, |
5585 | .ndo_set_multicast_list = ixgbe_set_rx_mode, | 5573 | .ndo_set_multicast_list = ixgbe_set_rx_mode, |
5586 | .ndo_validate_addr = eth_validate_addr, | 5574 | .ndo_validate_addr = eth_validate_addr, |