I/O Graphs: Squeeze some bytes out of io_graph_item_t
The min, max, and total members vary depending upon the hfinfo associated with the graph (or aren't used at all), so make them unions. We don't need separate float and double members; floats can be represented as doubles (and that's how we graph them anyway.) For the integer types, use doubles for the totals (as we've been doing; the integer total has been set but unused) because of possible overflow from summing many 64 bit integer fields. We only use the total when graphing (where it is converted to a double anyway, so we don't care about any lost precision for unsigned 64 bit integers larger than 2^53.) For the min and max use 64 bit integers because of that possible precision loss (so we always find the frame with the max and min value.) Have separate members for the min and max frame in the interval, so that we don't have to retap in order to find the max frame if we previously were looking for the min, and vice versa. (In practice, we were not retapping, so if we switched graph types the frame numbers were wrong.) This reduces sizeof(io_graph_item_t) from 152 bytes to 88 bytes on a system with 64 bit time_t. LOAD graphs still require retapping, since the value stored in item->time_tot for a LOAD graph is not the same as that stored in other graphs types. (Note however retapping doesn't occur when changing graph types, see above, and also LOAD graphs are broken since eb4e2cca69c5057995ff7.) We might want to add in some bytes later so that the value for LOAD graphs can be stored on the initial tap pass alongside the other values.
This commit is contained in:
parent
070a974b48
commit
350917786d
@ -4310,7 +4310,7 @@ sharkd_session_process_frame_cb(epan_dissect_t *edt, proto_tree *tree, struct ep
|
||||
sharkd_json_result_epilogue();
|
||||
}
|
||||
|
||||
#define SHARKD_IOGRAPH_MAX_ITEMS 250000 /* 250k limit of items is taken from wireshark-qt, on x86_64 sizeof(io_graph_item_t) is 152, so single graph can take max 36 MB */
|
||||
#define SHARKD_IOGRAPH_MAX_ITEMS 250000 /* 250k limit of items is taken from wireshark-qt, on x86_64 sizeof(io_graph_item_t) is 88, so single graph can take max 21 MB */
|
||||
|
||||
struct sharkd_iograph
|
||||
{
|
||||
@ -4344,14 +4344,14 @@ sharkd_iograph_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const vo
|
||||
int new_size = idx + 1024;
|
||||
|
||||
graph->items = (io_graph_item_t *) g_realloc(graph->items, sizeof(io_graph_item_t) * new_size);
|
||||
reset_io_graph_items(&graph->items[graph->space_items], new_size - graph->space_items);
|
||||
reset_io_graph_items(&graph->items[graph->space_items], new_size - graph->space_items, graph->hf_index);
|
||||
|
||||
graph->space_items = new_size;
|
||||
}
|
||||
else if (graph->items == NULL)
|
||||
{
|
||||
graph->items = g_new(io_graph_item_t, graph->space_items);
|
||||
reset_io_graph_items(graph->items, graph->space_items);
|
||||
reset_io_graph_items(graph->items, graph->space_items, graph->hf_index);
|
||||
}
|
||||
|
||||
graph->num_items = idx + 1;
|
||||
|
@ -179,24 +179,15 @@ double get_io_graph_item(const io_graph_item_t *items_, io_graph_item_unit_t val
|
||||
case FT_INT48:
|
||||
case FT_INT56:
|
||||
case FT_INT64:
|
||||
case FT_UINT8:
|
||||
case FT_UINT16:
|
||||
case FT_UINT24:
|
||||
case FT_UINT32:
|
||||
case FT_UINT40:
|
||||
case FT_UINT48:
|
||||
case FT_UINT56:
|
||||
case FT_UINT64:
|
||||
case FT_DOUBLE:
|
||||
switch (val_units_) {
|
||||
case IOG_ITEM_UNIT_CALC_SUM:
|
||||
value = item->double_tot;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MAX:
|
||||
value = item->double_max;
|
||||
value = item->int_max;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MIN:
|
||||
value = item->double_min;
|
||||
value = item->int_min;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_AVERAGE:
|
||||
if (item->fields) {
|
||||
@ -210,20 +201,51 @@ double get_io_graph_item(const io_graph_item_t *items_, io_graph_item_unit_t val
|
||||
}
|
||||
break;
|
||||
|
||||
case FT_FLOAT:
|
||||
case FT_UINT8:
|
||||
case FT_UINT16:
|
||||
case FT_UINT24:
|
||||
case FT_UINT32:
|
||||
case FT_UINT40:
|
||||
case FT_UINT48:
|
||||
case FT_UINT56:
|
||||
case FT_UINT64:
|
||||
switch (val_units_) {
|
||||
case IOG_ITEM_UNIT_CALC_SUM:
|
||||
value = item->float_tot;
|
||||
value = item->double_tot;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MAX:
|
||||
value = item->float_max;
|
||||
value = item->uint_max;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MIN:
|
||||
value = item->float_min;
|
||||
value = item->uint_min;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_AVERAGE:
|
||||
if (item->fields) {
|
||||
value = (double)item->float_tot / item->fields;
|
||||
value = item->double_tot / item->fields;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FT_DOUBLE:
|
||||
case FT_FLOAT:
|
||||
switch (val_units_) {
|
||||
case IOG_ITEM_UNIT_CALC_SUM:
|
||||
value = item->double_tot;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MAX:
|
||||
value = item->double_max;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_MIN:
|
||||
value = item->double_min;
|
||||
break;
|
||||
case IOG_ITEM_UNIT_CALC_AVERAGE:
|
||||
if (item->fields) {
|
||||
value = item->double_tot / item->fields;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
|
@ -41,24 +41,32 @@ typedef struct _io_graph_item_t {
|
||||
guint32 frames; /* always calculated, will hold number of frames*/
|
||||
guint64 bytes; /* always calculated, will hold number of bytes*/
|
||||
guint64 fields;
|
||||
gint64 int_max;
|
||||
gint64 int_min;
|
||||
gint64 int_tot;
|
||||
/* XXX - Why do we always use 64-bit ints but split floats between
|
||||
* gfloat and gdouble?
|
||||
/* We use a double for totals because of overflow. For min and max,
|
||||
* unsigned 64 bit integers larger than 2^53 cannot all be represented
|
||||
* in a double, and this is useful for determining the frame with the
|
||||
* min or max value, even though for plotting it will be converted to a
|
||||
* double.
|
||||
*/
|
||||
gfloat float_max;
|
||||
gfloat float_min;
|
||||
gfloat float_tot;
|
||||
gdouble double_max;
|
||||
gdouble double_min;
|
||||
gdouble double_tot;
|
||||
union {
|
||||
nstime_t time_max;
|
||||
double double_max;
|
||||
int64_t int_max;
|
||||
uint64_t uint_max;
|
||||
};
|
||||
union {
|
||||
nstime_t time_min;
|
||||
double double_min;
|
||||
int64_t int_min;
|
||||
uint64_t uint_min;
|
||||
};
|
||||
union {
|
||||
nstime_t time_tot;
|
||||
guint32 first_frame_in_invl;
|
||||
guint32 extreme_frame_in_invl; /* frame with min/max value */
|
||||
guint32 last_frame_in_invl;
|
||||
double double_tot;
|
||||
};
|
||||
uint32_t first_frame_in_invl;
|
||||
uint32_t min_frame_in_invl;
|
||||
uint32_t max_frame_in_invl;
|
||||
uint32_t last_frame_in_invl;
|
||||
} io_graph_item_t;
|
||||
|
||||
/** Reset (zero) an io_graph_item_t.
|
||||
@ -67,7 +75,7 @@ typedef struct _io_graph_item_t {
|
||||
* @param count [in] The number of items in the array.
|
||||
*/
|
||||
static inline void
|
||||
reset_io_graph_items(io_graph_item_t *items, gsize count) {
|
||||
reset_io_graph_items(io_graph_item_t *items, gsize count, int hf_index _U_) {
|
||||
io_graph_item_t *item;
|
||||
gsize i;
|
||||
|
||||
@ -77,21 +85,70 @@ reset_io_graph_items(io_graph_item_t *items, gsize count) {
|
||||
item->frames = 0;
|
||||
item->bytes = 0;
|
||||
item->fields = 0;
|
||||
item->int_max = 0;
|
||||
item->int_min = 0;
|
||||
item->int_tot = 0;
|
||||
item->float_max = 0;
|
||||
item->float_min = 0;
|
||||
item->float_tot = 0;
|
||||
item->double_max = 0;
|
||||
item->double_min = 0;
|
||||
item->double_tot = 0;
|
||||
item->first_frame_in_invl = 0;
|
||||
item->min_frame_in_invl = 0;
|
||||
item->max_frame_in_invl = 0;
|
||||
item->last_frame_in_invl = 0;
|
||||
|
||||
nstime_set_zero(&item->time_max);
|
||||
nstime_set_zero(&item->time_min);
|
||||
nstime_set_zero(&item->time_tot);
|
||||
item->first_frame_in_invl = 0;
|
||||
item->extreme_frame_in_invl = 0;
|
||||
item->last_frame_in_invl = 0;
|
||||
|
||||
#if 0
|
||||
/* XXX - On C, type punning is explicitly allowed since C99 so
|
||||
* setting the nstime_t values to 0 is always sufficient.
|
||||
* On C++ that appears technically to be undefined behavior (though
|
||||
* I don't know of any compilers for which it doesn't work and I
|
||||
* can't get UBSAN to complain about it) and this would be safer.
|
||||
*/
|
||||
if (hf_index > 0) {
|
||||
|
||||
switch (proto_registrar_get_ftype(hf_index)) {
|
||||
|
||||
case FT_INT8:
|
||||
case FT_INT16:
|
||||
case FT_INT24:
|
||||
case FT_INT32:
|
||||
case FT_INT40:
|
||||
case FT_INT48:
|
||||
case FT_INT56:
|
||||
case FT_INT64:
|
||||
item->int_max = 0;
|
||||
item->int_min = 0;
|
||||
item->double_tot = 0;
|
||||
break;
|
||||
|
||||
case FT_UINT8:
|
||||
case FT_UINT16:
|
||||
case FT_UINT24:
|
||||
case FT_UINT32:
|
||||
case FT_UINT40:
|
||||
case FT_UINT48:
|
||||
case FT_UINT56:
|
||||
case FT_UINT64:
|
||||
item->uint_max = 0;
|
||||
item->uint_min = 0;
|
||||
item->double_tot = 0;
|
||||
break;
|
||||
|
||||
case FT_DOUBLE:
|
||||
case FT_FLOAT:
|
||||
item->double_max = 0;
|
||||
item->double_min = 0;
|
||||
item->double_tot = 0;
|
||||
break;
|
||||
|
||||
case FT_RELATIVE_TIME:
|
||||
nstime_set_zero(&item->time_max);
|
||||
nstime_set_zero(&item->time_min);
|
||||
nstime_set_zero(&item->time_tot);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,21 +238,14 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
case FT_UINT32:
|
||||
new_uint64 = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
|
||||
|
||||
if ((new_uint64 > (guint64)item->int_max) || (item->fields == 0)) {
|
||||
item->int_max = new_uint64;
|
||||
item->double_max = (gdouble)new_uint64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
if ((new_uint64 > item->uint_max) || (item->fields == 0)) {
|
||||
item->uint_max = new_uint64;
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_uint64 < item->uint_min) || (item->fields == 0)) {
|
||||
item->uint_min = new_uint64;
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_uint64 < (guint64)item->int_min) || (item->fields == 0)) {
|
||||
item->int_min = new_uint64;
|
||||
item->double_min = (gdouble)new_uint64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
}
|
||||
item->int_tot += new_uint64;
|
||||
item->double_tot += (gdouble)new_uint64;
|
||||
item->fields++;
|
||||
break;
|
||||
@ -206,19 +256,12 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
new_int64 = fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
|
||||
if ((new_int64 > item->int_max) || (item->fields == 0)) {
|
||||
item->int_max = new_int64;
|
||||
item->double_max = (gdouble)new_int64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_int64 < item->int_min) || (item->fields == 0)) {
|
||||
item->int_min = new_int64;
|
||||
item->double_min = (gdouble)new_int64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
}
|
||||
item->int_tot += new_int64;
|
||||
item->double_tot += (gdouble)new_int64;
|
||||
item->fields++;
|
||||
break;
|
||||
@ -227,21 +270,14 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
case FT_UINT56:
|
||||
case FT_UINT64:
|
||||
new_uint64 = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
|
||||
if ((new_uint64 > (guint64)item->int_max) || (item->fields == 0)) {
|
||||
item->int_max = new_uint64;
|
||||
item->double_max = (gdouble)new_uint64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
if ((new_uint64 > item->uint_max) || (item->fields == 0)) {
|
||||
item->uint_max = new_uint64;
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_uint64 < item->uint_min) || (item->fields == 0)) {
|
||||
item->uint_min = new_uint64;
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_uint64 < (guint64)item->int_min) || (item->fields == 0)) {
|
||||
item->int_min = new_uint64;
|
||||
item->double_min = (gdouble)new_uint64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
}
|
||||
item->int_tot += new_uint64;
|
||||
item->double_tot += (gdouble)new_uint64;
|
||||
item->fields++;
|
||||
break;
|
||||
@ -252,52 +288,37 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
new_int64 = fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
|
||||
if ((new_int64 > item->int_max) || (item->fields == 0)) {
|
||||
item->int_max = new_int64;
|
||||
item->double_max = (gdouble)new_int64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_int64 < item->int_min) || (item->fields == 0)) {
|
||||
item->int_min = new_int64;
|
||||
item->double_min = (gdouble)new_int64;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
}
|
||||
item->int_tot += new_int64;
|
||||
item->double_tot += (gdouble)new_int64;
|
||||
item->fields++;
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
new_float = (gfloat)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
|
||||
if ((new_float > item->float_max) || (item->fields == 0)) {
|
||||
item->float_max = new_float;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
if ((new_float > item->double_max) || (item->fields == 0)) {
|
||||
item->double_max = new_float;
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_float < item->double_min) || (item->fields == 0)) {
|
||||
item->double_min = new_float;
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_float < item->float_min) || (item->fields == 0)) {
|
||||
item->float_min = new_float;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
}
|
||||
item->float_tot += new_float;
|
||||
item->double_tot += new_float;
|
||||
item->fields++;
|
||||
break;
|
||||
case FT_DOUBLE:
|
||||
new_double = fvalue_get_floating(((field_info *)gp->pdata[i])->value);
|
||||
if ((new_double > item->double_max) || (item->fields == 0)) {
|
||||
item->double_max = new_double;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ((new_double < item->double_min) || (item->fields == 0)) {
|
||||
item->double_min = new_double;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->double_tot += new_double;
|
||||
item->fields++;
|
||||
@ -311,8 +332,8 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
guint64 t, pt; /* time in us */
|
||||
int j;
|
||||
/*
|
||||
* Add the time this call spanned each interval according to its contribution
|
||||
* to that interval.
|
||||
* Add the time this call spanned each interval according to
|
||||
* its contribution to that interval.
|
||||
*/
|
||||
t = new_time->secs;
|
||||
t = t * 1000000 + new_time->nsecs / 1000;
|
||||
@ -354,18 +375,14 @@ update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_d
|
||||
&& (new_time->nsecs > item->time_max.nsecs))
|
||||
|| (item->fields == 0)) {
|
||||
item->time_max = *new_time;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->max_frame_in_invl = pinfo->num;
|
||||
}
|
||||
if ( (new_time->secs<item->time_min.secs)
|
||||
|| ( (new_time->secs == item->time_min.secs)
|
||||
&& (new_time->nsecs < item->time_min.nsecs))
|
||||
|| (item->fields == 0)) {
|
||||
item->time_min = *new_time;
|
||||
if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
|
||||
item->extreme_frame_in_invl = pinfo->num;
|
||||
}
|
||||
item->min_frame_in_invl = pinfo->num;
|
||||
}
|
||||
nstime_add(&item->time_tot, new_time);
|
||||
item->fields++;
|
||||
|
@ -2055,8 +2055,9 @@ int IOGraph::packetFromTime(double ts)
|
||||
if (idx >= 0 && idx <= cur_idx_) {
|
||||
switch (val_units_) {
|
||||
case IOG_ITEM_UNIT_CALC_MAX:
|
||||
return items_[idx].max_frame_in_invl;
|
||||
case IOG_ITEM_UNIT_CALC_MIN:
|
||||
return items_[idx].extreme_frame_in_invl;
|
||||
return items_[idx].min_frame_in_invl;
|
||||
default:
|
||||
return items_[idx].last_frame_in_invl;
|
||||
}
|
||||
@ -2067,7 +2068,9 @@ int IOGraph::packetFromTime(double ts)
|
||||
void IOGraph::clearAllData()
|
||||
{
|
||||
cur_idx_ = -1;
|
||||
reset_io_graph_items(&items_[0], items_.size());
|
||||
if (items_.size()) {
|
||||
reset_io_graph_items(&items_[0], items_.size(), hf_index_);
|
||||
}
|
||||
if (graph_) {
|
||||
graph_->data()->clear();
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ class QCPAxisTickerDateTime;
|
||||
// can span no more than 4.66 days, and if we decrease the minimum interval
|
||||
// size without increasing this it would decrease proportionately (e.g.
|
||||
// for 1 μs no more than 16.8 s.)
|
||||
// Each io_graph_item_t is 152 bytes on a LP64 system, so the max size
|
||||
// we'll attempt to allocate for the array of items is 2.375 GiB
|
||||
// Each io_graph_item_t is 88 bytes on a system with 64 bit time_t, so
|
||||
// the max size we'll attempt to allocate for the array of items is 1.375 GiB
|
||||
// (plus a tiny amount extra for the std::vector bookkeeping.)
|
||||
// 2^24 = 16777216
|
||||
const int max_io_items_ = 1 << 24;
|
||||
|
Loading…
x
Reference in New Issue
Block a user