/****************************************************************************** * bwm-ng process data * * * * Copyright (C) 2004 Volker Gropp (vgropp@pefra.de) * * * * for more info read README. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * *****************************************************************************/ #include "global_vars.h" #include "process.h" short show_iface(char *instr, char *searchstr,char iface_is_up); #if HAVE_GETTIMEOFDAY static inline long tvdiff(struct timeval newer, struct timeval older); float get_time_delay(int iface_num); #endif static inline ullong calc_new_values(ullong new, ullong old); t_iface_speed_stats convert2calced_values(t_iface_speed_stats new, t_iface_speed_stats old); t_iface_speed_stats convert2calced_disk_values(t_iface_speed_stats new, t_iface_speed_stats old); #if EXTENDED_STATS static inline void sub_avg_values(struct inouttotal_double *values,struct inouttotal_double data); static inline void add_avg_values(struct inouttotal_double *values,struct inouttotal_double data); static inline void save_avg_values(struct inouttotal_double *values,struct inouttotal_double *data,struct inout_long calced_stats,float multiplier); void save_avg(struct t_avg *avg,struct iface_speed_stats calced_stats,float multiplier); static inline void save_sum(struct inout_long *stats,struct inout_long new_stats_values); static inline void save_max(struct inouttotal_double *stats,struct inout_long calced_stats,float multiplier); #endif /* returns the whether to show the iface or not * if is in list return 1, if list is prefaced with ! or * name not found return 0 */ short show_iface(char *instr, char *searchstr,char iface_is_up) { int pos = 0,k,success_ret = 1; unsigned int i = 0; if (instr==NULL) return iface_is_up || (show_all_if==2); if (instr[0]=='%') { success_ret=!success_ret; i++; } k = strlen( searchstr ); for (;i<=strlen(instr);i++) { switch ( instr[i] ) { case 0: case ',': if ( k == pos && ! strncasecmp( &instr[i] - pos, searchstr, pos ) ) { return success_ret || (iface_is_up && show_all_if); } pos = 0; break; default: pos++; break; } } return !success_ret || (iface_is_up && show_all_if) || (show_all_if==2); } #if HAVE_GETTIMEOFDAY /* Returns: the time difference in milliseconds. */ static inline long tvdiff(struct timeval newer, struct timeval older) { return labs((newer.tv_sec-older.tv_sec)*1000+ (newer.tv_usec-older.tv_usec)/1000); } /* returns the milliseconds since old stat */ float get_time_delay(int iface_num) { struct timeval now; float ret; gettimeofday(&now,NULL); ret=(float)1000/tvdiff(now,if_stats[iface_num].time); if_stats[iface_num].time.tv_sec=now.tv_sec; if_stats[iface_num].time.tv_usec=now.tv_usec; return ret; } #endif /* basically new-old, but handles "overflow" of source aswell */ static inline ullong calc_new_values(ullong new, ullong old) { /* FIXME: WRAP_AROUND _might_ be wrong for libstatgrab, where the type is always long long */ return (new>=old) ? (ullong)(new-old) : (ullong)(( #ifdef HAVE_LIBKSTAT (input_method==KSTAT_IN) ? WRAP_32BIT : #endif WRAP_AROUND) -old)+new; } /* calc actual new-old values */ t_iface_speed_stats convert2calced_values(t_iface_speed_stats new, t_iface_speed_stats old) { t_iface_speed_stats calced_stats; calced_stats.errors.in=calc_new_values(new.errors.in,old.errors.in); calced_stats.errors.out=calc_new_values(new.errors.out,old.errors.out); calced_stats.packets.out=calc_new_values(new.packets.out,old.packets.out); calced_stats.packets.in=calc_new_values(new.packets.in,old.packets.in); calced_stats.bytes.out=calc_new_values(new.bytes.out,old.bytes.out); calced_stats.bytes.in=calc_new_values(new.bytes.in,old.bytes.in); return calced_stats; } /* calc actual new-old values */ t_iface_speed_stats convert2calced_disk_values(t_iface_speed_stats new, t_iface_speed_stats old) { t_iface_speed_stats calced_stats; calced_stats.bytes.out=calc_new_values(new.bytes.out,old.bytes.out); calced_stats.bytes.in=calc_new_values(new.bytes.in,old.bytes.in); /* needed for linux stats, read and write count */ calced_stats.packets.out=calc_new_values(new.packets.out,old.packets.out)*(calc_new_values(new.errors.out,old.errors.out)+1); calced_stats.packets.in=calc_new_values(new.packets.in,old.packets.in)*(calc_new_values(new.errors.in,old.errors.in)+1); calced_stats.errors.in=0; calced_stats.errors.out=0; return calced_stats; } #if EXTENDED_STATS /* sub old values from cached for avg stats */ static inline void sub_avg_values(struct inouttotal_double *values,struct inouttotal_double data) { values->in-=data.in; values->out-=data.out; values->total-=data.total; } static inline void add_avg_values(struct inouttotal_double *values,struct inouttotal_double data) { values->in+=data.in; values->out+=data.out; values->total+=data.total; } /* put new-old bytes in inout_long struct into a inouttotal_double struct * and add values to cached .value struct */ static inline void save_avg_values(struct inouttotal_double *values,struct inouttotal_double *data,struct inout_long calced_stats,float multiplier) { data->in=calced_stats.in*multiplier; data->out=calced_stats.out*multiplier; data->total=(calced_stats.in+calced_stats.out)*multiplier; add_avg_values(values,*data); } /* manages the list of values for avg * saves data in list * removes old entries * calculates the current value */ void save_avg(struct t_avg *avg,struct iface_speed_stats calced_stats,float multiplier) { struct double_list *list_p; if (avg->first==NULL) { /* first element */ avg->first=avg->last=(struct double_list *)malloc(sizeof(struct double_list)); /* init it to zero and NULL */ memset(avg->first,0,sizeof(struct double_list)); /* save data and add to cache */ save_avg_values(&avg->item_sum.bytes,&avg->first->data.bytes,calced_stats.bytes,multiplier); save_avg_values(&avg->item_sum.errors,&avg->first->data.errors,calced_stats.errors,multiplier); save_avg_values(&avg->item_sum.packets,&avg->first->data.packets,calced_stats.packets,multiplier); avg->items=1; } else { /* we already have a list */ avg->last->next=(struct double_list *)malloc(sizeof(struct double_list)); memset(avg->last->next,0,sizeof(struct double_list)); avg->last=avg->last->next; /* save data and add to cache */ save_avg_values(&avg->item_sum.bytes,&avg->last->data.bytes,calced_stats.bytes,multiplier); save_avg_values(&avg->item_sum.errors,&avg->last->data.errors,calced_stats.errors,multiplier); save_avg_values(&avg->item_sum.packets,&avg->last->data.packets,calced_stats.packets,multiplier); avg->items++; /* remove only entries if at least two items added, * else we might leave an empty list * avg->first has to be != NULL at this point (if in 2nd line of this function) */ while (avg->first->next!=NULL && avg->items > avg_length/delay) { /* list is full, remove first entry */ list_p=avg->first; avg->first=avg->first->next; /* sub values from cache */ sub_avg_values(&avg->item_sum.bytes,list_p->data.bytes); sub_avg_values(&avg->item_sum.errors,list_p->data.errors); sub_avg_values(&avg->item_sum.packets,list_p->data.packets); free(list_p); avg->items--; } } } /* add current in and out bytes to totals struct */ static inline void save_sum(struct inout_long *stats,struct inout_long new_stats_values) { stats->in+=new_stats_values.in; stats->out+=new_stats_values.out; } /* lookup old max values and save new if higher */ static inline void save_max(struct inouttotal_double *stats,struct inout_long calced_stats,float multiplier) { if (multiplier*calced_stats.in > stats->in) stats->in=multiplier*calced_stats.in; if (multiplier*calced_stats.out>stats->out) stats->out=multiplier*calced_stats.out; if (multiplier*(calced_stats.out+calced_stats.in)>stats->total) stats->total=multiplier*(calced_stats.in+calced_stats.out); } #endif void clean_down_ifaces(void) { #ifdef IOCTL int local_if_count; t_iface_stats *new_if_stats = NULL; int new_if_count = 0; for (local_if_count=0;local_if_count