From ce9b540b9765268311d0cc35b761d4b42be6afdc Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Thu, 9 Jun 2011 13:41:10 +0100 Subject: [PATCH] Initial GTK UI Speedups. The speedups work is being separated into 2 different phases and possibly branches. The idea is to have this minimal speedup merged into master as soon as possible since it's pretty simple. Reduces initial data transfer to about 10% of what was previously being transfered when client connected. The second phase is regarding row updates, ie, reduce them to what's actually being seen. This part is way more tricky. --- deluge/ui/gtkui/torrentview.py | 17 +++++++++++----- deluge/ui/sessionproxy.py | 37 +++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index 34b59877c..cf636772f 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -88,7 +88,7 @@ def cell_data_statusicon(column, cell, model, row, data): """Display text with an icon""" try: icon = ICON_STATE[model.get_value(row, data)] - #Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed + #Suppress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed with warnings.catch_warnings(): warnings.simplefilter("ignore") if cell.get_property("pixbuf") != icon: @@ -111,7 +111,7 @@ def cell_data_trackericon(column, cell, model, row, data): else: icon = create_blank_icon() - #Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed + #Suppress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed with warnings.catch_warnings(): warnings.simplefilter("ignore") if cell.get_property("pixbuf") != icon: @@ -411,8 +411,7 @@ class TorrentView(listview.ListView, component.Component): self.treeview.connect("key-release-event", self.on_key_press_event) # Connect to the 'changed' event of TreeViewSelection to get selection # changes. - self.treeview.get_selection().connect("changed", - self.on_selection_changed) + self.treeview.get_selection().connect("changed", self.on_selection_changed) self.treeview.connect("drag-drop", self.on_drag_drop) self.treeview.connect("key-press-event", self.on_key_press_event) @@ -431,7 +430,15 @@ class TorrentView(listview.ListView, component.Component): """Start the torrentview""" # We need to get the core session state to know which torrents are in # the session so we can add them to our list. - component.get("SessionProxy").get_torrents_status({}, []).addCallback(self._on_session_state) + # Only get the status fields required for the visible columns + status_fields = [] + for listview_column in self.columns.values(): + if listview_column.column.get_visible(): + if not listview_column.status_field: + continue + status_fields.extend(listview_column.status_field) + component.get("SessionProxy").get_torrents_status( + {}, status_fields).addCallback(self._on_session_state) def _on_session_state(self, state): self.treeview.freeze_child_notify() diff --git a/deluge/ui/sessionproxy.py b/deluge/ui/sessionproxy.py index af485a458..c6132f543 100644 --- a/deluge/ui/sessionproxy.py +++ b/deluge/ui/sessionproxy.py @@ -58,7 +58,7 @@ class SessionProxy(component.Component): component.Component.__init__(self, "SessionProxy", interval=5) # Set the cache time in seconds - # This is how long data will be valid before refetching from the core + # This is how long data will be valid before re-fetching from the core self.cache_time = 1.5 # Hold the torrents' status.. {torrent_id: [time, {status_dict}], ...} @@ -72,16 +72,25 @@ class SessionProxy(component.Component): client.register_event_handler("TorrentAddedEvent", self.on_torrent_added) def start(self): - def on_torrent_status(status): - # Save the time we got the torrent status - t = time.time() - for key, value in status.iteritems(): - self.torrents[key] = [t, value] - self.cache_times[key] = {} - for ikey in value.iterkeys(): - self.cache_times[key][ikey] = t - - return client.core.get_torrents_status({}, [], True).addCallback(on_torrent_status) + def on_get_session_state(torrent_ids): + for torrent_id in torrent_ids: + # Let's at least store the torrent ids with empty statuses + # so that upcoming queries or status updates don't throw errors. + self.torrents.setdefault(torrent_id, [time.time(), {}]) + self.cache_times.setdefault(torrent_id, {}) + # These initial keys are the ones used for the visible columns(by + # default) on the GTK UI torrent view. If either the console-ui + # or the web-ui needs additional keys, add them here; + # There's NO need to fetch every bit of status information from + # core if it's not going to be used. Additional status fields + # will be queried later, for example, when viewing the status tab + # of a torrent. + inital_keys = [ + 'queue', 'state', 'name', 'total_wanted', 'progress', 'state', + 'download_payload_rate', 'upload_payload_rate', 'eta' + ] + self.get_torrents_status({'id': torrent_ids}, inital_keys) + return client.core.get_session_state().addCallback(on_get_session_state) def stop(self): client.deregister_event_handler("TorrentStateChangedEvent", self.on_torrent_state_changed) @@ -134,7 +143,7 @@ class SessionProxy(component.Component): keys = self.torrents[torrent_id][1].keys() for key in keys: - if time.time() - self.cache_times[torrent_id][key] > self.cache_time: + if time.time() - self.cache_times[torrent_id].get(key, 0.0) > self.cache_time: keys_to_get.append(key) if not keys_to_get: @@ -243,8 +252,8 @@ class SessionProxy(component.Component): def on_torrent_state_changed(self, torrent_id, state): if torrent_id in self.torrents: - self.torrents[torrent_id][1]["state"] = state - self.cache_times[torrent_id]["state"] = time.time() + self.torrents[torrent_id][1].setdefault("state", state) + self.cache_times.setdefault(torrent_id, {}).update(state=time.time()) def on_torrent_added(self, torrent_id, from_state): self.torrents[torrent_id] = [time.time() - self.cache_time - 1, {}]