replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[metze/wireshark/wip.git] / ui / io_graph_item.h
1 /* io_graph_item.h
2  * Definitions and functions for IO graph items
3  *
4  * Copied from gtk/io_stat.c, (c) 2002 Ronnie Sahlberg
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later*/
11
12 #ifndef __IO_GRAPH_ITEM_H__
13 #define __IO_GRAPH_ITEM_H__
14
15 #ifdef __cplusplus
16 extern "C" {
17 #endif /* __cplusplus */
18
19 typedef enum {
20     IOG_ITEM_UNIT_FIRST,
21     IOG_ITEM_UNIT_PACKETS = IOG_ITEM_UNIT_FIRST,
22     IOG_ITEM_UNIT_BYTES,
23     IOG_ITEM_UNIT_BITS,
24     IOG_ITEM_UNIT_CALC_SUM,
25     IOG_ITEM_UNIT_CALC_FRAMES,
26     IOG_ITEM_UNIT_CALC_FIELDS,
27     IOG_ITEM_UNIT_CALC_MAX,
28     IOG_ITEM_UNIT_CALC_MIN,
29     IOG_ITEM_UNIT_CALC_AVERAGE,
30     IOG_ITEM_UNIT_CALC_LOAD,
31     IOG_ITEM_UNIT_LAST = IOG_ITEM_UNIT_CALC_LOAD,
32     NUM_IOG_ITEM_UNITS
33 } io_graph_item_unit_t;
34
35 typedef struct _io_graph_item_t {
36     guint32  frames;            /* always calculated, will hold number of frames*/
37     guint64  bytes;             /* always calculated, will hold number of bytes*/
38     guint64  fields;
39     gint64   int_max;
40     gint64   int_min;
41     gint64   int_tot;
42     /* XXX - Why do we always use 64-bit ints but split floats between
43      * gfloat and gdouble?
44      */
45     gfloat   float_max;
46     gfloat   float_min;
47     gfloat   float_tot;
48     gdouble  double_max;
49     gdouble  double_min;
50     gdouble  double_tot;
51     nstime_t time_max;
52     nstime_t time_min;
53     nstime_t time_tot;
54     guint32  first_frame_in_invl;
55     guint32  extreme_frame_in_invl; /* frame with min/max value */
56     guint32  last_frame_in_invl;
57 } io_graph_item_t;
58
59 /** Reset (zero) an io_graph_item_t.
60  *
61  * @param items [in,out] Array containing the items to reset.
62  * @param count [in] The number of items in the array.
63  */
64 static inline void
65 reset_io_graph_items(io_graph_item_t *items, gsize count) {
66     io_graph_item_t *item;
67     gsize i;
68
69     for (i = 0; i < count; i++) {
70         item = &items[i];
71
72         item->frames     = 0;
73         item->bytes      = 0;
74         item->fields     = 0;
75         item->int_max    = 0;
76         item->int_min    = 0;
77         item->int_tot    = 0;
78         item->float_max  = 0;
79         item->float_min  = 0;
80         item->float_tot  = 0;
81         item->double_max = 0;
82         item->double_min = 0;
83         item->double_tot = 0;
84         nstime_set_zero(&item->time_max);
85         nstime_set_zero(&item->time_min);
86         nstime_set_zero(&item->time_tot);
87         item->first_frame_in_invl = 0;
88         item->extreme_frame_in_invl = 0;
89         item->last_frame_in_invl  = 0;
90     }
91 }
92
93 /** Get the interval (array index) for a packet
94  *
95  * It is up to the caller to determine if the return value is valid.
96  *
97  * @param [in] pinfo Packet of interest.
98  * @param [in] interval Time interval in milliseconds.
99  * @return Array index on success, -1 on failure.
100  */
101 int get_io_graph_index(packet_info *pinfo, int interval);
102
103 /** Check field and item unit compatibility
104  *
105  * @param field_name [in] Header field name to check
106  * @param hf_index [out] Assigned the header field index corresponding to field_name if valid.
107  *                       Can be NULL.
108  * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
109  * @return NULL if compatible, otherwise an error string. The string must
110  *         be freed by the caller.
111  */
112 GString *check_field_unit(const char *field_name, int *hf_index, io_graph_item_unit_t item_unit);
113
114 /** Update the values of an io_graph_item_t.
115  *
116  * Frame and byte counts are always calculated. If edt is non-NULL advanced
117  * statistics are calculated using hfindex.
118  *
119  * @param items [in,out] Array containing the item to update.
120  * @param idx [in] Index of the item to update.
121  * @param pinfo [in] Packet containing update information.
122  * @param edt [in] Dissection information for advanced statistics. May be NULL.
123  * @param hf_index [in] Header field index for advanced statistics.
124  * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
125  * @param interval [in] Timing interval in ms.
126  * @return TRUE if the update was successful, otherwise FALSE.
127  */
128 static inline gboolean
129 update_io_graph_item(io_graph_item_t *items, int idx, packet_info *pinfo, epan_dissect_t *edt, int hf_index, int item_unit, guint32 interval) {
130     io_graph_item_t *item = &items[idx];
131
132     /* Set the first and last frame num in current interval matching the target field+filter  */
133     if (item->first_frame_in_invl == 0) {
134         item->first_frame_in_invl = pinfo->num;
135     }
136     item->last_frame_in_invl = pinfo->num;
137
138     if (edt && hf_index >= 0) {
139         GPtrArray *gp;
140         guint i;
141
142         gp = proto_get_finfo_ptr_array(edt->tree, hf_index);
143         if (!gp) {
144             return FALSE;
145         }
146
147         /* Update the appropriate counters. If fields == 0, this is the first seen
148          *  value so set any min/max values accordingly. */
149         for (i=0; i < gp->len; i++) {
150             int new_int;
151             gint64 new_int64;
152             float new_float;
153             double new_double;
154             nstime_t *new_time;
155
156             switch (proto_registrar_get_ftype(hf_index)) {
157             case FT_UINT8:
158             case FT_UINT16:
159             case FT_UINT24:
160             case FT_UINT32:
161                 new_int = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
162
163                 if ((new_int > item->int_max) || (item->fields == 0)) {
164                     item->int_max = new_int;
165                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
166                         item->extreme_frame_in_invl = pinfo->num;
167                     }
168                 }
169                 if ((new_int < item->int_min) || (item->fields == 0)) {
170                     item->int_min = new_int;
171                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
172                         item->extreme_frame_in_invl = pinfo->num;
173                     }
174                 }
175                 item->int_tot += new_int;
176                 item->fields++;
177                 break;
178             case FT_INT8:
179             case FT_INT16:
180             case FT_INT24:
181             case FT_INT32:
182                 new_int = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
183                 if ((new_int > item->int_max) || (item->fields == 0)) {
184                     item->int_max = new_int;
185                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
186                         item->extreme_frame_in_invl = pinfo->num;
187                     }
188                 }
189                 if ((new_int < item->int_min) || (item->fields == 0)) {
190                     item->int_min = new_int;
191                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
192                         item->extreme_frame_in_invl = pinfo->num;
193                     }
194                 }
195                 item->int_tot += new_int;
196                 item->fields++;
197                 break;
198             case FT_UINT40:
199             case FT_UINT48:
200             case FT_UINT56:
201             case FT_UINT64:
202                 new_int64 = fvalue_get_uinteger64(&((field_info *)gp->pdata[i])->value);
203                 if ((new_int64 > item->int_max) || (item->fields == 0)) {
204                     item->int_max = new_int64;
205                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
206                         item->extreme_frame_in_invl = pinfo->num;
207                     }
208                 }
209                 if ((new_int64 < item->int_min) || (item->fields == 0)) {
210                     item->int_min = new_int64;
211                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
212                         item->extreme_frame_in_invl = pinfo->num;
213                     }
214                 }
215                 item->int_tot += new_int64;
216                 item->fields++;
217                 break;
218             case FT_INT40:
219             case FT_INT48:
220             case FT_INT56:
221             case FT_INT64:
222                 new_int64 = fvalue_get_sinteger64(&((field_info *)gp->pdata[i])->value);
223                 if ((new_int64 > item->int_max) || (item->fields == 0)) {
224                     item->int_max = new_int64;
225                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
226                         item->extreme_frame_in_invl = pinfo->num;
227                     }
228                 }
229                 if ((new_int64 < item->int_min) || (item->fields == 0)) {
230                     item->int_min = new_int64;
231                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
232                         item->extreme_frame_in_invl = pinfo->num;
233                     }
234                 }
235                 item->int_tot += new_int64;
236                 item->fields++;
237                 break;
238             case FT_FLOAT:
239                 new_float = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
240                 if ((new_float > item->float_max) || (item->fields == 0)) {
241                     item->float_max = new_float;
242                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
243                         item->extreme_frame_in_invl = pinfo->num;
244                     }
245                 }
246                 if ((new_float < item->float_min) || (item->fields == 0)) {
247                     item->float_min = new_float;
248                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
249                         item->extreme_frame_in_invl = pinfo->num;
250                     }
251                 }
252                 item->float_tot += new_float;
253                 item->fields++;
254                 break;
255             case FT_DOUBLE:
256                 new_double = fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
257                 if ((new_double > item->double_max) || (item->fields == 0)) {
258                     item->double_max = new_double;
259                     if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
260                         item->extreme_frame_in_invl = pinfo->num;
261                     }
262                 }
263                 if ((new_double < item->double_min) || (item->fields == 0)) {
264                     item->double_min = new_double;
265                     if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
266                         item->extreme_frame_in_invl = pinfo->num;
267                     }
268                 }
269                 item->double_tot += new_double;
270                 item->fields++;
271                 break;
272             case FT_RELATIVE_TIME:
273                 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
274
275                 switch (item_unit) {
276                 case IOG_ITEM_UNIT_CALC_LOAD:
277                 {
278                     guint64 t, pt; /* time in us */
279                     int j;
280                     /*
281                      * Add the time this call spanned each interval according to its contribution
282                      * to that interval.
283                      */
284                     t = new_time->secs;
285                     t = t * 1000000 + new_time->nsecs / 1000;
286                     j = idx;
287                     /*
288                      * Handle current interval
289                      */
290                     pt = pinfo->rel_ts.secs * 1000000 + pinfo->rel_ts.nsecs / 1000;
291                     pt = pt % (interval * 1000);
292                     if (pt > t) {
293                         pt = t;
294                     }
295                     while (t) {
296                         io_graph_item_t *load_item;
297
298                         load_item = &items[j];
299                         load_item->time_tot.nsecs += (int) (pt * 1000);
300                         if (load_item->time_tot.nsecs > 1000000000) {
301                             load_item->time_tot.secs++;
302                             load_item->time_tot.nsecs -= 1000000000;
303                         }
304
305                         if (j == 0) {
306                             break;
307                         }
308                         j--;
309                         t -= pt;
310                         if (t > (guint64) interval * 1000) {
311                             pt = (guint64) interval * 1000;
312                         } else {
313                             pt = t;
314                         }
315                     }
316                     break;
317                 }
318                 default:
319                     if ( (new_time->secs > item->time_max.secs)
320                          || ( (new_time->secs == item->time_max.secs)
321                               && (new_time->nsecs > item->time_max.nsecs))
322                          || (item->fields == 0)) {
323                         item->time_max = *new_time;
324                         if (item_unit == IOG_ITEM_UNIT_CALC_MAX) {
325                             item->extreme_frame_in_invl = pinfo->num;
326                         }
327                     }
328                     if ( (new_time->secs<item->time_min.secs)
329                          || ( (new_time->secs == item->time_min.secs)
330                               && (new_time->nsecs < item->time_min.nsecs))
331                          || (item->fields == 0)) {
332                         item->time_min = *new_time;
333                         if (item_unit == IOG_ITEM_UNIT_CALC_MIN) {
334                             item->extreme_frame_in_invl = pinfo->num;
335                         }
336                     }
337                     nstime_add(&item->time_tot, new_time);
338                     item->fields++;
339                 }
340                 break;
341             default:
342                 if ((item_unit == IOG_ITEM_UNIT_CALC_FRAMES) ||
343                     (item_unit == IOG_ITEM_UNIT_CALC_FIELDS)) {
344                     /*
345                      * It's not an integeresque type, but
346                      * all we want to do is count it, so
347                      * that's all right.
348                      */
349                     item->fields++;
350                 }
351                 else {
352                     /*
353                      * "Can't happen"; see the "check that the
354                      * type is compatible" check in
355                      * filter_callback().
356                      */
357                     g_assert_not_reached();
358                 }
359                 break;
360             }
361         }
362     }
363
364     item->frames++;
365     item->bytes += pinfo->fd->pkt_len;
366
367     return TRUE;
368 }
369
370
371 #ifdef __cplusplus
372 }
373 #endif /* __cplusplus */
374
375 #endif /* __IO_GRAPH_ITEM_H__ */
376
377 /*
378  * Editor modelines
379  *
380  * Local Variables:
381  * c-basic-offset: 4
382  * tab-width: 8
383  * indent-tabs-mode: nil
384  * End:
385  *
386  * ex: set shiftwidth=4 tabstop=8 expandtab:
387  * :indentSize=4:tabSize=8:noTabs=true:
388  */