summaryrefslogtreecommitdiff
path: root/ui/cli
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2012-02-29 05:49:18 +0000
committerAnders Broman <anders.broman@ericsson.com>2012-02-29 05:49:18 +0000
commit9bdde5216f3ec31d4a02329423708288c57329c3 (patch)
tree823253bfd29afda05b703f1d13b2e9d2adf4d0b2 /ui/cli
parentd4c21b21234be048c384756ce31f8b3326ba7ea2 (diff)
downloadwireshark-9bdde5216f3ec31d4a02329423708288c57329c3.tar.gz
From Cal Turney:io,stat LOAD error, comma field ignored, zero data intervals not displayed, enhanced output https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6883
svn path=/trunk/; revision=41231
Diffstat (limited to 'ui/cli')
-rw-r--r--ui/cli/tap-iostat.c1330
1 files changed, 805 insertions, 525 deletions
diff --git a/ui/cli/tap-iostat.c b/ui/cli/tap-iostat.c
index 1104edd6d6..d2976313b6 100644
--- a/ui/cli/tap-iostat.c
+++ b/ui/cli/tap-iostat.c
@@ -38,15 +38,9 @@
#include <epan/tap.h>
#include <epan/stat_cmd_args.h>
#include <epan/strutil.h>
+#include "globals.h"
-typedef struct _io_stat_t {
- gint64 interval; /* unit is us */
- guint32 num_items;
- struct _io_stat_item_t *items;
- const char **filters;
-} io_stat_t;
-
#define CALC_TYPE_FRAMES 0
#define CALC_TYPE_BYTES 1
#define CALC_TYPE_FRAMES_AND_BYTES 2
@@ -57,16 +51,46 @@ typedef struct _io_stat_t {
#define CALC_TYPE_AVG 7
#define CALC_TYPE_LOAD 8
+typedef struct {
+ const char *func_name;
+ int calc_type;
+} calc_type_ent_t;
+
+static calc_type_ent_t calc_type_table[] = {
+ { "FRAMES", CALC_TYPE_FRAMES },
+ { "BYTES", CALC_TYPE_BYTES },
+ { "FRAMES BYTES", CALC_TYPE_FRAMES_AND_BYTES },
+ { "COUNT", CALC_TYPE_COUNT },
+ { "SUM", CALC_TYPE_SUM },
+ { "MIN", CALC_TYPE_MIN },
+ { "MAX", CALC_TYPE_MAX },
+ { "AVG", CALC_TYPE_AVG },
+ { "LOAD", CALC_TYPE_LOAD },
+ { NULL, 0 }
+};
+
+typedef struct _io_stat_t {
+ gint64 interval; /* The user-specified time interval (us) */
+ guint invl_prec; /* Decimal precision of the time interval (1=10s, 2=100s etc) */
+ guint32 num_cols; /* The number of columns of statistics in the table */
+ struct _io_stat_item_t
+ *items; /* Each item is a single cell in the table */
+ const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */
+ guint64 *max_vals; /* The max value sans the decimal or nsecs portion in each stat column */
+ guint32 *max_frames; /* The max number of frames in each stat column */
+} io_stat_t;
+
typedef struct _io_stat_item_t {
io_stat_t *parent;
- struct _io_stat_item_t *next;
+ struct _io_stat_item_t *next;
struct _io_stat_item_t *prev;
- gint64 time; /* unit is us since start of capture */
- int calc_type;
+ gint64 time; /* Time since start of capture (us)*/
+ int calc_type; /* The statistic type */
+ int colnum; /* Column number of this stat (0 to n) */
int hf_index;
- guint64 frames;
- guint64 num;
- guint64 counter;
+ guint32 frames;
+ guint32 num; /* The sample size of a given statistic (only needed for AVG) */
+ guint64 counter; /* The accumulated data for the calculation of that statistic */
gfloat float_counter;
gdouble double_counter;
} io_stat_item_t;
@@ -76,62 +100,69 @@ typedef struct _io_stat_item_t {
static int
iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
{
- io_stat_item_t *mit = arg;
+ io_stat_t *parent;
+ io_stat_item_t *mit;
io_stat_item_t *it;
- gint64 current_time, ct;
- GPtrArray *gp;
+ gint64 relative_time, rt;
+ nstime_t *new_time;
+ GPtrArray *gp;
guint i;
+ int ftype;
+
+ mit = arg;
+ parent = mit->parent;
+ relative_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000;
- current_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000;
-
- /* the prev item before the main one is always the last interval we saw packets for */
- it=mit->prev;
+ /* The prev item before the main one is always the last interval we saw packets for */
+ it = mit->prev;
/* XXX for the time being, just ignore all frames that are in the past.
should be fixed in the future but hopefully it is uncommon */
- if(current_time<it->time){
+ if(relative_time < it->time){
return FALSE;
}
- /* we have moved into a new interval, we need to create a new struct */
- ct = current_time;
- while(ct >= (it->time + mit->parent->interval)){
- it->next=g_malloc(sizeof(io_stat_item_t));
- it->next->prev=it;
- it->next->next=NULL;
- it=it->next;
- mit->prev=it;
-
- it->time = it->prev->time + mit->parent->interval;
- it->frames = 0;
+ /* If we have moved into a new interval (row), create a new io_stat_item_t struct for every interval
+ * between the last struct and this one. If an item was not found in a previous interval, an empty
+ * struct will be created for it. */
+ rt = relative_time;
+ while (rt >= it->time + parent->interval) {
+ it->next = g_malloc(sizeof(io_stat_item_t));
+ it->next->prev = it;
+ it->next->next = NULL;
+ it = it->next;
+ mit->prev = it;
+
+ it->time = it->prev->time + parent->interval;
+ it->frames = 0;
it->counter = 0;
it->float_counter = 0;
it->double_counter = 0;
- it->num = 0;
- it->calc_type=it->prev->calc_type;
- it->hf_index=it->prev->hf_index;
+ it->num = 0;
+ it->calc_type = it->prev->calc_type;
+ it->hf_index = it->prev->hf_index;
+ it->colnum = it->prev->colnum;
}
- /* it will now give us the current structure to use to store the data in */
+ /* Store info in the current structure */
it->frames++;
- switch(it->calc_type){
- case CALC_TYPE_BYTES:
+ switch(it->calc_type) {
case CALC_TYPE_FRAMES:
+ case CALC_TYPE_BYTES:
case CALC_TYPE_FRAMES_AND_BYTES:
- it->counter+=pinfo->fd->pkt_len;
+ it->counter += pinfo->fd->pkt_len;
break;
case CALC_TYPE_COUNT:
gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
if(gp){
- it->counter+=gp->len;
+ it->counter += gp->len;
}
break;
case CALC_TYPE_SUM:
gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
if(gp){
guint64 val;
- nstime_t *new_time;
for(i=0;i<gp->len;i++){
switch(proto_registrar_get_ftype(it->hf_index)){
@@ -139,30 +170,31 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
case FT_UINT16:
case FT_UINT24:
case FT_UINT32:
- it->counter+=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter += fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
break;
case FT_UINT64:
- it->counter+=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ it->counter += fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
break;
case FT_INT8:
case FT_INT16:
case FT_INT24:
case FT_INT32:
- it->counter+=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter += fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
break;
case FT_INT64:
- it->counter+=(gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ it->counter += (gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
break;
case FT_FLOAT:
- it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ it->float_counter +=
+ (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
break;
case FT_DOUBLE:
- it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
break;
case FT_RELATIVE_TIME:
new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
- it->counter += val;
+ it->counter += val;
break;
}
}
@@ -171,31 +203,25 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
case CALC_TYPE_MIN:
gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
if(gp){
- int type;
guint64 val;
gfloat float_val;
gdouble double_val;
- nstime_t *new_time;
- type=proto_registrar_get_ftype(it->hf_index);
+ ftype=proto_registrar_get_ftype(it->hf_index);
for(i=0;i<gp->len;i++){
- switch(type){
+ switch(ftype){
case FT_UINT8:
case FT_UINT16:
case FT_UINT24:
case FT_UINT32:
- val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val<it->counter){
+ val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ if ((it->frames==1 && i==0) || (val < it->counter)) {
it->counter=val;
}
break;
case FT_UINT64:
- val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val<it->counter){
+ val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0) || (val < it->counter)){
it->counter=val;
}
break;
@@ -203,43 +229,33 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
case FT_INT16:
case FT_INT24:
case FT_INT32:
- val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if((gint32)val<(gint32)(it->counter)){
+ val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0) || ((gint32)val < (gint32)(it->counter))) {
it->counter=val;
}
break;
case FT_INT64:
- val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if((gint64)val<(gint64)(it->counter)){
+ val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0) || ((gint64)val < (gint64)(it->counter))) {
it->counter=val;
- }
+ }
break;
case FT_FLOAT:
float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->float_counter=float_val;
- } else if(float_val<it->float_counter){
+ if((it->frames==1)&&(i==0) || (float_val < it->float_counter)) {
it->float_counter=float_val;
}
break;
case FT_DOUBLE:
double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->double_counter=double_val;
- } else if(double_val<it->double_counter){
+ if((it->frames==1)&&(i==0) || (double_val < it->double_counter)) {
it->double_counter=double_val;
- }
+ }
break;
case FT_RELATIVE_TIME:
new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
- val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val<it->counter){
+ val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ if((it->frames==1)&&(i==0) || (val < it->counter)) {
it->counter=val;
}
break;
@@ -250,78 +266,55 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
case CALC_TYPE_MAX:
gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
if(gp){
- int type;
guint64 val;
gfloat float_val;
gdouble double_val;
- nstime_t *new_time;
- type=proto_registrar_get_ftype(it->hf_index);
+ ftype=proto_registrar_get_ftype(it->hf_index);
for(i=0;i<gp->len;i++){
- switch(type){
+ switch(ftype){
case FT_UINT8:
case FT_UINT16:
case FT_UINT24:
case FT_UINT32:
- val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val>it->counter){
+ val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ if(val > it->counter)
it->counter=val;
- }
break;
case FT_UINT64:
- val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val>it->counter){
+ val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if(val > it->counter)
it->counter=val;
- }
break;
case FT_INT8:
case FT_INT16:
case FT_INT24:
case FT_INT32:
- val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
+ val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ if((gint32)val > (gint32)it->counter)
it->counter=val;
- } else if((gint32)val>(gint32)(it->counter)){
- it->counter=val;
- }
break;
case FT_INT64:
- val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if((gint64)val>(gint64)(it->counter)){
+ val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if ((gint64)val > (gint64)it->counter)
it->counter=val;
- }
break;
case FT_FLOAT:
- float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->float_counter=float_val;
- } else if(float_val>it->float_counter){
- it->float_counter=float_val;
- }
+ float_val = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if(float_val > it->float_counter)
+ it->float_counter=float_val;
break;
case FT_DOUBLE:
- double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
- if((it->frames==1)&&(i==0)){
- it->double_counter=double_val;
- } else if(double_val>it->double_counter){
- it->double_counter=double_val;
- }
+ double_val = fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if(double_val > it->double_counter)
+ it->double_counter=double_val;
break;
case FT_RELATIVE_TIME:
- new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
- val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
- if((it->frames==1)&&(i==0)){
- it->counter=val;
- } else if(val>it->counter){
+ new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ if (val>it->counter)
it->counter=val;
- }
- break;
+ break;
}
}
}
@@ -329,416 +322,686 @@ iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *du
case CALC_TYPE_AVG:
gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
if(gp){
- int type;
guint64 val;
- nstime_t *new_time;
-
- type=proto_registrar_get_ftype(it->hf_index);
+
+ ftype=proto_registrar_get_ftype(it->hf_index);
for(i=0;i<gp->len;i++){
it->num++;
- switch(type){
+ switch(ftype) {
case FT_UINT8:
case FT_UINT16:
case FT_UINT24:
case FT_UINT32:
- val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
- it->counter+=val;
+ val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter += val;
break;
case FT_UINT64:
case FT_INT64:
- val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
- it->counter+=val;
+ val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ it->counter += val;
break;
case FT_INT8:
case FT_INT16:
case FT_INT24:
case FT_INT32:
- val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
- it->counter+=val;
+ val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter += val;
break;
case FT_FLOAT:
- it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ it->float_counter += (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
break;
case FT_DOUBLE:
- it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
break;
case FT_RELATIVE_TIME:
- new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
- val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
- it->counter+=val;
+ new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val = (guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ it->counter += val;
break;
}
}
}
break;
case CALC_TYPE_LOAD:
- gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
- if(gp){
- int type;
-
- type=proto_registrar_get_ftype(it->hf_index);
- if (type != FT_RELATIVE_TIME) {
+ gp = proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if (gp) {
+ ftype = proto_registrar_get_ftype(it->hf_index);
+ if (ftype != FT_RELATIVE_TIME) {
fprintf(stderr,
- "\ntshark: LOAD() is only supported for relative-time fiels such as smb.time\n"
- );
+ "\ntshark: LOAD() is only supported for relative-time fields such as smb.time\n");
exit(10);
}
for(i=0;i<gp->len;i++){
guint64 val;
int tival;
- nstime_t *new_time;
io_stat_item_t *pit;
- new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
- val=(guint64)(new_time->secs)*1000000 + new_time->nsecs/1000;
- tival = (int)(val % mit->parent->interval);
+ new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val = (guint64)(new_time->secs)*1000000 + new_time->nsecs/1000;
+ tival = (int)(val % parent->interval);
it->counter += tival;
val -= tival;
pit = it->prev;
while (val > 0) {
- if (val < (guint64)mit->parent->interval) {
+ if (val < (guint64)parent->interval) {
pit->counter += val;
val = 0;
break;
}
-
- pit->counter += mit->parent->interval;
- val -= mit->parent->interval;
+ pit->counter += parent->interval;
+ val -= parent->interval;
pit = pit->prev;
-
}
}
}
break;
}
+ /* Store the highest value for this item in order to determine the width of each stat column.
+ * For real numbers we only need to know its magnitude (the value to the left of the decimal point
+ * so round it up before storing it as an integer in max_vals. For AVG of RELATIVE_TIME fields,
+ * calc the average, round it to the next second and store the seconds. For all other calc types
+ * of RELATIVE_TIME fields, store the counters without modification.
+ * fields. */
+ switch(it->calc_type) {
+ case CALC_TYPE_FRAMES:
+ case CALC_TYPE_FRAMES_AND_BYTES:
+ parent->max_frames[it->colnum] =
+ max(parent->max_frames[it->colnum], (guint32) it->frames);
+ if (it->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], it->counter);
+
+ case CALC_TYPE_BYTES:
+ case CALC_TYPE_COUNT:
+ case CALC_TYPE_LOAD:
+ parent->max_vals[it->colnum] = max(parent->max_vals[it->colnum], it->counter);
+ break;
+ case CALC_TYPE_SUM:
+ case CALC_TYPE_MIN:
+ case CALC_TYPE_MAX:
+ switch(ftype) {
+ case FT_FLOAT:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], (guint64)(it->float_counter+0.5));
+ break;
+ case FT_DOUBLE:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum],(guint64)(it->double_counter+0.5));
+ break;
+ case FT_RELATIVE_TIME:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], it->counter);
+ break;
+ default:
+ /* UINT16-64 and INT8-64 */
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], it->counter);
+ break;
+ }
+ break;
+ case CALC_TYPE_AVG:
+ switch(ftype) {
+ case FT_FLOAT:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], (guint64)it->float_counter/it->num);
+ break;
+ case FT_DOUBLE:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum],(guint64)it->double_counter/it->num);
+ break;
+ case FT_RELATIVE_TIME:
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], ((it->counter/it->num) + 500000000) / NANOSECS_PER_SEC);
+ break;
+ default:
+ /* UINT16-64 and INT8-64 */
+ parent->max_vals[it->colnum] =
+ max(parent->max_vals[it->colnum], it->counter/it->num);
+ break;
+ }
+ }
+ return TRUE;
+}
- return TRUE;
+static int
+magnitude (guint64 val, int max_w)
+{
+ int i, mag=0;
+
+ for (i=0; i<max_w; i++) {
+ mag++;
+ if ((val /= 10)==0)
+ break;
+ }
+ return(mag);
}
static void
-iostat_draw(void *arg)
+printcenter (const char *label, int lenval, int numpad)
{
- io_stat_item_t *mit = arg;
- io_stat_t *iot;
- io_stat_item_t **items;
- guint64 *frames;
- guint64 *counters;
- gfloat *float_counters;
- gdouble *double_counters;
- guint64 *num;
- guint32 i;
- guint32 borderLen=68;
- gboolean more_items;
- gint64 t;
-
- iot=mit->parent;
+ int lenlab = (int)strlen(label), len;
+ char *spaces=" ", *spaces_s;
+
+ len = (int)strlen(spaces) - (((lenval-lenlab) / 2) + numpad);
+ if (len > 0 && len < 6)
+ spaces_s = &spaces[len];
+ if ((lenval-lenlab)%2==0) {
+ printf("%s%s%s|", spaces_s, label, spaces_s);
+ } else {
+ printf("%s%s%s|", spaces_s-1, label, spaces_s);
+ }
+}
- printf("\n");
+typedef struct {
+ int fr; /* Width of this FRAMES column sans padding and border chars */
+ int val; /* Width of this non-FRAMES column sans padding and border chars */
+} column_width;
- /* Display the table border */
- for(i=0;i<iot->num_items;i++){
- if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)
- borderLen+=17;
- }
- if(iot->interval!=G_MAXINT32)
- borderLen+=8;
- if(iot->num_items>3)
- borderLen+=(iot->num_items-3)*17;
- for(i=0;i<borderLen;i++){
- printf("=");
+static void
+iostat_draw(void *arg)
+{
+ guint32 num;
+ guint64 t, invl_end;
+ gint64 interval, duration;
+ int i, j, k, num_cols, num_rows, div, dur_secs, dur_mag, invl_mag, invl_prec, tabrow_w,
+ borderlen, invl_col_w, numpad=1, namelen, len_filt, type, maxfltr_w, ftype;
+ int fr_mag; /* The magnitude of the max frame number in this column */
+ int val_mag; /* The magnitude of the max value in this column */
+ gboolean last_row=FALSE;
+ char *spaces, *spaces_s, *filler_s=0, *val_mag_s=" ", *fr_mag_s=" ", **fmts, *fmt;
+ const char *filter;
+ gchar *dur_mag_s=" ", *invl_mag_s=" ", *invl_prec_s=" ", *invl_fmt, *full_fmt;
+ io_stat_item_t *mit=arg;
+ io_stat_t *iot;
+ io_stat_item_t **stat_cols, *item;
+ column_width *col_w;
+
+ iot = mit->parent;
+ num_cols = iot->num_cols;
+ col_w = g_malloc(sizeof(column_width) * num_cols);
+ fmts = g_malloc(sizeof(char *) * num_cols);
+ duration = (gint64)(cfile.elapsed_time.secs*1000000) + (cfile.elapsed_time.nsecs+500)/1000;
+
+ /* Store the pointer to each stat column */
+ stat_cols = g_malloc(sizeof(io_stat_item_t *) * num_cols);
+ for (j=0; j<num_cols; j++)
+ stat_cols[j] = &iot->items[j];
+
+ /* The following prevents gross inaccuracies when the user specifies an interval that is greater
+ * than the capture duration. */
+ if (iot->interval > duration || iot->interval==G_MAXINT32) {
+ interval = duration;
+ iot->interval = G_MAXINT32;
+ } else {
+ interval = iot->interval;
+ }
+
+ /* Calc the capture duration's magnitude (dur_mag) */
+ dur_secs = (int)duration/1000000;
+ dur_mag = magnitude((guint64)dur_secs, 5);
+ itoa(dur_mag, dur_mag_s, 10);
+
+ /* Calc the interval's magnitude */
+ invl_mag = magnitude((guint64)interval/1000000, 5);
+
+ /* Set or get the interval precision */
+ if (interval==duration) {
+ /*
+ * An interval arg of 0 or an interval size exceeding the capture duration was specified.
+ * Set the decimal precision of duration based on its magnitude. */
+ if (dur_mag >= 2)
+ invl_prec = 1;
+ else if (dur_mag==1)
+ invl_prec = 3;
+ else
+ invl_prec = 6;
+
+ borderlen = 30 + dur_mag + (invl_prec==0 ? 0 : invl_prec+1);
+ } else {
+ invl_prec = iot->invl_prec;
+ borderlen = 24 + invl_mag + (invl_prec==0 ? 0 : invl_prec+1);
+ }
+
+ /* Round the duration according to invl_prec */
+ div=1000000;
+ for (i=0; i<invl_prec; i++)
+ div /= 10;
+ duration = duration + (5*(div/10));
+ if (iot->interval==G_MAXINT32)
+ interval = duration;
+
+ /* Recalc the dur_mag in case rounding has increased its magnitude */
+ dur_secs = (int)duration/1000000;
+ dur_mag = magnitude((guint64)dur_secs, 5);
+
+ /* Calc the width of the time interval column (incl borders and padding). */
+ if (invl_prec==0)
+ invl_col_w = (2*dur_mag) + 8;
+ else
+ invl_col_w = (2*dur_mag) + (2*invl_prec) + 10;
+ invl_col_w = max(invl_col_w, 12);
+ borderlen = max(borderlen, invl_col_w);
+
+ /* Calc the total width of each row in the stats table and build the printf format string for each
+ * column based on its field type, width, and name length.
+ * NOTE: The magnitude of all types including float and double are stored in iot->max_vals which
+ * is an *integer*. */
+ tabrow_w = invl_col_w;
+ for (j=0; j<num_cols; j++) {
+ type = iot->items[j].calc_type;
+ if (type==CALC_TYPE_FRAMES_AND_BYTES) {
+ namelen = 5;
+ } else {
+ namelen = (int)strlen(calc_type_table[type].func_name);
+ }
+ if(type==CALC_TYPE_FRAMES
+ || type==CALC_TYPE_FRAMES_AND_BYTES) {
+
+ fr_mag = magnitude(iot->max_frames[j], 15);
+ fr_mag = max(6, fr_mag);
+ col_w[j].fr = fr_mag;
+ tabrow_w += col_w[j].fr + 3;
+ itoa(fr_mag, fr_mag_s, 10);
+
+ if (type==CALC_TYPE_FRAMES) {
+ fmt = g_strconcat(" %", fr_mag_s, "u |", '\0');
+ } else {
+ /* CALC_TYPE_FRAMES_AND_BYTES
+ */
+ val_mag = magnitude(iot->max_vals[j], 15);
+ val_mag = max(5, val_mag);
+ col_w[j].val = val_mag;
+ tabrow_w += (col_w[j].val + 3);
+ itoa(val_mag, val_mag_s, 10);
+ fmt = g_strconcat(" %", fr_mag_s, "u |", " %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0');
+ }
+ fmts[j] = fmt;
+ continue;
+ }
+ switch(type) {
+ case CALC_TYPE_BYTES:
+ case CALC_TYPE_COUNT:
+
+ val_mag = magnitude(iot->max_vals[j], 15);
+ val_mag = max(5, val_mag);
+ col_w[j].val = val_mag;
+ itoa(val_mag, val_mag_s, 10);
+ fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0');
+ break;
+
+ default:
+ ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
+ switch (ftype) {
+ case FT_FLOAT:
+ case FT_DOUBLE:
+ val_mag = magnitude(iot->max_vals[j], 15);
+ itoa(val_mag, val_mag_s, 10);
+ fmt = g_strconcat(" %", val_mag_s, ".6f |", '\0');
+ col_w[j].val = val_mag + 7;
+ break;
+ case FT_RELATIVE_TIME:
+ /* Convert FT_RELATIVE_TIME field to seconds
+ * CALC_TYPE_LOAD was already converted in iostat_packet() ) */
+ if (type==CALC_TYPE_LOAD) {
+ iot->max_vals[j] /= interval;
+ } else {
+ iot->max_vals[j] = (iot->max_vals[j] + 500000000) / NANOSECS_PER_SEC;
+ }
+ val_mag = magnitude(iot->max_vals[j], 15);
+ itoa(val_mag, val_mag_s, 10);
+ fmt = g_strconcat(" %", val_mag_s, "u.%06u |", '\0');
+ col_w[j].val = val_mag + 7;
+ break;
+
+ default:
+ val_mag = magnitude(iot->max_vals[j], 15);
+ val_mag = max(namelen, val_mag);
+ col_w[j].val = val_mag;
+ itoa(val_mag, val_mag_s, 10);
+
+ switch (ftype) {
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", '\0');
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "d |", '\0');
+ break;
+ }
+ } /* End of ftype switch */
+ } /* End of switch for calc type */
+ tabrow_w += col_w[j].val + 3;
+ fmts[j] = fmt;
+ } /* End of for loop (columns) */
+
+ borderlen = max(borderlen, tabrow_w);
+
+ /* Calc the max width of the list of filters. */
+ maxfltr_w = 0;
+ for(j=0; j<num_cols; j++) {
+ if (iot->filters[j]) {
+ k = (int)strlen(iot->filters[j]) + 11;
+ maxfltr_w = max(maxfltr_w, k);
+ } else {
+ maxfltr_w = max(maxfltr_w, 26);
+ }
+ }
+ /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table
+ * (which currently = borderlen); however, if the filter width exceeds the table width and the
+ * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102.
+ * The filters will wrap at the lesser of borderlen-2 and the last space in the filter.
+ * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10).
+ * XXX: A pref could be added to change the max width from the default size of 102. */
+ if (maxfltr_w > borderlen && borderlen < 102)
+ borderlen = min(maxfltr_w, 102);
+
+ /* Prevent double right border by adding a space */
+ if (borderlen-tabrow_w==1)
+ borderlen++;
+
+ /* Display the top border */
+ printf("\n");
+ for (i=0; i<borderlen; i++)
+ printf("=");
+
+ spaces = (char*) g_malloc(borderlen+1);
+ for (i=0; i<borderlen; i++)
+ spaces[i] = ' ';
+ spaces[borderlen] = '\0';
+
+ spaces_s = &spaces[16];
+ printf("\n| IO Statistics%s|\n", spaces_s);
+ spaces_s = &spaces[2];
+ printf("|%s|\n", spaces_s);
+
+ itoa(invl_mag, invl_mag_s, 10);
+ itoa(invl_prec, invl_prec_s, 10);
+ if (invl_prec > 0) {
+ itoa(invl_prec, invl_prec_s, 10);
+ invl_fmt = g_strconcat("%", invl_mag_s, "u.%0", invl_prec_s, "u", '\0');
+ if (interval==duration) {
+ full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs (dur)%s", '\0');
+ spaces_s = &spaces[30+invl_mag+invl_prec];
+ } else {
+ full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", '\0');
+ spaces_s = &spaces[24+invl_mag+invl_prec];
+ }
+ printf(full_fmt, (guint32)interval/1000000,
+ (guint32)((interval%1000000)/div), spaces_s);
+ } else {
+ invl_fmt = g_strconcat("%", invl_mag_s, "u", '\0');
+ full_fmt = g_strconcat("| Interval size: ", invl_fmt, " secs%s", '\0');
+ spaces_s = &spaces[23 + invl_mag];
+ printf(full_fmt, (guint32)interval/1000000, spaces_s);
+ }
+ g_free(invl_fmt);
+ g_free(full_fmt);
+
+ if (invl_prec > 0)
+ invl_fmt = g_strconcat("%", dur_mag_s, "u.%0", invl_prec_s, "u", '\0');
+ else
+ invl_fmt = g_strconcat("%", dur_mag_s, "u", '\0');
+
+ /* Display the list of filters and their column numbers vertically */
+ printf("|\n| Col");
+ for(j=0; j<num_cols; j++){
+ printf((j==0 ? "%2u: %s" : "| %2u: %s"), j+1);
+ if (!iot->filters[j] || (iot->filters[j]==0)) {
+ /*
+ * An empty (no filter) comma field was specified */
+ spaces_s = &spaces[16 + 10];
+ printf("Frames and bytes%s|\n", spaces_s);
+ } else {
+ filter = iot->filters[j];
+ len_filt = (int)strlen(filter);
+
+ /* If the width of the widest filter exceeds the width of the stat table, borderlen has
+ * been set to 102 bytes above and filters wider than 102 will wrap at 91 bytes. */
+ if (len_filt+11 <= borderlen) {
+ printf("%s", filter);
+ if (len_filt+11 <= borderlen) {
+ spaces_s = &spaces[len_filt + 10];
+ printf("%s", spaces_s);
+ }
+ printf("|\n");
+ } else {
+ gchar *sfilter1, *sfilter2;
+ const char *pos;
+ int len, next_start, max_w=borderlen-11;
+
+ do {
+ if (len_filt > max_w) {
+ sfilter1 = g_strndup(filter, max_w);
+ /*
+ * Find the pos of the last space in sfilter1. If a space is found, set
+ * sfilter2 to the string prior to that space, and print it; otherwise, wrap
+ * the filter at max_w. */
+ pos = strrchr(sfilter1, ' ');
+ if (pos) {
+ len = (int)(pos-sfilter1);
+ next_start = len+1;
+ } else {
+ len = (int)strlen(sfilter1);
+ next_start = len;
+ }
+ sfilter2 = g_strndup(sfilter1, len);
+ printf("%s%s|\n", sfilter2, &spaces[len+10]);
+ g_free(sfilter1);
+ g_free(sfilter2);
+
+ printf("| ");
+ filter = &filter[next_start];
+ len_filt = (int)strlen(filter);
+ } else {
+ printf("%s%s|\n", filter, &spaces[(strlen(filter))+10]);
+ break;
+ }
+ } while (1);
+ }
+ }
}
- printf("\n");
-
- printf("IO Statistics\n");
- if(iot->interval!=G_MAXINT32)
- printf("Interval: %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u secs\n",
- iot->interval/1000000, iot->interval%1000000);
-
- for(i=0;i<iot->num_items;i++){
- printf("Column #%u: %s\n",i,iot->filters[i]?iot->filters[i]:"");
+ printf("|-");
+ for(i=0;i<borderlen-3;i++){
+ printf("-");
}
- if(iot->interval==G_MAXINT32){
- printf(" |");
- } else {
- printf(" |");
+ printf("|\n");
+
+ /* Display spaces above "Interval (s)" label */
+ spaces_s = &spaces[borderlen-(invl_col_w-2)];
+ printf("|%s|", spaces_s);
+
+ /* Display column number headers */
+ for(j=0; j<num_cols; j++) {
+ item = stat_cols[j];
+ if(item->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
+ spaces_s = &spaces[borderlen - (col_w[j].fr + col_w[j].val)] - 3;
+ else if (item->calc_type==CALC_TYPE_FRAMES)
+ spaces_s = &spaces[borderlen - col_w[j].fr];
+ else
+ spaces_s = &spaces[borderlen - col_w[j].val];
+
+ printf("%-2u%s|", j+1, spaces_s);
}
- for(i=0;i<iot->num_items;i++){
- if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES){
- printf(" Column #%-2u |",i);
- } else {
- printf(" Column #%-2u |",i);
- }
+ if (tabrow_w < borderlen) {
+ filler_s = &spaces[tabrow_w+1];
+ printf("%s|", filler_s);
+ }
+
+ printf("\n| Interval");
+ spaces_s = &spaces[borderlen-(invl_col_w-11)];
+ printf("%s|", spaces_s);
+
+ /* Display the stat label in each column */
+ for(j=0; j<num_cols; j++) {
+ type = stat_cols[j]->calc_type;
+ if(type==CALC_TYPE_FRAMES) {
+ printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad);
+ } else if (type==CALC_TYPE_FRAMES_AND_BYTES) {
+ printcenter ("Frames", col_w[j].fr, numpad);
+ printcenter ("Bytes", col_w[j].val, numpad);
+ } else {
+ printcenter (calc_type_table[type].func_name, col_w[j].val, numpad);
+ }
}
- printf("\n");
+ if (filler_s > 0)
+ printf("%s|", filler_s);
+ printf("\n|-");
- if(iot->interval==G_MAXINT32) {
- printf("Time |");
- } else {
- printf("Time |");
- }
- for(i=0;i<iot->num_items;i++){
- switch(iot->items[i].calc_type){
- case CALC_TYPE_FRAMES:
- printf(" FRAMES |");
- break;
- case CALC_TYPE_BYTES:
- printf(" BYTES |");
- break;
- case CALC_TYPE_FRAMES_AND_BYTES:
- printf(" Frames | Bytes |");
- break;
- case CALC_TYPE_COUNT:
- printf(" COUNT |");
- break;
- case CALC_TYPE_SUM:
- printf(" SUM |");
- break;
- case CALC_TYPE_MIN:
- printf(" MIN |");
- break;
- case CALC_TYPE_MAX:
- printf(" MAX |");
- break;
- case CALC_TYPE_AVG:
- printf(" AVG |");
- break;
- case CALC_TYPE_LOAD:
- printf(" LOAD |");
- break;
- }
- }
- printf("\n");
+ for(i=0; i<tabrow_w-3; i++)
+ printf("-");
+ printf("|");
- items=g_malloc(sizeof(io_stat_item_t *)*iot->num_items);
- frames=g_malloc(sizeof(guint64)*iot->num_items);
- counters=g_malloc(sizeof(guint64)*iot->num_items);
- float_counters=g_malloc(sizeof(gfloat)*iot->num_items);
- double_counters=g_malloc(sizeof(gdouble)*iot->num_items);
- num=g_malloc(sizeof(guint64)*iot->num_items);
- /* preset all items at the first interval */
- for(i=0;i<iot->num_items;i++){
- items[i]=&iot->items[i];
- }
+ if (tabrow_w < borderlen)
+ printf("%s|", &spaces[tabrow_w+1]);
- /* loop the items until we run out of them all */
+ printf("\n");
t=0;
- do {
- more_items=FALSE;
- for(i=0;i<iot->num_items;i++){
- frames[i]=0;
- counters[i]=0;
- float_counters[i]=0;
- double_counters[i]=0;
- num[i]=0;
- }
- for(i=0;i<iot->num_items;i++){
- if(items[i] && (t>=(items[i]->time+iot->interval))){
- items[i]=items[i]->next;
- }
-
- if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){
- frames[i]=items[i]->frames;
- counters[i]=items[i]->counter;
- float_counters[i]=items[i]->float_counter;
- double_counters[i]=items[i]->double_counter;
- num[i]=items[i]->num;
- }
-
- if(items[i]){
- more_items=TRUE;
- }
- }
-
- if(more_items){
- if(iot->interval==G_MAXINT32) {
- printf("000.000- ");
- } else {
- printf("%04u.%06u-%04u.%06u ",
- (int)(t/1000000),(int)(t%1000000),
- (int)((t+iot->interval)/1000000),
- (int)((t+iot->interval)%1000000));
- }
- for(i=0;i<iot->num_items;i++){
- switch(iot->items[i].calc_type){
- case CALC_TYPE_FRAMES:
- printf(" %15" G_GINT64_MODIFIER "u ", frames[i]);
- break;
- case CALC_TYPE_BYTES:
- printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
- break;
- case CALC_TYPE_FRAMES_AND_BYTES:
- printf(" %15" G_GINT64_MODIFIER "u %15" G_GINT64_MODIFIER "u ", frames[i], counters[i]);
- break;
- case CALC_TYPE_COUNT:
- printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
- break;
- case CALC_TYPE_SUM:
- switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- case FT_UINT64:
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- case FT_INT64:
- printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
- break;
- case FT_FLOAT:
- printf(" %f ", float_counters[i]);
- break;
- case FT_DOUBLE:
- printf(" %f ", double_counters[i]);
- break;
- case FT_RELATIVE_TIME:
- counters[i] = (counters[i]+500)/1000;
- printf(" %8u.%06u ",
- (int)(counters[i]/1000000), (int)(counters[i]%1000000));
- break;
- }
- break;
- case CALC_TYPE_MIN:
- switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- case FT_UINT64:
- printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
- break;
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- case FT_INT64:
- printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
- break;
- case FT_FLOAT:
- printf(" %f ", float_counters[i]);
- break;
- case FT_DOUBLE:
- printf(" %f ", double_counters[i]);
- break;
- case FT_RELATIVE_TIME:
- counters[i]=(counters[i]+500)/1000;
- printf(" %8u.%06u ",
- (int)(counters[i]/1000000), (int)(counters[i]%1000000));
- break;
- }
- break;
- case CALC_TYPE_MAX:
- switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- case FT_UINT64:
- printf(" %15u ", (int)(counters[i]));
- break;
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- case FT_INT64:
- printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
- break;
- case FT_FLOAT:
- printf(" %f ", float_counters[i]);
- break;
- case FT_DOUBLE:
- printf(" %f ", double_counters[i]);
- break;
- case FT_RELATIVE_TIME:
- counters[i]=(counters[i]+500)/1000;
- printf(" %8u.%06u ",
- (int)(counters[i]/1000000), (int)(counters[i]%1000000));
- break;
- }
- break;
- case CALC_TYPE_AVG:
- if(num[i]==0){
- num[i]=1;
- }
- switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- case FT_UINT64:
- printf(" %15" G_GINT64_MODIFIER "u ", counters[i]/num[i]);
- break;
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- case FT_INT64:
- printf(" %15" G_GINT64_MODIFIER "d ", counters[i]/num[i]);
- break;
- case FT_FLOAT:
- printf(" %f ", float_counters[i]/num[i]);
- break;
- case FT_DOUBLE:
- printf(" %f ", double_counters[i]/num[i]);
- break;
- case FT_RELATIVE_TIME:
- counters[i]=((counters[i]/num[i])+500)/1000;
- printf(" %8u.%06u ",
- (int)(counters[i]/1000000), (int)(counters[i]%1000000));
- break;
- }
- break;
-
- case CALC_TYPE_LOAD:
- switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
- case FT_RELATIVE_TIME:
- printf("%8u.%06u ",
- (int)(counters[i]/iot->interval), (int)((counters[i]%iot->interval)*1000000/iot->interval));
- break;
- }
- break;
-
- }
- }
- printf("\n");
- }
-
- t+=iot->interval;
- } while(more_items);
-
- for(i=0;i<borderLen;i++){
+ full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", '\0');
+ num_rows = (int)(duration/interval) + (((duration%interval+500000)/1000000) > 0 ? 1 : 0);
+
+ /* Display the table values.
+ * The outer loop is for time interval rows and the inner loop is for stat column items.*/
+ for (i=0; i<num_rows; i++) {
+
+ if (i==num_rows-1)
+ last_row = TRUE;
+
+ /* Display the interval for this row */
+ if (!last_row) {
+ invl_end = t + interval;
+ } else {
+ invl_end = duration;
+ }
+ if (invl_prec==0) {
+ printf(full_fmt, (guint32)(t/1000000),
+ (guint32)(invl_end/1000000));
+ } else {
+ printf(full_fmt, (guint32)(t/1000000),
+ (guint32)(t%1000000) / div,
+ (guint32) (invl_end/1000000),
+ (guint32)((invl_end%1000000) / div));
+ }
+
+ /* Display all the stat values in this row */
+ for (j=0; j<num_cols; j++) {
+ /*
+ * Point to the list for this stat (column). */
+ item = stat_cols[j];
+ /*
+ * Point to the item in the current row (time interval i) within this list. */
+ for (k=0; k<i; k++)
+ if (item && item->next)
+ item = item->next;
+ else
+ item = NULL;
+ fmt = fmts[j];
+
+ if (item) {
+ switch(item->calc_type) {
+ case CALC_TYPE_FRAMES:
+ printf(fmt, item->frames);
+ break;
+ case CALC_TYPE_BYTES:
+ case CALC_TYPE_COUNT:
+ printf(fmt, item->counter);
+ break;
+ case CALC_TYPE_FRAMES_AND_BYTES:
+ printf(fmt, item->frames, item->counter);
+ break;
+
+ case CALC_TYPE_SUM:
+ case CALC_TYPE_MIN:
+ case CALC_TYPE_MAX:
+ ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
+ switch(ftype){
+ case FT_FLOAT:
+ printf(fmt, item->float_counter);
+ break;
+ case FT_DOUBLE:
+ printf(fmt, item->double_counter);
+ break;
+ case FT_RELATIVE_TIME:
+ item->counter = (item->counter + 500) / 1000;
+ printf(fmt, (int)(item->counter/1000000), (int)(item->counter%1000000));
+ break;
+ default:
+ printf(fmt, item->counter);
+ break;
+ }
+ break;
+
+ case CALC_TYPE_AVG:
+ num = item->num;
+ if(num==0)
+ num=1;
+ ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
+ switch(ftype){
+ case FT_FLOAT:
+ printf(fmt, item->float_counter/num);
+ break;
+ case FT_DOUBLE:
+ printf(fmt, item->double_counter/num);
+ break;
+ case FT_RELATIVE_TIME:
+ item->counter = ((item->counter/num) + 500) / 1000;
+ printf(fmt,
+ (int)(item->counter/1000000), (int)(item->counter%1000000));
+ break;
+ default:
+ printf(fmt, item->counter/num);
+ break;
+ }
+ break;
+
+ case CALC_TYPE_LOAD:
+ ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
+ switch(ftype){
+ case FT_RELATIVE_TIME:
+ if (!last_row) {
+ printf(fmt,
+ (int) (item->counter/interval),
+ (int)((item->counter%interval)*1000000 / interval));
+ } else {
+ printf(fmt,
+ (int) (item->counter/(invl_end-t)),
+ (int)((item->counter%(invl_end-t))*1000000 / (invl_end-t)));
+ }
+ break;
+ }
+ break;
+ }
+ if (last_row)
+ g_free(fmt);
+
+ } else {
+ printf(fmt, (guint64)0);
+ }
+ }
+ if (filler_s > 0)
+ printf("%s|", filler_s);
+ printf("\n");
+ t += interval;
+
+ }
+ for(i=0;i<borderlen;i++){
printf("=");
}
- printf("\n");
-
- g_free(items);
- g_free(frames);
- g_free(counters);
- g_free(float_counters);
- g_free(double_counters);
- g_free(num);
+ printf("\n");
+ g_free(invl_fmt);
+ g_free(col_w);
+ g_free(full_fmt);
+ g_free(spaces);
}
-typedef struct {
- const char *func_name;
- int calc_type;
-} calc_type_ent_t;
-
-static calc_type_ent_t calc_type_table[] = {
- { "FRAMES", CALC_TYPE_FRAMES },
- { "BYTES", CALC_TYPE_BYTES },
- { "COUNT", CALC_TYPE_COUNT },
- { "SUM", CALC_TYPE_SUM },
- { "MIN", CALC_TYPE_MIN },
- { "MAX", CALC_TYPE_MAX },
- { "AVG", CALC_TYPE_AVG },
- { "LOAD", CALC_TYPE_LOAD },
- { NULL, 0 }
-};
-
static void
register_io_tap(io_stat_t *io, int i, const char *filter)
{
@@ -758,6 +1021,7 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
io->items[i].frames=0;
io->items[i].counter=0;
io->items[i].num=0;
+
io->filters[i]=filter;
flt=filter;
@@ -767,18 +1031,20 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
namelen=strlen(calc_type_table[j].func_name);
if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
io->items[i].calc_type=calc_type_table[j].calc_type;
+ io->items[i].colnum = i;
if(*(filter+namelen)=='(') {
p=filter+namelen+1;
parenp=strchr(p, ')');
if(!parenp){
- fprintf(stderr, "\ntshark: Closing parenthesis missing from calculated expression.\n");
+ fprintf(stderr,
+ "\ntshark: Closing parenthesis missing from calculated expression.\n");
exit(10);
}
-
if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){
if(parenp!=p) {
- fprintf(stderr, "\ntshark: %s does require or allow a field name within the parens.\n",
+ fprintf(stderr,
+ "\ntshark: %s does not require or allow a field name within the parens.\n",
calc_type_table[j].func_name);
exit(10);
}
@@ -811,6 +1077,7 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
} else {
if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
flt="";
+ io->items[i].colnum = i;
}
}
if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES ||
@@ -873,7 +1140,8 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
*/
if(io->items[i].calc_type!=CALC_TYPE_COUNT){
fprintf(stderr,
- "\ntshark: %s doesn't have integral values, so %s(*) calculations are not supported on it.\n",
+ "\ntshark: %s doesn't have integral values, so %s(*) "
+ "calculations are not supported on it.\n",
field,
calc_type_table[j].func_name);
exit(10);
@@ -883,7 +1151,8 @@ register_io_tap(io_stat_t *io, int i, const char *filter)
g_free(field);
}
- error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL, iostat_packet, i?NULL:iostat_draw);
+ error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL,
+ iostat_packet, i?NULL:iostat_draw);
if(error_string){
g_free(io->items);
g_free(io);
@@ -898,80 +1167,91 @@ static void
iostat_init(const char *optarg, void* userdata _U_)
{
gdouble interval_float;
- gint64 interval;
- int idx=0;
+ guint32 idx=0, i;
io_stat_t *io;
- const char *filter=NULL;
-
- if(sscanf(optarg,"io,stat,%lf,%n",&interval_float,&idx)==1){
- if(idx){
- if(*(optarg+idx)==',')
- filter=optarg+idx+1;
- else
- filter=optarg+idx;
- } else {
- filter=NULL;
- }
- } else {
+ const char *filters=NULL, *str, *pos;
+
+ if (sscanf(optarg, "io,stat,%lf,%n", &interval_float, &idx)==0) {
fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
exit(1);
}
-
- /* if interval is 0, calculate statistics over the whole file
- * by setting the interval to G_MAXINT32
- */
- if(interval_float==0) {
- interval=G_MAXINT32;
+
+ io = g_malloc(sizeof(io_stat_t));
+
+ /* If interval is 0, calculate statistics over the whole file by setting the interval to
+ * G_MAXINT32 */
+ if (interval_float==0) {
+ io->interval = G_MAXINT32;
+ io->invl_prec = 0;
} else {
- /* make interval be number of us rounded to the nearest integer*/
- interval=(gint64)(interval_float*1000000.0+0.5);
+ /* Set interval to the number of us rounded to the nearest integer */
+ io->interval = (gint64)(interval_float*1000000.0+0.5);
+ /*
+ * Determine what interval precision the user has specified */
+ io->invl_prec = 6;
+ for (i=10; i<10000000; i*=10) {
+ if (io->interval%i > 0)
+ break;
+ io->invl_prec--;
+ }
}
-
- if(interval<1){
+ if (io->interval < 1){
fprintf(stderr,
"\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
exit(10);
}
- io=g_malloc(sizeof(io_stat_t));
- io->interval=interval;
- if((!filter)||(filter[0]==0)){
- io->num_items=1;
- io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
- io->filters=g_malloc(sizeof(char *)*io->num_items);
-
- register_io_tap(io, 0, NULL);
+ /* Find how many ',' separated filters we have */
+ io->num_cols = 1;
+
+ if (idx) {
+ filters = optarg + idx;
+ if (strlen(filters) > 0 ) {
+ str = filters;
+ while((str = strchr(str, ','))) {
+ io->num_cols++;
+ str++;
+ }
+ }
} else {
- const char *str,*pos;
- char *tmp;
- int i;
- /* find how many ',' separated filters we have */
- str=filter;
- io->num_items=1;
- while((str=strchr(str,','))){
- io->num_items++;
- str++;
- }
-
- io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
- io->filters=g_malloc(sizeof(char *)*io->num_items);
+ filters=NULL;
+ }
- /* for each filter, register a tap listener */
- i=0;
- str=filter;
- do{
- pos=strchr(str,',');
+ io->items = g_malloc(sizeof(io_stat_item_t) * io->num_cols);
+ io->filters = g_malloc(sizeof(char *) * io->num_cols);
+ io->max_vals = g_malloc(sizeof(guint64) * io->num_cols);
+ io->max_frames = g_malloc(sizeof(guint64) * io->num_cols);
+
+ for (i=0; i<io->num_cols; i++) {
+ io->max_vals[i] = 0;
+ io->max_frames[i] = 0;
+ }
+
+ /* Register a tap listener for each filter */
+ if((!filters) || (filters[0]==0)) {
+ register_io_tap(io, 0, NULL);
+ } else {
+ const char *filter;
+ i = 0;
+ str = filters;
+ do {
+ pos = strchr(str, ',');
if(pos==str){
register_io_tap(io, i, NULL);
- } else if(pos==NULL) {
- tmp=g_strdup(str);
- register_io_tap(io, i, tmp);
+ } else if (pos==NULL) {
+ str = g_strstrip((gchar*)str);
+ filter = g_strdup((gchar*)str);
+ if (*filter)
+ register_io_tap(io, i, filter);
+ else
+ register_io_tap(io, i, NULL);
} else {
- tmp=g_malloc((pos-str)+1);
- g_strlcpy(tmp,str,(pos-str)+1);
- register_io_tap(io, i, tmp);
+ filter = g_malloc((pos-str)+1);
+ g_strlcpy((gchar*)filter, str, (pos-str)+1);
+ filter = g_strstrip((gchar*)filter);
+ register_io_tap(io, i, filter);
}
- str=pos+1;
+ str = pos+1;
i++;
} while(pos);
}