Is there a way to speed up widget creation on Windows?

289 views
Skip to first unread message

d0

unread,
Jul 16, 2021, 12:00:08 PM7/16/21
to wx-u...@googlegroups.com
Hi,

we've got an application where we dynamically create "worksheets". These have between 20 and 50 controls, each of which has at least a label and the control itself. On Linux with wxGTK this is pretty bearable and usually takes around 100 ms to bring up. On Windows it takes around 800-1000 ms (the run-to-run variance is probably from the many background applications on my Windows machine).

Profiling revealed that about 50 % of the entire time is spent creating the controls, around 10 % for the labels and then some misc. stuff. I tabulated this by control type and  noticed that there are two different classes of controls: Controls which can be created quickly (wxTextCtrl, wxCheckBox, wxTime/DatePickerCtrl, wxStaticText) in around 2 ms or so versus controls which are really expensive to create, like wx.Choice (around 16 ms) or wx.ComboBox (22-24 ms).

I already to Freeze/Thaw the panel these are created under. I tried double buffering in addition, made no difference. I also tried using wxEventBlocker but it made zero difference, as I expected. I've tried Hide()ing the panel, then Show()ing it once done but this also has no effect. I tried to create the panel in a hidden wxFrame, but this did not work, because the hidden wxFrame has no HWND so all sorts of things don't work.

I eliminated most of the "other" parts of the profile (mostly useless Layout() calls), but overall the effect of doing so is limited since they only amounted to a small part of the overall runtime to begin with.

Is there a way to speed the creation of these slow controls up?

(I suspect the answer is "no", because even MFC / Win32 apps seem to be cursed by slowly creating widgets; I've seen this many times across various applications using a lot of controls that I don't think it's due to the application developers doing something wrong per se)

Cheers, Marian

Igor Korot

unread,
Jul 16, 2021, 1:12:25 PM7/16/21
to wx-u...@googlegroups.com
Hi,



On Fri, Jul 16, 2021, 09:00 d0 <pub...@enkore.de> wrote:
Hi,

we've got an application where we dynamically create "worksheets". These have between 20 and 50 controls, each of which has at least a label and the control itself. On Linux with wxGTK this is pretty bearable and usually takes around 100 ms to bring up. On Windows it takes around 800-1000 ms (the run-to-run variance is probably from the many background applications on my Windows machine).

Profiling revealed that about 50 % of the entire time is spent creating the controls, around 10 % for the labels and then some misc. stuff. I tabulated this by control type and  noticed that there are two different classes of controls: Controls which can be created quickly (wxTextCtrl, wxCheckBox, wxTime/DatePickerCtrl, wxStaticText) in around 2 ms or so versus controls which are really expensive to create, like wx.Choice (around 16 ms) or wx.ComboBox (22-24 ms).

Are you creating an empty combo boxes or you pass the strings to its constructor?
What kind of strings do you use? Do you use wx container or simple static array? How big?

Also usual stanza:
Wx version?
Windows version?
Did you try the sample?
Are you checking debug or release build of the app?

Thank you.


I already to Freeze/Thaw the panel these are created under. I tried double buffering in addition, made no difference. I also tried using wxEventBlocker but it made zero difference, as I expected. I've tried Hide()ing the panel, then Show()ing it once done but this also has no effect. I tried to create the panel in a hidden wxFrame, but this did not work, because the hidden wxFrame has no HWND so all sorts of things don't work.

I eliminated most of the "other" parts of the profile (mostly useless Layout() calls), but overall the effect of doing so is limited since they only amounted to a small part of the overall runtime to begin with.

Is there a way to speed the creation of these slow controls up?

(I suspect the answer is "no", because even MFC / Win32 apps seem to be cursed by slowly creating widgets; I've seen this many times across various applications using a lot of controls that I don't think it's due to the application developers doing something wrong per se)

Cheers, Marian

--
Please read https://www.wxwidgets.org/support/mlhowto.htm before posting.
---
You received this message because you are subscribed to the Google Groups "wx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wx-users+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/wx-users/CAEi-PsvfK0LhZ13CNPM%3DCeBDqa0dh2a_bjv7FwXyEipdD1xmDg%40mail.gmail.com.

Vadim Zeitlin

unread,
Jul 16, 2021, 7:15:43 PM7/16/21
to wx-u...@googlegroups.com
On Fri, 16 Jul 2021 15:59:52 +0000 d0 wrote:

d> Profiling revealed that about 50 % of the entire time is spent creating the
d> controls, around 10 % for the labels and then some misc. stuff. I tabulated
d> this by control type and noticed that there are two different classes of
d> controls: Controls which can be created quickly (wxTextCtrl, wxCheckBox,
d> wxTime/DatePickerCtrl, wxStaticText) in around 2 ms or so versus controls
d> which are really expensive to create, like wx.Choice (around 16 ms) or
d> wx.ComboBox (22-24 ms).

This is not the biggest reason of the slowdown, but it's still surprising
that wxComboBox takes up to 50% longer than wxChoice to create when it's
the same underlying control. So the difference here must come from
something we do in wx code and so it might be possible to optimize it.

Would you have more details from your profiling runs about this, in
particular about the difference between these two controls? The problem is,
of course, that CreateWindow() sends out messages and I'm not sure how can
you account for the time taken handling them when profiling. The best would
probably be to create a simple test program creating a hundred or two of
wxChoices, profile it, save the results, then change it to create
wxComboBoxes, profile the new version and compare the results. Are there
any salient differences?

d> I already to Freeze/Thaw the panel these are created under. I tried double
d> buffering in addition, made no difference. I also tried using
d> wxEventBlocker but it made zero difference, as I expected. I've tried
d> Hide()ing the panel, then Show()ing it once done but this also has no
d> effect. I tried to create the panel in a hidden wxFrame, but this did not
d> work, because the hidden wxFrame has no HWND so all sorts of things don't
d> work.

A hidden wxFrame should still have a HWND. Do you mean a not created
wxFrame perhaps?

d> Is there a way to speed the creation of these slow controls up?

Unfortunately I don't know of any way to do it. I did run into this
problem myself, but it can usually be solved by not having "too many"
controls displayed at once, e.g. by using different wxNotebook pages for
them. But 50 is definitely not too many.

If the problem is really with just wxChoice and wxComboBox, perhaps you
could try using wxComboCtrl instead? It would be surprising if it were
faster than the native control, but could be worth checking.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Vojtěch Bubník

unread,
Jul 17, 2021, 2:13:30 AM7/17/21
to wx-u...@googlegroups.com
We have had the same discussion at the PrusaSlicer team recently. You may find the discussion in the list archive. You may compare also the source code and application speed for PrusaSlicer 2.2 vs. 2.3.0 to see the effects of the changes in the application source code we did.The general conclusion is: 

Win32 control creation is VERY expensive. Likely it has something to do with the cost of a Win32 window object, which is heavy with a lot of legacy stuff, skinning, screen readers... I did profiling on my ancient Core 2 Duo Windows 7 box and the application start up time was nearly the same as on modern Windows 10 box. My gut feeling is that the highest cost is associated with window compositing, which I suppose is more costly on Windows 10 and it cannot be disabled. However I have no base for that claim apart of comparing measurements on old slow Windows 7 box with fast Windows 10 box.

We did the following at the end:

1. We are newly creating pages of Win32 controls on demand, not at the application start up. Application starts very quickly, but page switching is slower.

2. To cope with slow page switching, we consolidated multiple labels with some other controls into our custom drawn control, thus reducing the number of controls significantly. Apart from the labels, the single control does layout of edit fields, shows and serves some indicator and undo buttons (we have three bitmap buttons rendered at each input line, all rendered and served by the same custom control). That was a very laborious process indeed, however it was the best we could do with wxWidgets wrapped Win32 controls. The speed up was extreme indeed.

3. Regarding profiling, I thing it is the window creation, window move and window destruction, that are expensive. I believe I indicated to Vadim some unnecessary window move calls at some widgets, it may have been some of the combo boxes, however reducing those calls would not be straightforward and it would bring maybe 20-30% speed up of the application, while doing 2. in our case brought something like 5x speed up if I remember correctly.

This is a Redmond specific issue. I spent considerable time looking for any information on cost of Win32 control creation. There is next to none. OSX and GTK are fine. Large number of Win32 controls will bring a Win32 application to its knees and Microsoft seems to not care, because they are trying hard to get away from Win32 for more than a decade. This single fact may be a very good reason for developers to turn from wxWidgets, as custom drawn widget liberaries such as QT, GTK on Windows or WPF (C# UI framework by microsoft) create just the top level Win32 windows. The solution for wxWidgets would be to refactor to custom draw (maybe optionally) at least some static controls and I believe Borland offered that when I played with Delphi around 2000, but that would require a lot of work of the wxWidgets team and likely it would require changes in applications as well.

Good luck,
Vojtech

Vojtěch Bubník

unread,
Jul 17, 2021, 2:26:01 AM7/17/21
to wx-u...@googlegroups.com
To add to the MoveWindow issue. I believe it is being called twice, once on window creation, the second time on layout. Suppressing the first one if one knows that a Layout will follow will likely bring some speed up, but it may make the code fragile. Also I believe wxBitmapComboBox re-creates after creation on Windows due to some layout (line height measurement?) issues.

d0

unread,
Jul 21, 2021, 9:13:20 AM7/21/21
to wx-u...@googlegroups.com
Thanks for all the responses, highly appreciated!

> This is not the biggest reason of the slowdown, but it's still surprising
> that wxComboBox takes up to 50% longer than wxChoice to create when it's
> the same underlying control. So the difference here must come from
> something we do in wx code and so it might be possible to optimize it.

The case I profiled had 15x wxChoices, but only two wxComboBoxen. I
know the system I'm using is pretty noisy, so I re-run profiles many
times to get an average overall runtime and use a reasonable profile
to work from, discarding all runs which took 1.5-3x longer than that
average. I've seen the differences across a few different runs though,
so I suspect it is real and not just noise.

All of these widgets get a fixed list of choices supplied through
wxArrayString. There are generally two to four choices, almost never
more than that.

Since 16 ms is a suspicious number near GUIs, I tried this with 24 Hz
refresh as well, but it takes just as long - so at least it's not
something locked to the refresh.

> Would you have more details from your profiling runs about this, in
> particular about the difference between these two controls? The problem is,
> of course, that CreateWindow() sends out messages and I'm not sure how can
> you account for the time taken handling them when profiling. The best would
> probably be to create a simple test program creating a hundred or two of
> wxChoices, profile it, save the results, then change it to create
> wxComboBoxes, profile the new version and compare the results. Are there
> any salient differences?

I will try to get more data on this.

> A hidden wxFrame should still have a HWND. Do you mean a not created
wxFrame perhaps?

Yes, I accidentally wrote it the wrong way. Tried it again with a
hidden wxFrame, however,
it makes no difference w.r.t. performance.

> If the problem is really with just wxChoice and wxComboBox, perhaps you
> could try using wxComboCtrl instead? It would be surprising if it were
> faster than the native control, but could be worth checking.

I can confirm that wxComboCtrl is indeed much faster than
wxChoice/wxComboBox to create, it seems to fall squarely in the
"cheap" category. I didn't provide a wxComboPopup though; looking at
the API it seems to be support lazy creation of the popup controls, so
it shouldn't have any impact in that area.

It is interesting to observe that the "cheap" widgets on MSW are still
super-slow compared to GTK. That group of widget takes like <0.2 ms to
create with GTK. I may not like many of GTK's design decisions, but it
sure looks to be far better optimized than Microsoft's GUI stack.

-----

> 1. We are newly creating pages of Win32 controls on demand, not at the application start up. Application starts very quickly, but page switching is slower.

We are essentially doing this already, our app supports multiple
worksheets at the same time, user selects desired type of worksheet,
which is then lazily created. However, inside the worksheet itself we
can't really lazily create anything, as it is all visible at the same
time.

> 2. To cope with slow page switching, we consolidated multiple labels with some other controls into our custom drawn control, thus reducing the number of controls significantly. Apart from the labels, the single control does layout of edit fields, shows and serves some indicator and undo buttons (we have three bitmap buttons rendered at each input line, all rendered and served by the same custom control). That was a very laborious process indeed, however it was the best we could do with wxWidgets wrapped Win32 controls. The speed up was extreme indeed.

I don't feel toooo amazed about that prospect, though killing off the
biggest offenders in our case with wxComboCtrl just for Windows might
be worth it, while retaining wxChoice (actually, we are using our own
custom-drawn faux-wxChoice on GTK, because GTK has rendering bug if
you reduce the height of a wxChoice) and wxComboBox for GTK, since
wxComboCtrl looks quite odd on GTK.

Cheers, Marian

Vadim Zeitlin

unread,
Jul 21, 2021, 10:00:05 AM7/21/21
to wx-u...@googlegroups.com
On Wed, 21 Jul 2021 13:13:07 +0000 d0 wrote:

d> I can confirm that wxComboCtrl is indeed much faster than
d> wxChoice/wxComboBox to create,

Thanks for testing this and I definitely accept your findings, but it's
still a very surprising result. I don't have time to do it right now, but
it would be great to write a simple program using Win32 API directly
creating (a bunch of) COMBOBOX control(s) and measure the time taken by it,
as I'd like to know if it's something that Windows itself does or if we
could be doing something wrong when creating these controls.

d> It is interesting to observe that the "cheap" widgets on MSW are still
d> super-slow compared to GTK. That group of widget takes like <0.2 ms to
d> create with GTK. I may not like many of GTK's design decisions, but it
d> sure looks to be far better optimized than Microsoft's GUI stack.

Just out of curiosity, are you measuring GTK times with X11 or Wayland
backend?

d> while retaining wxChoice (actually, we are using our own custom-drawn
d> faux-wxChoice on GTK, because GTK has rendering bug if you reduce the
d> height of a wxChoice) and wxComboBox for GTK, since wxComboCtrl looks
d> quite odd on GTK.

I'd also like to know more about these problems because I didn't know
about either of them. I guess there is not much we're going to be able to
do if wxChoice has height smaller than its minimal required one (if this is
what you mean), but perhaps we could improve wxComboCtrl appearance -- what
exactly is odd about it?

Thanks,
Reply all
Reply to author
Forward
0 new messages