attr_dissector_fn_t
[wireshark-sm.git] / ui / io_graph_item.h
blob2c9d66c0658cebe4bc80a3e9da82b487b32de39e
1 /** @file
3 * Definitions and functions for I/O graph items
5 * Copied from gtk/io_stat.c, (c) 2002 Ronnie Sahlberg
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #ifndef __IO_GRAPH_ITEM_H__
15 #define __IO_GRAPH_ITEM_H__
17 #include "cfile.h"
18 #include <wsutil/ws_assert.h>
20 #include <epan/epan_dissect.h>
22 #ifdef __cplusplus
23 extern "C" {
24 #endif /* __cplusplus */
26 typedef enum {
27 IOG_ITEM_UNIT_FIRST,
28 IOG_ITEM_UNIT_PACKETS = IOG_ITEM_UNIT_FIRST,
29 IOG_ITEM_UNIT_BYTES,
30 IOG_ITEM_UNIT_BITS,
31 IOG_ITEM_UNIT_CALC_SUM,
32 IOG_ITEM_UNIT_CALC_FRAMES,
33 IOG_ITEM_UNIT_CALC_FIELDS,
34 IOG_ITEM_UNIT_CALC_MAX,
35 IOG_ITEM_UNIT_CALC_MIN,
36 IOG_ITEM_UNIT_CALC_AVERAGE,
37 IOG_ITEM_UNIT_CALC_THROUGHPUT,
38 IOG_ITEM_UNIT_CALC_LOAD,
39 IOG_ITEM_UNIT_LAST = IOG_ITEM_UNIT_CALC_LOAD,
40 NUM_IOG_ITEM_UNITS
41 } io_graph_item_unit_t;
43 typedef struct _io_graph_item_t {
44 uint32_t frames; /* always calculated, will hold number of frames*/
45 uint64_t bytes; /* always calculated, will hold number of bytes*/
46 uint64_t fields;
47 /* We use a double for totals because of overflow. For min and max,
48 * unsigned 64 bit integers larger than 2^53 cannot all be represented
49 * in a double, and this is useful for determining the frame with the
50 * min or max value, even though for plotting it will be converted to a
51 * double.
53 union {
54 nstime_t time_max;
55 double double_max;
56 int64_t int_max;
57 uint64_t uint_max;
59 union {
60 nstime_t time_min;
61 double double_min;
62 int64_t int_min;
63 uint64_t uint_min;
65 union {
66 nstime_t time_tot;
67 double double_tot;
69 uint32_t first_frame_in_invl;
70 uint32_t min_frame_in_invl;
71 uint32_t max_frame_in_invl;
72 uint32_t last_frame_in_invl;
73 } io_graph_item_t;
75 /** Reset (zero) an io_graph_item_t.
77 * @param items [in,out] Array containing the items to reset.
78 * @param count [in] The number of items in the array.
80 static inline void
81 reset_io_graph_items(io_graph_item_t *items, size_t count, int hf_index _U_) {
82 io_graph_item_t *item;
83 size_t i;
85 for (i = 0; i < count; i++) {
86 item = &items[i];
88 item->frames = 0;
89 item->bytes = 0;
90 item->fields = 0;
91 item->first_frame_in_invl = 0;
92 item->min_frame_in_invl = 0;
93 item->max_frame_in_invl = 0;
94 item->last_frame_in_invl = 0;
96 nstime_set_zero(&item->time_max);
97 nstime_set_zero(&item->time_min);
98 nstime_set_zero(&item->time_tot);
100 #if 0
101 /* XXX - On C, type punning is explicitly allowed since C99 so
102 * setting the nstime_t values to 0 is always sufficient.
103 * On C++ that appears technically to be undefined behavior (though
104 * I don't know of any compilers for which it doesn't work and I
105 * can't get UBSAN to complain about it) and this would be safer.
107 if (hf_index > 0) {
109 switch (proto_registrar_get_ftype(hf_index)) {
111 case FT_INT8:
112 case FT_INT16:
113 case FT_INT24:
114 case FT_INT32:
115 case FT_INT40:
116 case FT_INT48:
117 case FT_INT56:
118 case FT_INT64:
119 item->int_max = 0;
120 item->int_min = 0;
121 item->double_tot = 0;
122 break;
124 case FT_UINT8:
125 case FT_UINT16:
126 case FT_UINT24:
127 case FT_UINT32:
128 case FT_UINT40:
129 case FT_UINT48:
130 case FT_UINT56:
131 case FT_UINT64:
132 item->uint_max = 0;
133 item->uint_min = 0;
134 item->double_tot = 0;
135 break;
137 case FT_DOUBLE:
138 case FT_FLOAT:
139 item->double_max = 0;
140 item->double_min = 0;
141 item->double_tot = 0;
142 break;
144 case FT_RELATIVE_TIME:
145 nstime_set_zero(&item->time_max);
146 nstime_set_zero(&item->time_min);
147 nstime_set_zero(&item->time_tot);
148 break;
150 default:
151 break;
154 #endif
158 /** Get the interval (array index) for a packet
160 * It is up to the caller to determine if the return value is valid.
162 * @param [in] pinfo Packet of interest.
163 * @param [in] interval Time interval in microseconds
164 * @return Array index on success, -1 on failure.
166 * @note pinfo->rel_ts, and hence the index, is not affected by ignoring
167 * frames, but is affected by time references. (Ignoring frames before
168 * a time reference can be useful, though.)
170 int64_t get_io_graph_index(packet_info *pinfo, int interval);
172 /** Check field and item unit compatibility
174 * @param field_name [in] Header field name to check
175 * @param hf_index [out] Assigned the header field index corresponding to field_name if valid.
176 * Can be NULL.
177 * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
178 * @return NULL if compatible, otherwise an error string. The string must
179 * be freed by the caller.
181 GString *check_field_unit(const char *field_name, int *hf_index, io_graph_item_unit_t item_unit);
183 /** Get the value at the given interval (idx) for the current value unit.
185 * @param items [in] Array containing the item to get.
186 * @param val_units [in] The type of unit to calculate. From IOG_ITEM_UNITS.
187 * @param idx [in] Index of the item to get.
188 * @param hf_index [in] Header field index for advanced statistics.
189 * @param cap_file [in] Capture file.
190 * @param interval [in] Timing interval in ms.
191 * @param cur_idx [in] Current index.
192 * @param asAOT [in] Interpret when possible the value as an Average Over Time.
194 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, bool asAOT);
196 /** Update the values of an io_graph_item_t.
198 * Frame and byte counts are always calculated. If edt is non-NULL advanced
199 * statistics are calculated using hfindex.
201 * @param items [in,out] Array containing the item to update.
202 * @param idx [in] Index of the item to update.
203 * @param pinfo [in] Packet containing update information.
204 * @param edt [in] Dissection information for advanced statistics. May be NULL.
205 * @param hf_index [in] Header field index for advanced statistics.
206 * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
207 * @param interval [in] Timing interval in μs.
208 * @return true if the update was successful, otherwise false.
210 static inline bool
211 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) {
212 io_graph_item_t *item = &items[idx];
214 /* Set the first and last frame num in current interval matching the target field+filter */
215 if (item->first_frame_in_invl == 0) {
216 item->first_frame_in_invl = pinfo->num;
218 item->last_frame_in_invl = pinfo->num;
220 if (edt && hf_index >= 0) {
221 GPtrArray *gp;
222 unsigned i;
224 gp = proto_get_finfo_ptr_array(edt->tree, hf_index);
225 if (!gp) {
226 return false;
229 /* Update the appropriate counters. If fields == 0, this is the first seen
230 * value so set any min/max values accordingly. */
231 for (i=0; i < gp->len; i++) {
232 int64_t new_int64;
233 uint64_t new_uint64;
234 float new_float;
235 double new_double;
236 const nstime_t *new_time;
238 switch (proto_registrar_get_ftype(hf_index)) {
239 case FT_UINT8:
240 case FT_UINT16:
241 case FT_UINT24:
242 case FT_UINT32:
243 new_uint64 = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
245 if ((new_uint64 > item->uint_max) || (item->fields == 0)) {
246 item->uint_max = new_uint64;
247 item->max_frame_in_invl = pinfo->num;
249 if ((new_uint64 < item->uint_min) || (item->fields == 0)) {
250 item->uint_min = new_uint64;
251 item->min_frame_in_invl = pinfo->num;
253 item->double_tot += (double)new_uint64;
254 item->fields++;
255 break;
256 case FT_INT8:
257 case FT_INT16:
258 case FT_INT24:
259 case FT_INT32:
260 new_int64 = fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
261 if ((new_int64 > item->int_max) || (item->fields == 0)) {
262 item->int_max = new_int64;
263 item->max_frame_in_invl = pinfo->num;
265 if ((new_int64 < item->int_min) || (item->fields == 0)) {
266 item->int_min = new_int64;
267 item->min_frame_in_invl = pinfo->num;
269 item->double_tot += (double)new_int64;
270 item->fields++;
271 break;
272 case FT_UINT40:
273 case FT_UINT48:
274 case FT_UINT56:
275 case FT_UINT64:
276 new_uint64 = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
277 if ((new_uint64 > item->uint_max) || (item->fields == 0)) {
278 item->uint_max = new_uint64;
279 item->max_frame_in_invl = pinfo->num;
281 if ((new_uint64 < item->uint_min) || (item->fields == 0)) {
282 item->uint_min = new_uint64;
283 item->min_frame_in_invl = pinfo->num;
285 item->double_tot += (double)new_uint64;
286 item->fields++;
287 break;
288 case FT_INT40:
289 case FT_INT48:
290 case FT_INT56:
291 case FT_INT64:
292 new_int64 = fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
293 if ((new_int64 > item->int_max) || (item->fields == 0)) {
294 item->int_max = new_int64;
295 item->max_frame_in_invl = pinfo->num;
297 if ((new_int64 < item->int_min) || (item->fields == 0)) {
298 item->int_min = new_int64;
299 item->min_frame_in_invl = pinfo->num;
301 item->double_tot += (double)new_int64;
302 item->fields++;
303 break;
304 case FT_FLOAT:
305 new_float = (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
306 if ((new_float > item->double_max) || (item->fields == 0)) {
307 item->double_max = new_float;
308 item->max_frame_in_invl = pinfo->num;
310 if ((new_float < item->double_min) || (item->fields == 0)) {
311 item->double_min = new_float;
312 item->min_frame_in_invl = pinfo->num;
314 item->double_tot += new_float;
315 item->fields++;
316 break;
317 case FT_DOUBLE:
318 new_double = fvalue_get_floating(((field_info *)gp->pdata[i])->value);
319 if ((new_double > item->double_max) || (item->fields == 0)) {
320 item->double_max = new_double;
321 item->max_frame_in_invl = pinfo->num;
323 if ((new_double < item->double_min) || (item->fields == 0)) {
324 item->double_min = new_double;
325 item->min_frame_in_invl = pinfo->num;
327 item->double_tot += new_double;
328 item->fields++;
329 break;
330 case FT_RELATIVE_TIME:
331 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
333 switch (item_unit) {
334 case IOG_ITEM_UNIT_CALC_LOAD:
336 uint64_t t, pt; /* time in us */
337 int j;
339 * Add the time this call spanned each interval according to
340 * its contribution to that interval.
341 * If the call time is negative (unlikely, requires both an
342 * out of order capture file plus retransmission), ignore.
344 const nstime_t time_zero = NSTIME_INIT_ZERO;
345 if (nstime_cmp(new_time, &time_zero) < 0) {
346 break;
348 t = new_time->secs;
349 t = t * 1000000 + new_time->nsecs / 1000;
350 j = idx;
352 * Handle current interval
353 * This cannot be negative, because get_io_graph_index
354 * returns an invalid interval if so.
356 pt = pinfo->rel_ts.secs * 1000000 + pinfo->rel_ts.nsecs / 1000;
357 pt = pt % interval;
358 if (pt > t) {
359 pt = t;
361 while (t) {
362 io_graph_item_t *load_item;
364 load_item = &items[j];
365 load_item->time_tot.nsecs += (int) (pt * 1000);
366 if (load_item->time_tot.nsecs > 1000000000) {
367 load_item->time_tot.secs++;
368 load_item->time_tot.nsecs -= 1000000000;
370 load_item->fields++;
372 if (j == 0) {
373 break;
375 j--;
376 t -= pt;
377 if (t > (uint64_t) interval) {
378 pt = (uint64_t) interval;
379 } else {
380 pt = t;
383 break;
385 default:
386 if ( (nstime_cmp(new_time, &item->time_max) > 0)
387 || (item->fields == 0)) {
388 item->time_max = *new_time;
389 item->max_frame_in_invl = pinfo->num;
391 if ( (nstime_cmp(new_time, &item->time_min) < 0)
392 || (item->fields == 0)) {
393 item->time_min = *new_time;
394 item->min_frame_in_invl = pinfo->num;
396 nstime_add(&item->time_tot, new_time);
397 item->fields++;
399 break;
400 default:
401 if ((item_unit == IOG_ITEM_UNIT_CALC_FRAMES) ||
402 (item_unit == IOG_ITEM_UNIT_CALC_FIELDS)) {
404 * It's not an integeresque type, but
405 * all we want to do is count it, so
406 * that's all right.
408 item->fields++;
410 else {
412 * "Can't happen"; see the "check that the
413 * type is compatible" check in
414 * filter_callback().
416 ws_assert_not_reached();
418 break;
423 item->frames++;
424 item->bytes += pinfo->fd->pkt_len;
426 return true;
430 #ifdef __cplusplus
432 #endif /* __cplusplus */
434 #endif /* __IO_GRAPH_ITEM_H__ */