blob: 5393f0d04154e2fdf33a9bbcaef14535311f964b [file] [log] [blame]
#include <linux/config.h> /* for CONFIG_NET_PROFILE */
#ifndef _NET_PROFILE_H_
#define _NET_PROFILE_H_ 1
#ifdef CONFIG_NET_PROFILE
#include <linux/types.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <asm/system.h>
#ifdef CONFIG_X86_TSC
#include <asm/msr.h>
#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