Wireshark-dev: [Wireshark-dev] New packet list: Optimize memory usage
From: Jakub Zawadzki <darkjames@xxxxxxxxxxxxxxxx>
Date: Sun, 12 Jul 2009 21:48:14 +0200
Hi, This patch (Proof of Concept) removes allocating memory for columns data, and makes them 'dynamic' (packets redissected when column data needed) Getting column data is done in packet_list_record_get_column() I'd be grateful if someone could give some hints how it could be optimized. (Anyway I think it'd be nice if we have some column cache for some previous and next rows, or e.g. tcp.stream related) Unfortunetly resorting for large dumps is PITA - we could also cache some columns (configurable by user?) Some stats for loading 113MB dumpfile: Old New Diff Loading: 16s 11s (-5s) VmRSS: 587956 kB 386376 kB (-201580 kB) I haven't seen any visible lags while scrolling, CPU usage is higher but for GUI is still fluent :)
diff --git file.c file.c index 71ac4d1..181c32f 100644 --- file.c +++ file.c @@ -1046,7 +1046,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, evaluated. */ if ((dfcode != NULL && refilter) || color_filters_used() || filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE) || - have_custom_cols(&cf->cinfo)) + 0 /* have_custom_cols(&cf->cinfo) */) create_proto_tree = TRUE; /* Dissect the frame. */ @@ -1060,7 +1060,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, color_filters_prime_edt(edt); } - col_custom_prime_edt(edt, &cf->cinfo); + /* col_custom_prime_edt(edt, &cf->cinfo); */ tap_queue_init(edt); epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo); @@ -1090,7 +1090,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, cum_bytes += fdata->pkt_len; } - epan_dissect_fill_in_columns(edt); + /* epan_dissect_fill_in_columns(edt); */ /* dynamic */ /* If we haven't yet seen the first frame, this is it. diff --git gtk/new_packet_list.c gtk/new_packet_list.c index 73f7209..84bd9bc 100644 --- gtk/new_packet_list.c +++ gtk/new_packet_list.c @@ -82,21 +82,10 @@ new_packet_list_create(void) } guint -new_packet_list_append(column_info cinfo, frame_data *fdata) +new_packet_list_append(column_info cinfo _U_, frame_data *fdata) { - gint i; row_data_t row_data; - /* Allocate the array holding column data, the size is the current number of columns */ - row_data.col_text = se_alloc0(sizeof(row_data.col_text)*cfile.cinfo.num_cols); - row_data.col_fmt = (gint *) se_alloc(sizeof(gint) * cfile.cinfo.num_cols); - - for(i = 0; i < cfile.cinfo.num_cols; i++) { - row_data.col_text[i] = - se_strdup(cinfo.col_data[i]); - row_data.col_fmt[i] = cinfo.col_fmt[i]; - } - row_data.fdata = fdata; packet_list_append_record(packetlist, &row_data); @@ -132,8 +121,7 @@ create_view_and_model(void) for(i = 0; i < cfile.cinfo.num_cols; i++) { col = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(col, renderer, TRUE); - gtk_tree_view_column_add_attribute(col, renderer, "text", - cfile.cinfo.col_fmt[i]); + gtk_tree_view_column_add_attribute(col, renderer, "text", i); gtk_tree_view_column_set_title(col, cfile.cinfo.col_title[i]); gtk_tree_view_column_set_sort_column_id(col, i); gtk_tree_view_column_set_resizable(col, TRUE); diff --git gtk/packet_list_store.c gtk/packet_list_store.c index 1b1cc14..898ef6e 100644 --- gtk/packet_list_store.c +++ gtk/packet_list_store.c @@ -205,31 +205,6 @@ packet_list_tree_model_init(GtkTreeModelIface *iface) static void packet_list_init(PacketList *packet_list) { - guint i; -#if 0 - gint fmt; - - for(i = 0; i < (guint)cfile.cinfo.num_cols; i++) { - /* Get the format of the column, see column_info.h */ - fmt = get_column_format(i); - switch(fmt){ - /* if we wish to store data rater than strings for some - * colum types add case statements to the switch. - */ - case COL_NUMBER: - default: - packet_list->column_types[i] = G_TYPE_STRING; - break; - } - } -#endif - - for(i = 0; i < NUM_COL_FMTS; i++) { /* XXX - Temporary? */ - packet_list->column_types[i] = G_TYPE_STRING; - } - - - packet_list->n_columns = NUM_COL_FMTS; packet_list->num_rows = 0; packet_list->rows = NULL; @@ -267,17 +242,18 @@ packet_list_get_n_columns(GtkTreeModel *tree_model) { g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), 0); - return PACKET_LIST(tree_model)->n_columns; + /* return NUM_COL_FMTS; */ + return cfile.cinfo.num_cols; } static GType packet_list_get_column_type(GtkTreeModel *tree_model, gint index) { g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), G_TYPE_INVALID); - g_return_val_if_fail(index < PACKET_LIST(tree_model)->n_columns && + g_return_val_if_fail(index < cfile.cinfo.num_cols && index >= 0, G_TYPE_INVALID); - return PACKET_LIST(tree_model)->column_types[index]; + return G_TYPE_STRING; /* always string */ } static gboolean @@ -340,6 +316,39 @@ packet_list_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) return path; } +static const gchar * +packet_list_record_get_column(PacketListRecord *record, gint column) +{ + capture_file *cf = &cfile; + epan_dissect_t *edt; + + gchar *err_info; + int err; + + g_return_val_if_fail(column >= 0 && column < cfile.cinfo.num_cols, NULL); + +#if 0 /* doesn't work, dunno how */ + if (cf->current_frame == record->fdata) { + printf("hit cache: %p %p\n", cf->current_frame, record->fdata); + return cf->cinfo.col_data[column]; + } +#endif + + if (!wtap_seek_read(cf->wth, record->fdata->file_off, &cf->pseudo_header, + cf->pd, record->fdata->cap_len, &err, &err_info)) + { + return "[ERROR]"; + } + + edt = epan_dissect_new(have_custom_cols(&cf->cinfo), FALSE); + col_custom_prime_edt(edt, &cf->cinfo); + epan_dissect_run(edt, &cf->pseudo_header, cf->pd, record->fdata, &cf->cinfo); + epan_dissect_fill_in_columns(edt); + epan_dissect_free(edt); + + return cf->cinfo.col_data[column]; +} + static void packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) @@ -349,9 +358,9 @@ packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, g_return_if_fail(PACKETLIST_IS_LIST(tree_model)); g_return_if_fail(iter != NULL); - g_return_if_fail(column < PACKET_LIST(tree_model)->n_columns); + g_return_if_fail(column >= 0 && column < cfile.cinfo.num_cols); - g_value_init(value, PACKET_LIST(tree_model)->column_types[column]); + g_value_init(value, G_TYPE_STRING); packet_list = PACKET_LIST(tree_model); @@ -360,7 +369,7 @@ packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, if(record->pos >= packet_list->num_rows) g_return_if_reached(); - g_value_set_string(value, record->col_text[column]); + g_value_set_string(value, packet_list_record_get_column(record, column)); } /* Takes an iter structure and sets it to point to the next row. */ @@ -505,7 +514,6 @@ packet_list_append_record(PacketList *packet_list, row_data_t *row_data) GtkTreePath *path; PacketListRecord *newrecord; guint pos; - gint i; g_return_if_fail(PACKETLIST_IS_LIST(packet_list)); @@ -516,18 +524,11 @@ packet_list_append_record(PacketList *packet_list, row_data_t *row_data) packet_list->rows = g_renew(PacketListRecord*, packet_list->rows, packet_list->num_rows); - newrecord = se_alloc0(sizeof(PacketListRecord)); - newrecord->col_text = se_alloc0(sizeof(row_data->col_text)* NUM_COL_FMTS); - - - /* XXX newrecord->col_text still uses the fmt index */ - for(i = 0; i < cfile.cinfo.num_cols; i++) - newrecord->col_text[row_data->col_fmt[i]] = row_data->col_text[i]; - + newrecord = se_alloc(sizeof(PacketListRecord)); newrecord->fdata = row_data->fdata; + newrecord->pos = pos; packet_list->rows[pos] = newrecord; - newrecord->pos = pos; /* Inform the tree view and other interested objects (such as tree row * references) that we have inserted a new row and where it was @@ -632,8 +633,8 @@ packet_list_compare_records(gint sort_id, PacketListRecord *a, * seen by the user, whereas the col_text array from a and b is a * column format number. This matches them to each other to get * the right column text. */ - gchar *a_col_text = a->col_text[cfile.cinfo.col_fmt[sort_id]]; - gchar *b_col_text = b->col_text[cfile.cinfo.col_fmt[sort_id]]; + const gchar *a_col_text = packet_list_record_get_column(a, sort_id); + const gchar *b_col_text = packet_list_record_get_column(b, sort_id); if((a_col_text) && (b_col_text)) return strcmp(a_col_text, b_col_text); diff --git gtk/packet_list_store.h gtk/packet_list_store.h index 3262ac6..721e18a 100644 --- gtk/packet_list_store.h +++ gtk/packet_list_store.h @@ -38,9 +38,6 @@ #define PACKETLIST_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PACKETLIST_TYPE_LIST, PacketListClass)) typedef struct { - gint *col_fmt; - gchar **col_text; - gchar **col_filter; frame_data *fdata; } row_data_t; @@ -53,7 +50,6 @@ struct _PacketListRecord { frame_data *fdata; - gchar **col_text; /* admin stuff used by the custom list model */ guint pos; /* position within the array */ @@ -69,8 +65,6 @@ struct _PacketList * the PacketListRecord structure for each * row. */ - gint n_columns; - GType column_types[NUM_COL_FMTS]; GtkWidget *view; /* XXX - Does this really belong here?? */ gint sort_id;
- Follow-Ups:
- Re: [Wireshark-dev] New packet list: Optimize memory usage
- From: Jakub Zawadzki
- Re: [Wireshark-dev] New packet list: Optimize memory usage
- From: Guy Harris
- Re: [Wireshark-dev] New packet list: Optimize memory usage
- From: Stephen Fisher
- Re: [Wireshark-dev] New packet list: Optimize memory usage
- From: didier
- Re: [Wireshark-dev] New packet list: Optimize memory usage
- Prev by Date: Re: [Wireshark-dev] New packet list - small fixes
- Next by Date: Re: [Wireshark-dev] New packet list: Optimize memory usage
- Previous by thread: Re: [Wireshark-dev] New packet list - small fixes
- Next by thread: Re: [Wireshark-dev] New packet list: Optimize memory usage
- Index(es):