diff --git a/Makefile b/Makefile index 8e7c811..194e821 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,12 @@ # Give the location of pcap.h here: CFLAGS += -I/usr/include/pcap +# CFLAGS += -pg -a # Give the location of libpcap here if it's not in one of the standard # directories: #LDFLAGS += -L/usr/local/lib +# LDFLAGS += -pg -a # PREFIX specifies the base directory for the installation. PREFIX = /usr/local @@ -33,9 +35,9 @@ LDFLAGS += -g LDLIBS += -lpcap -lpthread -lcurses -lm SRCS = iftop.c addr_hash.c hash.c ns_hash.c resolver.c ui.c util.c sorted_list.c\ - options.c serv_hash.c + options.c serv_hash.c threadprof.c HDRS = addr_hash.h hash.h iftop.h ns_hash.h resolver.h sorted_list.h ui.h options.h sll.h\ - serv_hash.h + serv_hash.h threadprof.h TXTS = README CHANGES INSTALL TODO iftop.8 COPYING SPECFILE = iftop.spec diff --git a/hash.c b/hash.c index be73dbf..540af8e 100644 --- a/hash.c +++ b/hash.c @@ -64,9 +64,7 @@ hash_status_enum hash_find(hash_type* hash_table, void* key, void **rec) { /******************************* * find node containing data * *******************************/ - int bucket = hash_table->hash(key); - - p = hash_table->table[bucket]; + p = hash_table->table[hash_table->hash(key)]; while (p && !hash_table->compare(p->key, key)) { p = p->next; diff --git a/iftop.c b/iftop.c index 4e6093d..6015a0a 100644 --- a/iftop.c +++ b/iftop.c @@ -25,6 +25,7 @@ #include "ui.h" #include "options.h" #include "sll.h" +#include "threadprof.h" unsigned char if_hw_addr[6]; /* ethernet address of interface. */ @@ -226,21 +227,21 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir) ht->last_write = history_pos; if(iptr->ip_src.s_addr == ap.src.s_addr) { ht->sent[history_pos] += len; - ht->total_sent += len; + ht->total_sent += len; } else { ht->recv[history_pos] += len; - ht->total_recv += len; + ht->total_recv += len; } if(direction == 0) { /* incoming */ history_totals.recv[history_pos] += ntohs(iptr->ip_len); - history_totals.total_recv += len; + history_totals.total_recv += len; } else { history_totals.sent[history_pos] += ntohs(iptr->ip_len); - history_totals.total_sent += len; + history_totals.total_sent += len; } } diff --git a/resolver.c b/resolver.c index 2815d48..e98cbf0 100644 --- a/resolver.c +++ b/resolver.c @@ -16,6 +16,8 @@ #include "ns_hash.h" #include "iftop.h" +#include "threadprof.h" + #define RESOLVE_QUEUE_LENGTH 20 struct in_addr resolve_queue[RESOLVE_QUEUE_LENGTH]; diff --git a/threadprof.c b/threadprof.c new file mode 100644 index 0000000..41006b4 --- /dev/null +++ b/threadprof.c @@ -0,0 +1,76 @@ +/* + * pthread_create wrapper for gprof compatibility + * + */ + +#include +#include + +#undef pthread_create + +typedef struct wrapper_s +{ + void * (*start_routine)(void *); + void * arg; + + pthread_mutex_t lock; + pthread_cond_t wait; + + struct itimerval itimer; + +} wrapper_t; + +static void * wrapper_routine(void *); + +/* Same prototype as pthread_create; use some #define magic to + * transparently replace it in other files */ +int gprof_pthread_create(pthread_t * thread, pthread_attr_t * attr, + void * (*start_routine)(void *), void * arg) +{ + wrapper_t wrapper_data; + int i_return; + + /* Initialize the wrapper structure */ + wrapper_data.start_routine = start_routine; + wrapper_data.arg = arg; + getitimer(ITIMER_PROF, &wrapper_data.itimer); + pthread_cond_init(&wrapper_data.wait, NULL); + pthread_mutex_init(&wrapper_data.lock, NULL); + pthread_mutex_lock(&wrapper_data.lock); + + /* The real pthread_create call */ + i_return = pthread_create(thread, attr, &wrapper_routine, + &wrapper_data); + + /* If the thread was successfully spawned, wait for the data + * to be released */ + if(i_return == 0) + { + pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock); + } + + pthread_mutex_unlock(&wrapper_data.lock); + pthread_mutex_destroy(&wrapper_data.lock); + pthread_cond_destroy(&wrapper_data.wait); + + return i_return; +} + +/* The wrapper function in charge for setting the itimer value */ +static void * wrapper_routine(void * data) +{ + /* Put user data in thread-local variables */ + void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine; + void * arg = ((wrapper_t*)data)->arg; + + /* Set the profile timer value */ + setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL); + + /* Tell the calling thread that we don't need its data anymore */ + pthread_mutex_lock(&((wrapper_t*)data)->lock); + pthread_cond_signal(&((wrapper_t*)data)->wait); + pthread_mutex_unlock(&((wrapper_t*)data)->lock); + + /* Call the real function */ + return start_routine(arg); +} diff --git a/threadprof.h b/threadprof.h new file mode 100644 index 0000000..0db89e2 --- /dev/null +++ b/threadprof.h @@ -0,0 +1,8 @@ +#ifdef PROFILING + +#define pthread_create(a, b, c, d) gprof_pthread_create(a, b, c, d) + +int gprof_pthread_create(pthread_t * thread, pthread_attr_t * attr, + void * (*start_routine)(void *), void * arg); + +#endif diff --git a/ui.c b/ui.c index a11cc0b..d630859 100644 --- a/ui.c +++ b/ui.c @@ -63,12 +63,18 @@ int screen_line_compare(void* a, void* b) { } void readable_size(float n, char* buf, int bsize, int ksize, int bytes) { - if(n >= 10 * ksize * ksize) { + if(n >= 100 * ksize * ksize) { + snprintf(buf, bsize, " %4.0f%s", n / (ksize * ksize), bytes ? "MB" : "M"); + } + else if(n >= 10 * ksize * ksize) { snprintf(buf, bsize, " %4.1f%s", n / (ksize * ksize), bytes ? "MB" : "M"); } if(n >= ksize * ksize) { snprintf(buf, bsize, " %4.2f%s", n / (ksize * ksize), bytes ? "MB" : "M" ); } + else if(n >= 100 * ksize) { + snprintf(buf, bsize, " %4.0f%s", n / ksize, bytes ? "KB" : "K" ); + } else if(n >= 10 * ksize) { snprintf(buf, bsize, " %4.1f%s", n / ksize, bytes ? "KB" : "K" ); } @@ -190,11 +196,46 @@ void screen_data_clear() { sorted_list_destroy(&screen_list); } -void analyse_data() { - hash_node_type* n = NULL; +void calculate_totals() { int i; - if(options.paused == 0) { + /** + * Calculate peaks and totals + */ + for(i = 0; i < HISTORY_LENGTH; i++) { + int j; + int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; + + for(j = 0; j < HISTORY_DIVISIONS; j++) { + if(i < history_divs[j]) { + totals.recv[j] += history_totals.recv[ii]; + totals.sent[j] += history_totals.sent[ii]; + } + } + + if(history_totals.recv[i] > peakrecv) { + peakrecv = history_totals.recv[i]; + } + if(history_totals.sent[i] > peaksent) { + peaksent = history_totals.sent[i]; + } + if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) { + peaktotal = history_totals.recv[i] + history_totals.sent[i]; + } + } +} + +void make_screen_list() { + hash_node_type* n = NULL; + while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { + sorted_list_insert(&screen_list, (host_pair_line*)n->rec); + } +} + +void analyse_data() { + hash_node_type* n = NULL; + + if(options.paused == 1) { return; } @@ -253,36 +294,11 @@ void analyse_data() { } - n = NULL; - while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { - sorted_list_insert(&screen_list, (host_pair_line*)n->rec); - } + make_screen_list(); + hash_delete_all(screen_hash); - /** - * Calculate peaks and totals - */ - for(i = 0; i < HISTORY_LENGTH; i++) { - int j; - int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; - - for(j = 0; j < HISTORY_DIVISIONS; j++) { - if(i < history_divs[j]) { - totals.recv[j] += history_totals.recv[ii]; - totals.sent[j] += history_totals.sent[ii]; - } - } - - if(history_totals.recv[i] > peakrecv) { - peakrecv = history_totals.recv[i]; - } - if(history_totals.sent[i] > peaksent) { - peaksent = history_totals.sent[i]; - } - if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) { - peaktotal = history_totals.recv[i] + history_totals.sent[i]; - } - } + calculate_totals(); }