From 6b31a515e3401685cdab2eeb6692f1a0f53f72ca Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2007 13:29:21 -0800 Subject: [PATCH] [TG3]: Avoid an expensive divide. During an oprofile session of linux-2.6.20 on a dual opteron system, I noticed an expensive divide was done in tg3_poll(). I am using gcc-4.1.1, so the following comment from drivers/net/tg3.c seems over-optimistic : /* Do not place this n-ring entries value into the tp struct itself, * we really want to expose these constants to GCC so that modulo et * al. operations are done with shifts and masks instead of with * hw multiply/modulo instructions. Another solution would be to * replace things like '% foo' with '& (foo - 1)'. */ #define TG3_RX_RCB_RING_SIZE(tp) \ ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024) Assembly code before patch : (oprofile results included) 6434 0.0088 :ffffffff803684b9: mov 0x6f0(%r15),%eax 587 8.0e-04 :ffffffff803684c0: and $0x40000,%eax 2170 0.0030 :ffffffff803684c5: cmp $0x1,%eax :ffffffff803684c8: lea 0x1(%r13),%eax :ffffffff803684cc: sbb %ecx,%ecx 2051 0.0028 :ffffffff803684ce: xor %edx,%edx :ffffffff803684d0: and $0x200,%ecx 20 2.7e-05 :ffffffff803684d6: add $0x200,%ecx 1986 0.0027 :ffffffff803684dc: div %ecx 103427 0.1410 :ffffffff803684de: cmp %edx,0xffffffffffffff7c(%rbp) Assembly code after the suggested patch : ffffffff803684b9: mov 0x6f0(%r15),%eax ffffffff803684c0: and $0x40000,%eax ffffffff803684c5: cmp $0x1,%eax ffffffff803684c8: sbb %eax,%eax ffffffff803684ca: inc %r13d ffffffff803684cd: and $0x200,%eax ffffffff803684d2: add $0x1ff,%eax ffffffff803684d7: and %eax,%r13d ffffffff803684da: cmp %r13d,0xffffffffffffff7c(%rbp) Signed-off-by: Eric Dumazet Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 135c0987deae..e136bae61970 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3380,7 +3380,7 @@ next_pkt: } next_pkt_nopost: sw_idx++; - sw_idx %= TG3_RX_RCB_RING_SIZE(tp); + sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1); /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { -- 2.39.5