Follow Stream: ensure linear performance with many packets

Reverse the payload chunks list to achieve a running time of O(n) rather
than O(n²) for insertion of all chunks. Executing a RelWithDebInfo+ASAN
build with `tshark -r chargen-session.pcapng.gz -qz follow,tcp,hex,0`
previously took 11m5s to complete, but now finishes in 16 seconds.

Tested using a capture file with 152k TCP packets (from bug 11777).
Backport note: must update ui/gtk/follow_stream.c too.

Change-Id: Icf70d45f33d4399e53209fb6199d3809608c8d99
Reviewed-on: https://code.wireshark.org/review/28595
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Peter Wu 2018-07-04 21:53:53 +02:00 committed by Anders Broman
parent 2d36c475f9
commit c40c26c04c
7 changed files with 14 additions and 14 deletions

View File

@ -514,8 +514,8 @@ ssl_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _
appl_data->plain_data, appl_data->plain_data,
appl_data->data_len); appl_data->data_len);
/* Append the record to the follow_info structure. */ /* Add the record to the follow_info structure. */
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
follow_info->bytes_written[from] += appl_data->data_len; follow_info->bytes_written[from] += appl_data->data_len;
} }

View File

@ -1001,7 +1001,7 @@ check_follow_fragments(follow_info_t *follow_info, gboolean is_server, guint32 a
fragment->data->data + new_pos, fragment->data->data + new_pos,
new_frag_size); new_frag_size);
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
} }
follow_info->seq[is_server] += (fragment->data->len - new_pos); follow_info->seq[is_server] += (fragment->data->len - new_pos);
@ -1019,7 +1019,7 @@ check_follow_fragments(follow_info_t *follow_info, gboolean is_server, guint32 a
if( EQ_SEQ(fragment->seq, follow_info->seq[is_server]) ) { if( EQ_SEQ(fragment->seq, follow_info->seq[is_server]) ) {
/* this fragment fits the stream */ /* this fragment fits the stream */
if( fragment->data->len > 0 ) { if( fragment->data->len > 0 ) {
follow_info->payload = g_list_append(follow_info->payload, fragment); follow_info->payload = g_list_prepend(follow_info->payload, fragment);
} }
follow_info->seq[is_server] += fragment->data->len; follow_info->seq[is_server] += fragment->data->len;
@ -1047,7 +1047,7 @@ check_follow_fragments(follow_info_t *follow_info, gboolean is_server, guint32 a
follow_record->seq = lowest_seq; follow_record->seq = lowest_seq;
follow_info->seq[is_server] = lowest_seq; follow_info->seq[is_server] = lowest_seq;
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
return TRUE; return TRUE;
} }
@ -1094,7 +1094,7 @@ follow_tcp_tap_listener(void *tapdata, packet_info *pinfo,
follow_info->seq[follow_record->is_server]++; follow_info->seq[follow_record->is_server]++;
follow_info->bytes_written[follow_record->is_server] += follow_record->data->len; follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
return FALSE; return FALSE;
} }
@ -1141,7 +1141,7 @@ follow_tcp_tap_listener(void *tapdata, packet_info *pinfo,
follow_info->seq[follow_record->is_server]++; follow_info->seq[follow_record->is_server]++;
if (data_length > 0) { if (data_length > 0) {
follow_info->bytes_written[follow_record->is_server] += follow_record->data->len; follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
added_follow_record = TRUE; added_follow_record = TRUE;
} }

View File

@ -142,7 +142,7 @@ follow_info_free(follow_info_t* follow_info)
GList *cur; GList *cur;
follow_record_t *follow_record; follow_record_t *follow_record;
for(cur = follow_info->payload; cur; cur = g_list_next(cur)) { for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
if(cur->data) { if(cur->data) {
follow_record = (follow_record_t *)cur->data; follow_record = (follow_record_t *)cur->data;
if(follow_record->data) if(follow_record->data)
@ -206,7 +206,7 @@ follow_tvb_tap_listener(void *tapdata, packet_info *pinfo,
/* update stream counter */ /* update stream counter */
follow_info->bytes_written[follow_record->is_server] += follow_record->data->len; follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
follow_info->payload = g_list_append(follow_info->payload, follow_record); follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
return FALSE; return FALSE;
} }

View File

@ -84,7 +84,7 @@ typedef struct {
typedef struct _follow_info { typedef struct _follow_info {
show_stream_t show_stream; show_stream_t show_stream;
char *filter_out_filter; char *filter_out_filter;
GList *payload; GList *payload; /* "follow_record_t" entries, in reverse order. */
guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */ guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */
guint32 seq[2]; /* TCP only */ guint32 seq[2]; /* TCP only */
GList *fragments[2]; /* TCP only */ GList *fragments[2]; /* TCP only */

View File

@ -2564,7 +2564,7 @@ sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count)
printf(",\"payloads\":["); printf(",\"payloads\":[");
for (cur = follow_info->payload; cur; cur = g_list_next(cur)) for (cur = g_list_last(follow_info->payload); cur; cur = g_list_previous(cur))
{ {
follow_record = (follow_record_t *) cur->data; follow_record = (follow_record_t *) cur->data;

View File

@ -184,9 +184,9 @@ static void follow_draw(void *contextp)
else else
printf("Node 1: %s:%u\n", buf, follow_info->server_port); printf("Node 1: %s:%u\n", buf, follow_info->server_port);
for (cur = follow_info->payload, chunk = 1; for (cur = g_list_last(follow_info->payload), chunk = 1;
cur != NULL; cur != NULL;
cur = g_list_next(cur), chunk++) cur = g_list_previous(cur), chunk++)
{ {
follow_record = (follow_record_t *)cur->data; follow_record = (follow_record_t *)cur->data;
if (!follow_record->is_server) { if (!follow_record->is_server) {

View File

@ -1004,7 +1004,7 @@ FollowStreamDialog::readFollowStream()
elapsed_timer.start(); elapsed_timer.start();
for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) { for (cur = g_list_last(follow_info_.payload); cur; cur = g_list_previous(cur)) {
if (dialogClosed()) break; if (dialogClosed()) break;
follow_record = (follow_record_t *)cur->data; follow_record = (follow_record_t *)cur->data;