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
169 int64_t get_io_graph_index(packet_info
*pinfo
, int interval
);
171 /** Check field and item unit compatibility
173 * @param field_name [in] Header field name to check
174 * @param hf_index [out] Assigned the header field index corresponding to field_name if valid.
176 * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
177 * @return NULL if compatible, otherwise an error string. The string must
178 * be freed by the caller.
180 GString
*check_field_unit(const char *field_name
, int *hf_index
, io_graph_item_unit_t item_unit
);
182 /** Get the value at the given interval (idx) for the current value unit.
184 * @param items [in] Array containing the item to get.
185 * @param val_units [in] The type of unit to calculate. From IOG_ITEM_UNITS.
186 * @param idx [in] Index of the item to get.
187 * @param hf_index [in] Header field index for advanced statistics.
188 * @param cap_file [in] Capture file.
189 * @param interval [in] Timing interval in ms.
190 * @param cur_idx [in] Current index.
191 * @param asAOT [in] Interpret when possible the value as an Average Over Time.
193 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
);
195 /** Update the values of an io_graph_item_t.
197 * Frame and byte counts are always calculated. If edt is non-NULL advanced
198 * statistics are calculated using hfindex.
200 * @param items [in,out] Array containing the item to update.
201 * @param idx [in] Index of the item to update.
202 * @param pinfo [in] Packet containing update information.
203 * @param edt [in] Dissection information for advanced statistics. May be NULL.
204 * @param hf_index [in] Header field index for advanced statistics.
205 * @param item_unit [in] The type of unit to calculate. From IOG_ITEM_UNITS.
206 * @param interval [in] Timing interval in μs.
207 * @return true if the update was successful, otherwise false.
210 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
) {
211 io_graph_item_t
*item
= &items
[idx
];
213 /* Set the first and last frame num in current interval matching the target field+filter */
214 if (item
->first_frame_in_invl
== 0) {
215 item
->first_frame_in_invl
= pinfo
->num
;
217 item
->last_frame_in_invl
= pinfo
->num
;
219 if (edt
&& hf_index
>= 0) {
223 gp
= proto_get_finfo_ptr_array(edt
->tree
, hf_index
);
228 /* Update the appropriate counters. If fields == 0, this is the first seen
229 * value so set any min/max values accordingly. */
230 for (i
=0; i
< gp
->len
; i
++) {
235 const nstime_t
*new_time
;
237 switch (proto_registrar_get_ftype(hf_index
)) {
242 new_uint64
= fvalue_get_uinteger(((field_info
*)gp
->pdata
[i
])->value
);
244 if ((new_uint64
> item
->uint_max
) || (item
->fields
== 0)) {
245 item
->uint_max
= new_uint64
;
246 item
->max_frame_in_invl
= pinfo
->num
;
248 if ((new_uint64
< item
->uint_min
) || (item
->fields
== 0)) {
249 item
->uint_min
= new_uint64
;
250 item
->min_frame_in_invl
= pinfo
->num
;
252 item
->double_tot
+= (double)new_uint64
;
259 new_int64
= fvalue_get_sinteger(((field_info
*)gp
->pdata
[i
])->value
);
260 if ((new_int64
> item
->int_max
) || (item
->fields
== 0)) {
261 item
->int_max
= new_int64
;
262 item
->max_frame_in_invl
= pinfo
->num
;
264 if ((new_int64
< item
->int_min
) || (item
->fields
== 0)) {
265 item
->int_min
= new_int64
;
266 item
->min_frame_in_invl
= pinfo
->num
;
268 item
->double_tot
+= (double)new_int64
;
275 new_uint64
= fvalue_get_uinteger64(((field_info
*)gp
->pdata
[i
])->value
);
276 if ((new_uint64
> item
->uint_max
) || (item
->fields
== 0)) {
277 item
->uint_max
= new_uint64
;
278 item
->max_frame_in_invl
= pinfo
->num
;
280 if ((new_uint64
< item
->uint_min
) || (item
->fields
== 0)) {
281 item
->uint_min
= new_uint64
;
282 item
->min_frame_in_invl
= pinfo
->num
;
284 item
->double_tot
+= (double)new_uint64
;
291 new_int64
= fvalue_get_sinteger64(((field_info
*)gp
->pdata
[i
])->value
);
292 if ((new_int64
> item
->int_max
) || (item
->fields
== 0)) {
293 item
->int_max
= new_int64
;
294 item
->max_frame_in_invl
= pinfo
->num
;
296 if ((new_int64
< item
->int_min
) || (item
->fields
== 0)) {
297 item
->int_min
= new_int64
;
298 item
->min_frame_in_invl
= pinfo
->num
;
300 item
->double_tot
+= (double)new_int64
;
304 new_float
= (float)fvalue_get_floating(((field_info
*)gp
->pdata
[i
])->value
);
305 if ((new_float
> item
->double_max
) || (item
->fields
== 0)) {
306 item
->double_max
= new_float
;
307 item
->max_frame_in_invl
= pinfo
->num
;
309 if ((new_float
< item
->double_min
) || (item
->fields
== 0)) {
310 item
->double_min
= new_float
;
311 item
->min_frame_in_invl
= pinfo
->num
;
313 item
->double_tot
+= new_float
;
317 new_double
= fvalue_get_floating(((field_info
*)gp
->pdata
[i
])->value
);
318 if ((new_double
> item
->double_max
) || (item
->fields
== 0)) {
319 item
->double_max
= new_double
;
320 item
->max_frame_in_invl
= pinfo
->num
;
322 if ((new_double
< item
->double_min
) || (item
->fields
== 0)) {
323 item
->double_min
= new_double
;
324 item
->min_frame_in_invl
= pinfo
->num
;
326 item
->double_tot
+= new_double
;
329 case FT_RELATIVE_TIME
:
330 new_time
= fvalue_get_time(((field_info
*)gp
->pdata
[i
])->value
);
333 case IOG_ITEM_UNIT_CALC_LOAD
:
335 uint64_t t
, pt
; /* time in us */
338 * Add the time this call spanned each interval according to
339 * its contribution to that interval.
340 * If the call time is negative (unlikely, requires both an
341 * out of order capture file plus retransmission), ignore.
343 const nstime_t time_zero
= NSTIME_INIT_ZERO
;
344 if (nstime_cmp(new_time
, &time_zero
) < 0) {
348 t
= t
* 1000000 + new_time
->nsecs
/ 1000;
351 * Handle current interval
352 * This cannot be negative, because get_io_graph_index
353 * returns an invalid interval if so.
355 pt
= pinfo
->rel_ts
.secs
* 1000000 + pinfo
->rel_ts
.nsecs
/ 1000;
361 io_graph_item_t
*load_item
;
363 load_item
= &items
[j
];
364 load_item
->time_tot
.nsecs
+= (int) (pt
* 1000);
365 if (load_item
->time_tot
.nsecs
> 1000000000) {
366 load_item
->time_tot
.secs
++;
367 load_item
->time_tot
.nsecs
-= 1000000000;
376 if (t
> (uint64_t) interval
) {
377 pt
= (uint64_t) interval
;
385 if ( (nstime_cmp(new_time
, &item
->time_max
) > 0)
386 || (item
->fields
== 0)) {
387 item
->time_max
= *new_time
;
388 item
->max_frame_in_invl
= pinfo
->num
;
390 if ( (nstime_cmp(new_time
, &item
->time_min
) < 0)
391 || (item
->fields
== 0)) {
392 item
->time_min
= *new_time
;
393 item
->min_frame_in_invl
= pinfo
->num
;
395 nstime_add(&item
->time_tot
, new_time
);
400 if ((item_unit
== IOG_ITEM_UNIT_CALC_FRAMES
) ||
401 (item_unit
== IOG_ITEM_UNIT_CALC_FIELDS
)) {
403 * It's not an integeresque type, but
404 * all we want to do is count it, so
411 * "Can't happen"; see the "check that the
412 * type is compatible" check in
415 ws_assert_not_reached();
423 item
->bytes
+= pinfo
->fd
->pkt_len
;
431 #endif /* __cplusplus */
433 #endif /* __IO_GRAPH_ITEM_H__ */