*
* Definitions and functions for I/O graph items
*
* Copied from gtk/io_stat.c, (c) 2002 Ronnie Sahlberg
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __IO_GRAPH_ITEM_H__
#define __IO_GRAPH_ITEM_H__
#include "cfile.h"
#include <wsutil/ws_assert.h>
#include <epan/epan_dissect.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
IOG_ITEM_UNIT_FIRST,
IOG_ITEM_UNIT_PACKETS = IOG_ITEM_UNIT_FIRST,
IOG_ITEM_UNIT_BYTES,
IOG_ITEM_UNIT_BITS,
IOG_ITEM_UNIT_CALC_SUM,
IOG_ITEM_UNIT_CALC_FRAMES,
IOG_ITEM_UNIT_CALC_FIELDS,
IOG_ITEM_UNIT_CALC_MAX,
IOG_ITEM_UNIT_CALC_MIN,
IOG_ITEM_UNIT_CALC_AVERAGE,
IOG_ITEM_UNIT_CALC_THROUGHPUT,
IOG_ITEM_UNIT_CALC_LOAD,
IOG_ITEM_UNIT_LAST = IOG_ITEM_UNIT_CALC_LOAD,
NUM_IOG_ITEM_UNITS
} io_graph_item_unit_t;
typedef struct _io_graph_item_t {
uint32_t frames;
uint64_t bytes;
uint64_t fields;
* 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.
*/
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;
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;
*
* @param items [in,out] Array containing the items to reset.
* @param count [in] The number of items in the array.
*/
static inline void
reset_io_graph_items(io_graph_item_t *items, size_t count, int hf_index _U_) {
io_graph_item_t *item;
size_t i;
for (i = 0; i < count; i++) {
item = &items[i];
item->frames = 0;
item->bytes = 0;
item->fields = 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);
#if 0
* 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
}
}
*
* It is up to the caller to determine if the return value is valid.
*
* @param [in] pinfo Packet of interest.
* @param [in] interval Time interval in microseconds
* @return Array index on success, -1 on failure.
*
* @note pinfo->rel_ts, and hence the index, is not affected by ignoring
* frames.
*/
int64_t get_io_graph_index(packet_info *pinfo, int interval);
*
* @param field_name [in] Header field name to check
* @param hf_index [out] Assigned the header field index corresponding to field_name if valid.
* Can be NULL.
* @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
* @return NULL if compatible, otherwise an error string. The string must
* be freed by the caller.
*/
GString *check_field_unit(const char *field_name, int *hf_index, io_graph_item_unit_t item_unit);
*
* @param items [in] Array containing the item to get.
* @param val_units [in] The type of unit to calculate. From IOG_ITEM_UNITS.
* @param idx [in] Index of the item to get.
* @param hf_index [in] Header field index for advanced statistics.
* @param cap_file [in] Capture file.
* @param interval [in] Timing interval in ms.
* @param cur_idx [in] Current index.
*/
double get_io_graph_item(const io_graph_item_t *items, io_graph_item_unit_t val_units, int idx, int hf_index, const capture_file *cap_file, int interval, int cur_idx);
*
* Frame and byte counts are always calculated. If edt is non-NULL advanced
* statistics are calculated using hfindex.
*
* @param items [in,out] Array containing the item to update.
* @param idx [in] Index of the item to update.
* @param pinfo [in] Packet containing update information.
* @param edt [in] Dissection information for advanced statistics. May be NULL.
* @param hf_index [in] Header field index for advanced statistics.
* @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
* @param interval [in] Timing interval in μs.
* @return true if the update was successful, otherwise false.
*/
static inline bool
update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_dissect_t *edt, int hf_index, int item_unit, uint32_t interval) {
io_graph_item_t *item = &items[idx];
if (item->first_frame_in_invl == 0) {
item->first_frame_in_invl = pinfo->num;
}
item->last_frame_in_invl = pinfo->num;
if (edt && hf_index >= 0) {
GPtrArray *gp;
unsigned i;
gp = proto_get_finfo_ptr_array(edt->tree, hf_index);
if (!gp) {
return false;
}
* value so set any min/max values accordingly. */
for (i=0; i < gp->len; i++) {
int64_t new_int64;
uint64_t new_uint64;
float new_float;
double new_double;
const nstime_t *new_time;
switch (proto_registrar_get_ftype(hf_index)) {
case FT_UINT8:
case FT_UINT16:
case FT_UINT24:
case FT_UINT32:
new_uint64 = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
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;
}
item->double_tot += (double)new_uint64;
item->fields++;
break;
case FT_INT8:
case FT_INT16:
case FT_INT24:
case FT_INT32:
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->max_frame_in_invl = pinfo->num;
}
if ((new_int64 < item->int_min) || (item->fields == 0)) {
item->int_min = new_int64;
item->min_frame_in_invl = pinfo->num;
}
item->double_tot += (double)new_int64;
item->fields++;
break;
case FT_UINT40:
case FT_UINT48:
case FT_UINT56:
case FT_UINT64:
new_uint64 = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
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;
}
item->double_tot += (double)new_uint64;
item->fields++;
break;
case FT_INT40:
case FT_INT48:
case FT_INT56:
case FT_INT64:
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->max_frame_in_invl = pinfo->num;
}
if ((new_int64 < item->int_min) || (item->fields == 0)) {
item->int_min = new_int64;
item->min_frame_in_invl = pinfo->num;
}
item->double_tot += (double)new_int64;
item->fields++;
break;
case FT_FLOAT:
new_float = (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
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;
}
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;
item->max_frame_in_invl = pinfo->num;
}
if ((new_double < item->double_min) || (item->fields == 0)) {
item->double_min = new_double;
item->min_frame_in_invl = pinfo->num;
}
item->double_tot += new_double;
item->fields++;
break;
case FT_RELATIVE_TIME:
new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
switch (item_unit) {
case IOG_ITEM_UNIT_CALC_LOAD:
{
uint64_t t, pt;
int j;
* Add the time this call spanned each interval according to
* its contribution to that interval.
* If the call time is negative (unlikely, requires both an
* out of order capture file plus retransmission), ignore.
*/
const nstime_t time_zero = NSTIME_INIT_ZERO;
if (nstime_cmp(new_time, &time_zero) < 0) {
break;
}
t = new_time->secs;
t = t * 1000000 + new_time->nsecs / 1000;
j = idx;
* Handle current interval
* This cannot be negative, because get_io_graph_index
* returns an invalid interval if so.
*/
pt = pinfo->rel_ts.secs * 1000000 + pinfo->rel_ts.nsecs / 1000;
pt = pt % interval;
if (pt > t) {
pt = t;
}
while (t) {
io_graph_item_t *load_item;
load_item = &items[j];
load_item->time_tot.nsecs += (int) (pt * 1000);
if (load_item->time_tot.nsecs > 1000000000) {
load_item->time_tot.secs++;
load_item->time_tot.nsecs -= 1000000000;
}
load_item->fields++;
if (j == 0) {
break;
}
j--;
t -= pt;
if (t > (uint64_t) interval) {
pt = (uint64_t) interval;
} else {
pt = t;
}
}
break;
}
default:
if ( (nstime_cmp(new_time, &item->time_max) > 0)
|| (item->fields == 0)) {
item->time_max = *new_time;
item->max_frame_in_invl = pinfo->num;
}
if ( (nstime_cmp(new_time, &item->time_min) < 0)
|| (item->fields == 0)) {
item->time_min = *new_time;
item->min_frame_in_invl = pinfo->num;
}
nstime_add(&item->time_tot, new_time);
item->fields++;
}
break;
default:
if ((item_unit == IOG_ITEM_UNIT_CALC_FRAMES) ||
(item_unit == IOG_ITEM_UNIT_CALC_FIELDS)) {
* It's not an integeresque type, but
* all we want to do is count it, so
* that's all right.
*/
item->fields++;
}
else {
* "Can't happen"; see the "check that the
* type is compatible" check in
* filter_callback().
*/
ws_assert_not_reached();
}
break;
}
}
}
item->frames++;
item->bytes += pinfo->fd->pkt_len;
return true;
}
#ifdef __cplusplus
}
#endif
#endif