Performance improvements - console should now be much faster with many torrents and slightly faster to somewhat slower with few

This commit is contained in:
Asmageddon 2012-06-04 17:44:06 +02:00
parent 7a55a2e6ce
commit 08f5841522
3 changed files with 45 additions and 28 deletions

View File

@ -256,8 +256,9 @@ SEARCH_END_REACHED = 4
class AllTorrents(BaseMode, component.Component): class AllTorrents(BaseMode, component.Component):
def __init__(self, stdscr, encoding=None): def __init__(self, stdscr, encoding=None):
self.formatted_rows = None
self.torrent_names = None self.torrent_names = None
self.numtorrents = -1
self._cached_rows = {}
self.cursel = 1 self.cursel = 1
self.curoff = 1 # TODO: this should really be 0 indexed self.curoff = 1 # TODO: this should really be 0 indexed
self.column_string = "" self.column_string = ""
@ -411,15 +412,13 @@ class AllTorrents(BaseMode, component.Component):
def set_state(self, state, refresh): def set_state(self, state, refresh):
self.curstate = state # cache in case we change sort order self.curstate = state # cache in case we change sort order
newnames = [] newnames = []
newrows = [] self._cached_rows = {}
self._sorted_ids = self._sort_torrents(self.curstate) self._sorted_ids = self._sort_torrents(self.curstate)
for torrent_id in self._sorted_ids: for torrent_id in self._sorted_ids:
ts = self.curstate[torrent_id] ts = self.curstate[torrent_id]
newnames.append(ts["name"]) newnames.append(ts["name"])
newrows.append((format_utils.format_row([column.get_column_value(name,ts) for name in self.__columns],self.column_widths),ts["state"]))
self.numtorrents = len(state) self.numtorrents = len(state)
self.formatted_rows = newrows
self.torrent_names = newnames self.torrent_names = newnames
if refresh: if refresh:
self.refresh() self.refresh()
@ -529,6 +528,7 @@ class AllTorrents(BaseMode, component.Component):
cmp_func = self._queue_sort cmp_func = self._queue_sort
sg = state.get
def sort_by_field(state, result, field): def sort_by_field(state, result, field):
if field in column_names_to_state_keys: if field in column_names_to_state_keys:
field = column_names_to_state_keys[field] field = column_names_to_state_keys[field]
@ -541,8 +541,8 @@ class AllTorrents(BaseMode, component.Component):
if field in first_element: if field in first_element:
is_string = isinstance( first_element[field], basestring) is_string = isinstance( first_element[field], basestring)
sort_key = lambda s:state.get(s)[field] sort_key = lambda s:sg(s)[field]
sort_key2 = lambda s:state.get(s)[field].lower() sort_key2 = lambda s:sg(s)[field].lower()
#If it's a string, sort case-insensitively but preserve A>a order #If it's a string, sort case-insensitively but preserve A>a order
if is_string: if is_string:
@ -806,23 +806,40 @@ class AllTorrents(BaseMode, component.Component):
pass pass
# add all the torrents # add all the torrents
if self.formatted_rows == []: if self.numtorrents == 0:
msg = "No torrents match filter".center(self.cols) msg = "No torrents match filter".center(self.cols)
self.add_string(3, "{!info!}%s"%msg) self.add_string(3, "{!info!}%s"%msg)
elif self.formatted_rows: elif self.numtorrents > 0:
tidx = self.curoff tidx = self.curoff
currow = 2 currow = 2
#Because dots are slow
sorted_ids = self._sorted_ids
curstate = self.curstate
gcv = column.get_column_value
fr = format_utils.format_row
cols = self.__columns
colw = self.column_widths
cr = self._cached_rows
def draw_row(index):
if index not in cr:
ts = curstate[sorted_ids[index]]
cr[index] = (fr([gcv(name,ts) for name in cols],colw),ts["state"])
return cr[index]
if lines: if lines:
todraw = [] todraw = []
for l in lines: for l in lines:
try: if l < tidx - 1: continue
todraw.append(self.formatted_rows[l]) if l >= tidx - 1 + self.rows - 3: break
except: if l >= self.numtorrents: break
pass #A quick and ugly fix for crash caused by doing shift-m on last torrent todraw.append(draw_row(l))
lines.reverse() lines.reverse()
else: else:
todraw = self.formatted_rows[tidx-1:] todraw = []
for i in range(tidx-1, tidx-1 + self.rows - 3):
if i >= self.numtorrents: break
todraw += [draw_row(i)]
for row in todraw: for row in todraw:
# default style # default style
@ -1083,7 +1100,7 @@ class AllTorrents(BaseMode, component.Component):
reactor.stop() reactor.stop()
return return
if self.formatted_rows==None or self.popup: if self.numtorrents == 0 or self.popup:
return return
elif self.entering_search: elif self.entering_search:

View File

@ -75,18 +75,15 @@ def get_column_value(name,state):
log.error("No such column: %s",name) log.error("No such column: %s",name)
return None return None
if col[1] != None: if col[1]:
args = []
try: try:
for key in col[0]: args = [ state[key] for key in col[0] ]
args.append(state[key])
except: except:
log.error("Could not get column field: %s",col[0]) log.error("Could not get column field: %s",col[0])
return None return None
colval = col[1](*args) return col[1](*args)
else: else:
colval = state[col[0][0]] return state[col[0][0]]
return colval
def get_required_fields(cols): def get_required_fields(cols):

View File

@ -104,15 +104,18 @@ def trim_string(string, w, have_dbls):
else: else:
return u"%s "%(string[0:w-1]) return u"%s "%(string[0:w-1])
#Dots are slow
eaw = unicodedata.east_asian_width
ud_normalize = unicodedata.normalize
def format_column(col, lim): def format_column(col, lim):
dbls = 0 dbls = 0
if haveud and isinstance(col,unicode): #Chosen over isinstance(col, unicode) and col.__class__ == unicode
# for speed - it's ~3 times faster for non-unicode strings and ~1.5
# for unicode strings.
if haveud and col.__class__ is unicode:
# might have some double width chars # might have some double width chars
col = unicodedata.normalize("NFC",col) col = ud_normalize("NFC",col)
for c in col: dbls = sum(eaw(c) in 'WF' for c in col)
if unicodedata.east_asian_width(c) in ['W','F']:
# found a wide/full char
dbls += 1
size = len(col)+dbls size = len(col)+dbls
if (size >= lim - 1): if (size >= lim - 1):
return trim_string(col,lim,dbls>0) return trim_string(col,lim,dbls>0)