Instantiating all those device formats can result in lengthy processes like loading kernel modules, some of which are very large. This results in lag between when the user leaves the welcome spoke and the hub being displayed.
In my thoroughly unscientific testing on one computer, this knocks about two seconds off the amount of time between the welcome screen and the hub. --- pyanaconda/ui/gui/spokes/custom.py | 18 +++++++++++++----- pyanaconda/ui/gui/spokes/storage.py | 1 + 2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index b20f3eb..368b742 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -45,7 +45,7 @@ import re from pykickstart.constants import *
from pyanaconda.product import productName, productVersion -from pyanaconda.threads import threadMgr +from pyanaconda.threads import AnacondaThread, threadMgr
from blivet import devicefactory from blivet.formats import device_formats @@ -79,7 +79,7 @@ from pyanaconda.ui.gui.spokes.lib.passphrase import PassphraseDialog from pyanaconda.ui.gui.spokes.lib.accordion import * from pyanaconda.ui.gui.spokes.lib.refresh import RefreshDialog from pyanaconda.ui.gui.spokes.lib.summary import ActionSummaryDialog -from pyanaconda.ui.gui.utils import setViewportBackground +from pyanaconda.ui.gui.utils import setViewportBackground, gtk_thread_wait from pyanaconda.ui.gui.categories.storage import StorageCategory
from gi.repository import Gtk @@ -518,8 +518,16 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # Populate the list of valid filesystem types from the format classes. # Unfortunately, we have to narrow them down a little bit more because # this list will include things like PVs and RAID members. - fsCombo = self.builder.get_object("fileSystemTypeCombo") - fsCombo.remove_all() + self.fsCombo = self.builder.get_object("fileSystemTypeCombo") + self.fsCombo.remove_all() + + threadMgr.add(AnacondaThread(name="AnaCustomStorageInit", target=self._initialize)) + + def _initialize(self): + @gtk_thread_wait + def gtk_action(name): + self.fsCombo.append_text(name) + self._fs_types = [] for cls in device_formats.itervalues(): obj = cls() @@ -530,7 +538,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): (isinstance(obj, FS) or obj.type in ["biosboot", "prepboot", "swap"])) if supported_fs: - fsCombo.append_text(obj.name) + gtk_action(obj.name) self._fs_types.append(obj.name)
@property diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py index 1b474f0..17bfbeb 100644 --- a/pyanaconda/ui/gui/spokes/storage.py +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -561,6 +561,7 @@ class StorageSpoke(NormalSpoke, StorageChecker): communication.send_message(self.__class__.__name__, _("Probing storage..."))
threadMgr.wait("AnaStorageThread") + threadMgr.wait("AnaCustomStorageInit")
self.disks = getDisks(self.storage.devicetree)
This saves some very small amount of time in bringing the hub up after the welcome spoke goes away. It's still not quite fast enough, though. --- pyanaconda/ui/gui/spokes/datetime_spoke.py | 55 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index 1800f02..2b344c4 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -29,11 +29,12 @@ log = logging.getLogger("anaconda") # pylint: disable-msg=E0611 from gi.repository import AnacondaWidgets, GLib, Gtk, Gdk
+from pyanaconda.ui import communication from pyanaconda.ui.common import FirstbootSpokeMixIn from pyanaconda.ui.gui import GUIObject from pyanaconda.ui.gui.spokes import NormalSpoke from pyanaconda.ui.gui.categories.localization import LocalizationCategory -from pyanaconda.ui.gui.utils import enlightbox, gtk_thread_nowait, gtk_call_once +from pyanaconda.ui.gui.utils import enlightbox, gtk_thread_nowait, gtk_thread_wait, gtk_call_once
from pyanaconda import timezone from pyanaconda.timezone import NTP_SERVICE @@ -311,27 +312,6 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._citiesStore = self.builder.get_object("cities") self._tzmap = self.builder.get_object("tzmap")
- self._regions_zones = timezone.get_all_regions_and_timezones() - - for day in xrange(1, 32): - self.add_to_store(self._daysStore, day) - - self._months_nums = dict() - for i in xrange(1, 13): - #a bit hacky way, but should return the translated string - #TODO: how to handle language change? Clear and populate again? - month = datetime.date(2000, i, 1).strftime('%B') - self.add_to_store(self._monthsStore, month) - self._months_nums[month] = i - - for year in xrange(1990, 2051): - self.add_to_store(self._yearsStore, year) - - for region in self._regions_zones.keys(): - self.add_to_store(self._regionsStore, region) - for city in self._regions_zones[region]: - self.add_to_store(self._citiesStore, city) - # we need to know it the new value is the same as previous or not self._old_region = None self._old_city = None @@ -360,6 +340,31 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
self._ntpSwitch = self.builder.get_object("networkTimeSwitch")
+ self._regions_zones = timezone.get_all_regions_and_timezones() + + threadMgr.add(AnacondaThread(name="AnaDateTimeThread", target=self._initialize)) + + @gtk_thread_wait + def _initialize(self): + for day in xrange(1, 32): + self.add_to_store(self._daysStore, day) + + self._months_nums = dict() + for i in xrange(1, 13): + #a bit hacky way, but should return the translated string + #TODO: how to handle language change? Clear and populate again? + month = datetime.date(2000, i, 1).strftime('%B') + self.add_to_store(self._monthsStore, month) + self._months_nums[month] = i + + for year in xrange(1990, 2051): + self.add_to_store(self._yearsStore, year) + + for region in self._regions_zones.keys(): + self.add_to_store(self._regionsStore, region) + for city in self._regions_zones[region]: + self.add_to_store(self._citiesStore, city) + if self._radioButton24h.get_active(): self._set_amPm_part_sensitive(False)
@@ -379,6 +384,8 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._config_dialog = NTPconfigDialog(self.data) self._config_dialog.initialize()
+ communication.send_ready(self.__class__.__name__) + @property def status(self): if self.data.timezone.timezone: @@ -410,6 +417,10 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self.data.timezone.setup(self.data)
@property + def ready(self): + return not threadMgr.get("AnaDateTimeThread") + + @property def completed(self): if flags.flags.automatedInstall and not self.data.timezone.seen: return False
On Fri, 2013-03-15 at 14:17 -0400, Chris Lumens wrote:
This saves some very small amount of time in bringing the hub up after the welcome spoke goes away. It's still not quite fast enough, though.
pyanaconda/ui/gui/spokes/datetime_spoke.py | 55 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index 1800f02..2b344c4 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -29,11 +29,12 @@ log = logging.getLogger("anaconda") # pylint: disable-msg=E0611 from gi.repository import AnacondaWidgets, GLib, Gtk, Gdk
+from pyanaconda.ui import communication from pyanaconda.ui.common import FirstbootSpokeMixIn from pyanaconda.ui.gui import GUIObject from pyanaconda.ui.gui.spokes import NormalSpoke from pyanaconda.ui.gui.categories.localization import LocalizationCategory -from pyanaconda.ui.gui.utils import enlightbox, gtk_thread_nowait, gtk_call_once +from pyanaconda.ui.gui.utils import enlightbox, gtk_thread_nowait, gtk_thread_wait, gtk_call_once
from pyanaconda import timezone from pyanaconda.timezone import NTP_SERVICE @@ -311,27 +312,6 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._citiesStore = self.builder.get_object("cities") self._tzmap = self.builder.get_object("tzmap")
self._regions_zones = timezone.get_all_regions_and_timezones()for day in xrange(1, 32):self.add_to_store(self._daysStore, day)self._months_nums = dict()for i in xrange(1, 13):#a bit hacky way, but should return the translated string#TODO: how to handle language change? Clear and populate again?month = datetime.date(2000, i, 1).strftime('%B')self.add_to_store(self._monthsStore, month)self._months_nums[month] = ifor year in xrange(1990, 2051):self.add_to_store(self._yearsStore, year)for region in self._regions_zones.keys():self.add_to_store(self._regionsStore, region)for city in self._regions_zones[region]:self.add_to_store(self._citiesStore, city)# we need to know it the new value is the same as previous or not self._old_region = None self._old_city = None@@ -360,6 +340,31 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
self._ntpSwitch = self.builder.get_object("networkTimeSwitch")
self._regions_zones = timezone.get_all_regions_and_timezones()threadMgr.add(AnacondaThread(name="AnaDateTimeThread", target=self._initialize))- @gtk_thread_wait
- def _initialize(self):
for day in xrange(1, 32):self.add_to_store(self._daysStore, day)self._months_nums = dict()for i in xrange(1, 13):#a bit hacky way, but should return the translated string#TODO: how to handle language change? Clear and populate again?month = datetime.date(2000, i, 1).strftime('%B')self.add_to_store(self._monthsStore, month)self._months_nums[month] = ifor year in xrange(1990, 2051):self.add_to_store(self._yearsStore, year)for region in self._regions_zones.keys():self.add_to_store(self._regionsStore, region)for city in self._regions_zones[region]:self.add_to_store(self._citiesStore, city)if self._radioButton24h.get_active(): self._set_amPm_part_sensitive(False)
Does this really change anything? Cause if I'm not wrong, using the @gtk_thread_wait decorator makes the _initialize method run in the main loop, thus in the main thread. I believe the code changing the Gtk widgets (not stores etc.) should be put in a separate function decorated with @gtk_thread_nowait (because the thread doesn't have to wait for these actions to finish).
Does this really change anything? Cause if I'm not wrong, using the @gtk_thread_wait decorator makes the _initialize method run in the main loop, thus in the main thread. I believe the code changing the Gtk widgets (not stores etc.) should be put in a separate function decorated with @gtk_thread_nowait (because the thread doesn't have to wait for these actions to finish).
If I leave everything else as it was in the patch, but remove the decorator from _initialize and mark add_to_store as gtk_action_nowait, the time from betanag dialog to hub displayed is under one second on my thoroughly unscientific testing. It might even be under half a second.
So that's definitely an improvement.
- Chris
On Thu, 2013-03-28 at 11:37 -0400, Chris Lumens wrote:
Does this really change anything? Cause if I'm not wrong, using the @gtk_thread_wait decorator makes the _initialize method run in the main loop, thus in the main thread. I believe the code changing the Gtk widgets (not stores etc.) should be put in a separate function decorated with @gtk_thread_nowait (because the thread doesn't have to wait for these actions to finish).
If I leave everything else as it was in the patch, but remove the decorator from _initialize and mark add_to_store as gtk_action_nowait, the time from betanag dialog to hub displayed is under one second on my thoroughly unscientific testing. It might even be under half a second.
So that's definitely an improvement.
It definitely is, great! Thanks for the further investigation.
My goal here is to make it seem like we're taking less time to set up. --- pyanaconda/ui/gui/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py index 7ace103..db9ea5f 100644 --- a/pyanaconda/ui/gui/__init__.py +++ b/pyanaconda/ui/gui/__init__.py @@ -362,10 +362,6 @@ class GraphicalUserInterface(UserInterface): return
self._currentAction.initialize() - - # Do this at the last possible minute. - unbusyCursor() - self._currentAction.refresh()
self._currentAction.window.set_beta(not self._isFinal) @@ -376,6 +372,10 @@ class GraphicalUserInterface(UserInterface): settings.set_property("gtk-font-name", "Cantarell")
self._currentAction.window.show_all() + + # Do this at the last possible minute. + unbusyCursor() + Gtk.main()
###
anaconda-patches@lists.fedorahosted.org