Hi David

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 <[EMAIL PROTECTED]>
--- linux-2.6.20/drivers/net/tg3.c.orig 2007-02-06 22:30:39.000000000 +0100
+++ linux-2.6.20-ed/drivers/net/tg3.c   2007-02-06 22:32:42.000000000 +0100
@@ -3384,7 +3384,7 @@
                }
 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) {

Reply via email to