#include /* for CONFIG_NET_PROFILE */ #ifndef _NET_PROFILE_H_ #define _NET_PROFILE_H_ 1 #ifdef CONFIG_NET_PROFILE #include #include #include #include #ifdef CONFIG_X86_TSC #include #endif struct net_profile_slot { char id[16]; struct net_profile_slot *next; struct timeval entered; struct timeval accumulator; struct timeval irq; int hits; int active; int underflow; }; extern atomic_t net_profile_active; extern struct timeval net_profile_adjust; extern void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved); #ifdef CONFIG_X86_TSC static inline void net_profile_stamp(struct timeval *pstamp) { rdtsc(pstamp->tv_usec, pstamp->tv_sec); } static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { __asm__ __volatile__ ("subl %2,%0\n\t" "sbbl %3,%1\n\t" "addl %4,%0\n\t" "adcl %5,%1\n\t" "subl " SYMBOL_NAME_STR(net_profile_adjust) "+4,%0\n\t" "sbbl $0,%1\n\t" : "=r" (acc->tv_usec), "=r" (acc->tv_sec) : "g" (entered->tv_usec), "g" (entered->tv_sec), "g" (leaved->tv_usec), "g" (leaved->tv_sec), "0" (acc->tv_usec), "1" (acc->tv_sec)); } static inline void net_profile_sub(struct timeval *sub, struct timeval *acc) { __asm__ __volatile__ ("subl %2,%0\n\t" "sbbl %3,%1\n\t" : "=r" (acc->tv_usec), "=r" (acc->tv_sec) : "g" (sub->tv_usec), "g" (sub->tv_sec), "0" (acc->tv_usec), "1" (acc->tv_sec)); } static inline void net_profile_add(struct timeval *add, struct timeval *acc) { __asm__ __volatile__ ("addl %2,%0\n\t" "adcl %3,%1\n\t" : "=r" (acc->tv_usec), "=r" (acc->tv_sec) : "g" (add->tv_usec), "g" (add->tv_sec), "0" (acc->tv_usec), "1" (acc->tv_sec)); } #elif defined (__alpha__) extern __u32 alpha_lo; extern long alpha_hi; /* On alpha cycle counter has only 32 bits :-( :-( */ static inline void net_profile_stamp(struct timeval *pstamp) { __u32 result; __asm__ __volatile__ ("rpcc %0" : "r="(result)); if (result <= alpha_lo) alpha_hi++; alpha_lo = result; pstamp->tv_sec = alpha_hi; pstamp->tv_usec = alpha_lo; } static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { time_t usecs = acc->tv_usec + leaved->tv_usec - entered->tv_usec - net_profile_adjust.tv_usec; time_t secs = acc->tv_sec + leaved->tv_sec - entered->tv_sec; if (usecs >= 0x100000000L) { usecs -= 0x100000000L; secs++; } else if (usecs < -0x100000000L) { usecs += 0x200000000L; secs -= 2; } else if (usecs < 0) { usecs += 0x100000000L; secs--; } acc->tv_sec = secs; acc->tv_usec = usecs; } static inline void net_profile_sub(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec - entered->tv_usec; time_t secs = leaved->tv_sec - entered->tv_sec; if (usecs < 0) { usecs += 0x100000000L; secs--; } leaved->tv_sec = secs; leaved->tv_usec = usecs; } static inline void net_profile_add(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec + entered->tv_usec; time_t secs = leaved->tv_sec + entered->tv_sec; if (usecs >= 0x100000000L) { usecs -= 0x100000000L; secs++; } leaved->tv_sec = secs; leaved->tv_usec = usecs; } #else static inline void net_profile_stamp(struct timeval *pstamp) { /* Not "fast" counterpart! On architectures without cpu clock "fast" routine is absolutely useless in this situation. do_gettimeofday still says something on slow-slow-slow boxes, though it eats more cpu time than the subject of investigation :-) :-) */ do_gettimeofday(pstamp); } static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { time_t usecs = acc->tv_usec + leaved->tv_usec - entered->tv_usec - net_profile_adjust.tv_usec; time_t secs = acc->tv_sec + leaved->tv_sec - entered->tv_sec; if (usecs >= 1000000) { usecs -= 1000000; secs++; } else if (usecs < -1000000) { usecs += 2000000; secs -= 2; } else if (usecs < 0) { usecs += 1000000; secs--; } acc->tv_sec = secs; acc->tv_usec = usecs; } static inline void net_profile_sub(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec - entered->tv_usec; time_t secs = leaved->tv_sec - entered->tv_sec; if (usecs < 0) { usecs += 1000000; secs--; } leaved->tv_sec = secs; leaved->tv_usec = usecs; } static inline void net_profile_add(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec + entered->tv_usec; time_t secs = leaved->tv_sec + entered->tv_sec; if (usecs >= 1000000) { usecs -= 1000000; secs++; } leaved->tv_sec = secs; leaved->tv_usec = usecs; } #endif static inline void net_profile_enter(struct net_profile_slot *s) { unsigned long flags; save_flags(flags); cli(); if (s->active++ == 0) { net_profile_stamp(&s->entered); atomic_inc(&net_profile_active); } restore_flags(flags); } static inline void net_profile_leave_irq(struct net_profile_slot *s) { unsigned long flags; save_flags(flags); cli(); if (--s->active <= 0) { if (s->active == 0) { struct timeval curr_pstamp; net_profile_stamp(&curr_pstamp); net_profile_accumulate(&s->entered, &curr_pstamp, &s->accumulator); if (!atomic_dec_and_test(&net_profile_active)) net_profile_irq_adjust(&s->entered, &curr_pstamp); } else { s->underflow++; } } s->hits++; restore_flags(flags); } static inline void net_profile_leave(struct net_profile_slot *s) { unsigned long flags; save_flags(flags); cli(); if (--s->active <= 0) { if (s->active == 0) { struct timeval curr_pstamp; net_profile_stamp(&curr_pstamp); net_profile_accumulate(&s->entered, &curr_pstamp, &s->accumulator); atomic_dec(&net_profile_active); } else { s->underflow++; } } s->hits++; restore_flags(flags); } #define NET_PROFILE_ENTER(slot) net_profile_enter(&net_prof_##slot) #define NET_PROFILE_LEAVE(slot) net_profile_leave(&net_prof_##slot) #define NET_PROFILE_LEAVE_IRQ(slot) net_profile_leave_irq(&net_prof_##slot) #define NET_PROFILE_SKB_CLEAR(skb) ({ \ skb->pstamp.tv_usec = 0; \ }) #define NET_PROFILE_SKB_INIT(skb) ({ \ net_profile_stamp(&skb->pstamp); \ }) #define NET_PROFILE_SKB_PASSED(skb, slot) ({ \ if (skb->pstamp.tv_usec) { \ struct timeval cur_pstamp = skb->pstamp; \ net_profile_stamp(&skb->pstamp); \ net_profile_accumulate(&cur_pstamp, &skb->pstamp, &net_prof_##slot.accumulator); \ net_prof_##slot.hits++; \ }}) #define NET_PROFILE_DECL(slot) \ extern struct net_profile_slot net_prof_##slot; #define NET_PROFILE_DEFINE(slot) \ struct net_profile_slot net_prof_##slot = { #slot, }; #define NET_PROFILE_REGISTER(slot) net_profile_register(&net_prof_##slot) #define NET_PROFILE_UNREGISTER(slot) net_profile_unregister(&net_prof_##slot) extern int net_profile_init(void); extern int net_profile_register(struct net_profile_slot *); extern int net_profile_unregister(struct net_profile_slot *); #else #define NET_PROFILE_ENTER(slot) do { /* nothing */ } while(0) #define NET_PROFILE_LEAVE(slot) do { /* nothing */ } while(0) #define NET_PROFILE_LEAVE_IRQ(slot) do { /* nothing */ } while(0) #define NET_PROFILE_SKB_CLEAR(skb) do { /* nothing */ } while(0) #define NET_PROFILE_SKB_INIT(skb) do { /* nothing */ } while(0) #define NET_PROFILE_SKB_PASSED(skb, slot) do { /* nothing */ } while(0) #define NET_PROFILE_DECL(slot) #define NET_PROFILE_DEFINE(slot) #define NET_PROFILE_REGISTER(slot) do { /* nothing */ } while(0) #define NET_PROFILE_UNREGISTER(slot) do { /* nothing */ } while(0) #endif #endif