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__
18 #include <wsutil/ws_assert.h>
20 #include <epan/epan_dissect.h>
24 #endif /* __cplusplus */
28 IOG_ITEM_UNIT_PACKETS
= IOG_ITEM_UNIT_FIRST
,
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
,
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*/
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
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
;
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.
81 reset_io_graph_items(io_graph_item_t
*items
, size_t count
, int hf_index _U_
) {
82 io_graph_item_t
*item
;
85 for (i
= 0; i
< count
; i
++) {
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
);
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.
109 switch (proto_registrar_get_ftype(hf_index
)) {
121 item
->double_tot
= 0;
134 item
->double_tot
= 0;
139 item
->double_max
= 0;
140 item
->double_min
= 0;
141 item
->double_tot
= 0;
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
);
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.
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.
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) {
224 gp
= proto_get_finfo_ptr_array(edt
->tree
, hf_index
);
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
++) {
236 const nstime_t
*new_time
;
238 switch (proto_registrar_get_ftype(hf_index
)) {
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
;
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
;
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
;
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
;
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
;
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
;
330 case FT_RELATIVE_TIME
:
331 new_time
= fvalue_get_time(((field_info
*)gp
->pdata
[i
])->value
);
334 case IOG_ITEM_UNIT_CALC_LOAD
:
336 uint64_t t
, pt
; /* time in us */
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) {
349 t
= t
* 1000000 + new_time
->nsecs
/ 1000;
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;
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;
377 if (t
> (uint64_t) interval
) {
378 pt
= (uint64_t) interval
;
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
);
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
412 * "Can't happen"; see the "check that the
413 * type is compatible" check in
416 ws_assert_not_reached();
424 item
->bytes
+= pinfo
->fd
->pkt_len
;
432 #endif /* __cplusplus */
434 #endif /* __IO_GRAPH_ITEM_H__ */