Let's try that again: Faster loading?

My last message was in error from something other than my normal e-mail program. Here it is in a readable format:

Apologies if this is an old question, but I wasn't able to find an answer by googling or searching the archives. I have two simple applications using wxWidgets (2.5.1.5u) and python (2.3) that does some calculations on stock prices (find the last time a stock moved this much or was at today's value). I'm distributing it using py2exe (0.5.0). The main windows in both cases are dialog-like with less than two dozen controls each. The app executables are just 24KB each. But of course those load many tens of megabytes of python and wx code before running.

The problem I'm having is that they take a long time to start up. On some our slower PCs, it can take a minute or more. That's prompting some users to click on the icon two or three times because they think it didn't work. Then three copies launch (behind another window, so they can't see it -- the usual novice-support blues). I'm trying to quickly throw something on the screen so that the user is aware that the app is coming, eventually. I tried a splashscreen, like so:

class MyApp(wxApp):
     def OnInit(self):
         bmp = wx.Image("lib/splash.bmp").ConvertToBitmap()
         splash = wx.SplashScreen(bmp,
                                  wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
                                  6000, None, -1)
         wx.BeginBusyCursor()
         splash.Show()
         wxInitAllImageHandlers()
         self.main = wxMoveSince.create(None)
         self.main.CentreOnScreen()
         self.main.Show()
         self.SetTopWindow(self.main)
         wx.EndBusyCursor()
         return True

def main():
     application = MyApp(0)
     application.MainLoop()

But all that does is load the splashscreen immediately (as in a split second) before the main window, so it appears to be the large libraries and not the code itself.

Any ideas? What's the fastest way to show some activity? Should I do a quicker loader in C, just to show the splashscreen and then load the python programs? Is there an alternative executable maker that may be faster?

Eamonn Sullivan wrote:
[...]

But all that does is load the splashscreen immediately (as in a split second) before the main window, so it appears to be the large libraries and not the code itself.

Correct. If you can show a splashscreen then all the lib is loaded so you may as well just show the main frame. For wxpython apps a splash screen is good if you have other non-UI stuff that needs to be initialized too, such as connecting to a database or loading things from a server.

Any ideas? What's the fastest way to show some activity? Should I do a quicker loader in C, just to show the splashscreen and then load the python programs?

That woudl be an excellent way to do it.

Is there an alternative executable maker that may be faster?

Not that I know of.

There may be other things you can do to optimize the load time. Try to figure out what it is about the machines that are taking a minute to load. Are the loading the .exe and .dll from a network server or the local disk? Are they severly memory constrained such that they have to swap out virtual memory to make enough room to load your app? etc.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Eamonn Sullivan:

Apologies if this is an old question, but I wasn't able to find an
answer by googling or searching the archives. I have two simple
applications using wxWidgets (2.5.1.5u)

   The Unicode version of wxPython has seemed much slower to me. Try doing a
benchmark with the non-Unicode version. Speed differs depending on build as
well.

and python (2.3) that does some calculations on stock prices
...
The app executables are just 24KB each. But of course
those load many tens of megabytes of python and wx code before running.

   Loading these executables should not require reading them all into memory
as executable code is loaded as needed using memory mapping on Windows.
However, object oriented code often includes static initialization dispersed
into each object so that many pages need to be executed. Microsoft have
produced tools for optimizing this, see
http://msdn.microsoft.com/msdnmag/issues/1000/bugslayer/

   Another possibility is an address collision. Each DLL is linked to run at
a particular address and if it is loaded into a process where that address
is already in use it has to be relocated. The Rebase utility can be used to
set the load addresses for a set of DLLs to avoid runtime relocation.

   Neil

Eamonn Sullivan <eamonn_sullivan@blueyonder.co.uk> writes:

But all that does is load the splashscreen immediately (as in a split
second) before the main window, so it appears to be the large
libraries and not the code itself.

Did you try isolate your splashscreen application code from all
non-related imports or is it in a main module that also imports other
non-wxPython modules? From your sample code my guess is you're
showing the splashscreen as part of your main initialization and thus
probably within the module that has already imported everything else
it is going to need.

While just getting wxPython loaded may be taking all the time, you may
also find room for improvement if you isolate the splashscreen to just
wxPython.

For example, I've got an application based around wxPython and twisted
that can take 45-60 seconds to load on a slower PII laptop. The
application was written as a "demo.py" main module. But when I put
together a splashscreen module ("startup.py") that just loaded the
splashscreen and then imported the other modules, that splashscreen
showed up in about 15s worst case on the laptop.

For example, here's the startup.py module - note the import of the
main code (the demo module in this case) occurs within the splash
screen handler and not at the top of the module, so that the time to
import it only occurs once the splashscreen is up. This module should
be able to wrap any other module that is built to be externally
callable (such as a fairly typical "main" entry point as here).

          - - - - - - - - - - - - - - - - - - - - - - - - -

import os
import sys
from wxPython import wx

···

#
# --------------------------------------------------------------------------
#

class StartupApp(wx.wxApp):
    """Startup application used to present the splash screen"""

    def OnInit(self):
        wx.wxInitAllImageHandlers()

        splashfile = os.path.join(os.path.dirname(sys.argv[0]),'aurora.jpg')
        bmp = wx.wxImage(splashfile).ConvertToBitmap()
        splash = wx.wxSplashScreen(bmp,
                                   wx.wxSPLASH_CENTRE_ON_SCREEN |
                                   wx.wxSPLASH_TIMEOUT,
                                   5000, None, -1,
                                   style = wx.wxSIMPLE_BORDER |
                                           wx.wxFRAME_NO_TASKBAR |
                                           wx.wxSTAY_ON_TOP)

        # Now that the splash screen is up, import the main demo module
        # which can take a while (and will probably gate the removal of the
        # splash screen rather than the default 5s timeout above)
        global demo
        import demo

        return True

if __name__ == "__main__":
    app = StartupApp(0)
    app.MainLoop()

    # When the splash screen exits, the demo module has been imported and
    # is available as a global
    demo.main()

          - - - - - - - - - - - - - - - - - - - - - - - - -

Any ideas? What's the fastest way to show some activity? Should I do a
quicker loader in C, just to show the splashscreen and then load the
python programs? Is there an alternative executable maker that may be
faster?

If the above isn't any faster than your prior attempts, then yes, a
separate loader might well be a good idea and C/C++ would be one
possibility.

If you wanted to try something else before dropping all the way down
to C/C++, another alternative (which I intended to pursue if the above
wasn't fast enough for me, but haven't had a pressing need yet since
the PCs I'm using tend to be PIIIs at least) would be to do a
splashscreen using the above approach but trying a thinner wrapper
than wxPython thus making the initial loading faster. Something like
win32all (ala the win32ui/win32gui modules) or venster, which should
let the splashscreen portion of the application load much more quickly
than something based on wxPython. I'm not sure if all the necessary
calls would be wrapped, but presumably if you were going to figure out
how to do it in C/C++ it should be easy enough to do it with one of
those wrappers, or just with ctypes directly.

-- David

Neil Hodgson wrote:

   Another possibility is an address collision. Each DLL is linked to run at
a particular address and if it is loaded into a process where that address
is already in use it has to be relocated. The Rebase utility can be used to
set the load addresses for a set of DLLs to avoid runtime relocation.

I had forgotten about this. I guess I should run the .dll's and .pyd's through rebase before making the installers...

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!