Wireshark-dev: Re: [Wireshark-dev] Qt Interface Profiling
From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Fri, 26 Jun 2015 16:03:40 -0700
On Jun 26, 2015, at 2:45 PM, Evan Huus <eapache@xxxxxxxxx> wrote:

> I just ran the Qt interface through callgrind while loading a fairly
> large capture. Stripping out all the dissector-related expenses, the
> following two UI functions show up as hot spots:
> 
> qt_blurImage()
> This is a Qt internal function for blurring, presumably from the fancy
> start-up screen, but showed up as *surprisingly* expensive given the
> fact that the startup screen was only a tiny fraction of the time
> profiled. Is it possible it's still getting run with a blur factor of
> 0 on every screen or something?

It sounds, from the documentation, as if callgrind calculates a call graph; does it show who's calling qt_blurImage - from a quick look at the Qt 5.3.2 source, it's called from a couple of pixmap routines - and who's calling those routines?

> PacketListModel::recordLessThan()
> This is ours, used for sorting the packet list. Not immediately sure
> how to make it better, the GTK version is entirely different.

What columns do you have in your display?

The custom column sort will look up the column's field over and over again, but if you're not using a custom column, that won't be an issue.

For columns that don't come from frame data, it does a string compare, or converts the string column data to a number, which probably does more work than it needs to if the underlying column isn't just a text string.

On the other hand, if you're just *loading* the capture, there shouldn't *be* any sorting - the frames should just be displayed in the order in which they're read!

According to

	http://doc.qt.io/qt-4.8/model-view-programming.html

(I'm using 4.8 documentation to avoid making Wireshark 5.x-only, so that it doesn't require the latest shiniest version of $DISTRIBUTION):

	There are two ways of approaching sorting in the model/view architecture; which approach to choose depends on your underlying model.

	If your model is sortable, i.e, if it reimplements the QAbstractItemModel::sort() function, both QTableView and QTreeView provide an API that allows you to sort your model data programmatically. In addition, you can enable interactive sorting (i.e. allowing the users to sort the data by clicking the view's headers), by connecting the QHeaderView::sortIndicatorChanged() signal to the QTableView::sortByColumn() slot or the QTreeView::sortByColumn() slot, respectively.

	The alternative approach, if your model do not have the required interface or if you want to use a list view to present your data, is to use a proxy model to transform the structure of your model before presenting the data in the view. This is covered in detail in the section on Proxy Models.

That section says:

	In the model/view framework, items of data supplied by a single model can be shared by any number of views, and each of these can possibly represent the same information in completely different ways. Custom views and delegates are effective ways to provide radically different representations of the same data. However, applications often need to provide conventional views onto processed versions of the same data, such as differently-sorted views onto a list of items.

	Although it seems appropriate to perform sorting and filtering operations as internal functions of views, this approach does not allow multiple views to share the results of such potentially costly operations. The alternative approach, involving sorting within the model itself, leads to the similar problem where each view has to display items of data that are organized according to the most recent processing operation.

	To solve this problem, the model/view framework uses proxy models to manage the information supplied between individual models and views. Proxy models are components that behave like ordinary models from the perspective of a view, and access data from source models on behalf of that view. The signals and slots used by the model/view framework ensure that each view is updated appropriately no matter how many proxy models are placed between itself and the source model.

So, as I understand it, we could:

	have an underlying model that is as thin a wrapper as possible around the frame_data_sequence;

	have a proxy model that has a trivial map when sorting by frame number (either mapping row N to frame N or mapping row N to frame (max + 1 - N), depending on whether we're sorting in increasing or decreasing order) and maintains its own map for other column types;

	perhaps have the sort method for that model make one pass over all the packets, constructing a map from frames to rows - given that you could be sorting a very large capture, and that if we generate the column data dynamically that means reading and dissecting each frame, a sort that accesses each frame only once and does so in sequential order, entering them into a sorted tree, might be faster than other sorts.