def loadex():
'''The target of threading.Thread.'''
if 0: # Profile the code.
cProfile.runctx('loadex_helper()',
globals(),
locals(),
'profile_stats', # 'profile-%s.out' % process_name
)
print('===== writing profile_stats')
p = pstats.Stats('profile_stats')
p.strip_dirs().sort_stats('tottime').print_stats(50)
# .print_stats('leoDataModel.py', 50)
else:
loadex_helper()
def loadex_helper():
ltm2 = LeoTreeModel.frombytes(ltmbytes)
loaddir = os.path.dirname(fname)
loadExternalFiles(ltm2, loaddir)
G.q.put(ltm2)1. Limited to leoDataModel.py:
TotTime:
ncalls tottime percall cumtime percall filename:lineno(function)
8212 0.267 0.000 0.586 0.000 leoDataModel.py:1233(load_derived_file)
8212 0.023 0.000 0.611 0.000 leoDataModel.py:1569(viter)
8047 0.017 0.000 0.024 0.000 leoDataModel.py:1327(set_node)
Calls:
ncalls tottime percall cumtime percall filename:lineno(function)
16691 0.003 0.000 0.006 0.000 leoDataModel.py:37(parPosIter)
8212 0.268 0.000 0.587 0.000 leoDataModel.py:1233(load_derived_file)
8212 0.023 0.000 0.612 0.000 leoDataModel.py:1569(viter)
8047 0.017 0.000 0.023 0.000 leoDataModel.py:1327(set_node)
971 0.000 0.000 0.001 0.000 leoDataModel.py:293(parents)
806/165 0.001 0.000 0.001 0.000 leoDataModel.py:412(updateParentSize) (in replaceNode)
2. Including all methods:
TotTime:
ncalls tottime percall cumtime percall filename:lineno(function)
8212 0.272 0.000 0.594 0.000 leoDataModel.py:1233(load_derived_file)
626060 0.220 0.000 0.220 0.000 {method 'match' of '_sre.SRE_Pattern' objects}
232802 0.036 0.000 0.036 0.000 {method 'startswith' of 'str' objects}
165 0.021 0.000 0.030 0.000 {method 'read' of '_io.TextIOWrapper' objects}
Calls:
ncalls tottime percall cumtime percall filename:lineno(function)
626060 0.221 0.000 0.221 0.000 {method 'match' of '_sre.SRE_Pattern' objects}
232802 0.036 0.000 0.036 0.000 {method 'startswith' of 'str' objects}
167416 0.014 0.000 0.014 0.000 {method 'append' of 'list' objects}
110420 0.008 0.000 0.008 0.000 {built-in method builtins.len}
95453 0.007 0.000 0.007 0.000 {method 'isspace' of 'str' objects}
35554 0.006 0.000 0.006 0.000 {method 'group' of '_sre.SRE_Match' objects}
16357 0.001 0.000 0.001 0.000 {method 'random' of '_random.Random' objects}
8906 0.002 0.000 0.002 0.000 {method 'pop' of 'list' objects}
8562 0.006 0.000 0.006 0.000 {method 'join' of 'str' objects}
2204 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}Summaryload_derived_file is incredibly fast. When loading .leo files, only it's performance matters.
The only truly important performance metric is how long it takes miniTkLeo.py to load a substantial .leo file. I changed this file so it loads my private leoPy.leo file if no file is given on the command line.
from leo.core.leoQt import QtCoreimport datetimedef traverse_tree(t1): p = c.p def move_next(): if p.hasChildren() and not p.isExpanded(): p.expand() p.moveToThreadNext() if p: c.selectPosition(p) c.redraw(p) QtCore.QTimer.singleShot(0, move_next) else: t2 = datetime.datetime.utcnow() dt = t2 - t1 t = dt.seconds + dt.microseconds / 1e6 g.es('Finished after %fs'%t) move_next()c.selectPosition(c.rootPosition())c.contractAllHeadlines()c.redraw()t1 = datetime.datetime.utcnow()traverse_tree(t1)def traverse_speed(x): import datetime ltm.selectedPosition = ltm.positions[1] ltm.expanded.clear() ltm.invalidate_visual() draw_tree(tree, ltm) def tf(i): alt_right(None) if i < len(ltm.positions): tree.after_idle(tf, i + 1) else: dt = datetime.datetime.utcnow() - t1 t = dt.seconds + 1e-6*dt.microseconds G.log.insert('end -1 ch', 'Finished in %fs\n'%t) t1 = datetime.datetime.utcnow() tf(1)
G.app.bind_all('<Shift-F10>', traverse_speed)
Finished in 1.067294s
Finished after 41.404681s
Finished in 98.063228s
Thanks for the thorough investigation of the prototype.
The only truly important performance metric is how long it takes miniTkLeo.py to load a substantial .leo file. I changed this file so it loads my private leoPy.leo file if no file is given on the command line.Well I think this is just one. The other maybe even more important is how fast tree drawing is.
load_derived_file is incredibly fast.
if not special and not patterns.union.match(line):
<< handle indentation, and add the line >>if not(special or union.match(line) or union2.match(line):
<< handle indentation, and add the line >>On Thursday, May 31, 2018 at 5:02:47 AM UTC-5, Edward K. Ream wrote:load_derived_file is incredibly fast.The main loop, << iterate all other lines >> might be made significantly faster by short-circuiting most tests at the start of the loop.
if not (
verbatim or line == verbline or
in_doc or line.strip().startswith(delim_st)
):
# unindent the line if necessary
if indent and line[:indent].isspace() and len(line) > indent:
line = line[indent:]
body.append(line)
continueAre you sure it is still correct import?
Are you sure it is still correct import?
for i, line in flines[start:]:
# These three sections must be first.
<< handle verbatim lines >>
<< unindent the line if necessary >>
<< short-circuit later tests >># This is valid because all following sections are either:
# 1. guarded by 'if in_doc' or
# 2. guarded by a pattern that matches delim_st + '@'
if not in_doc and not line.strip().startswith(delim_st+'@'):
body.append(line)
continueif not in_doc:
# This guard ensures that the short-circuit tests are valid.
m = doc_pat.match(line)
if m:The other maybe even more important [performance test] is how fast tree drawing is.
if you open in miniTkLeo LeoPyRef.leo and then select the first top-level node and then press and hold left arrow on the keyboard it will traverse all nodes in the outline expanding if necessary.
The test script I use limits the number of redraws to 1000, which should be plenty good enough. That script takes about 6 seconds on my machine.It's tricky to get real stats for the entire run, because most of the script runs at Tk idle time. I'll report back when I find a solution.
def traverse_speed(x):
'''Traverse the entire tree.'''
g.cls()
if profile_redraw:
cProfile.runctx('traverse_speed_helper()',
globals(),
locals(),
'profile_stats', # 'profile-%s.out' % process_name
)
print('===== starting profile_stats')
p = pstats.Stats('profile_stats')
p.sort_stats('ncalls').print_stats(100)
# p.strip_dirs().
# .print_stats('leoDataModel.py', 50)
else:
traverse_speed_helper()
def traverse_speed_helper():
ltm.selectedPosition = ltm.positions[1]
ltm.expanded.clear()
ltm.invalidate_visual()
draw_tree(tree, ltm)
def tf(i):
if profile_redraw:
n_positions = len(ltm.positions)
n = min(1000, n_positions)
for i in range(n):
# From alt_right:
bw = G.body
gnx = ltm.select_node_right()
if gnx:
body = ltm.attrs[gnx][1]
bw.replace('1.0', 'end', body)
draw_tree(tree, ltm)
print('===== writing profile_stats')
p = pstats.Stats('profile_stats')
p.strip_dirs().sort_stats('tottime').print_stats(50)
# .print_stats('leoDataModel.py', 50)
else:
alt_right(None)
if i < 500 and i < n_positions:
tree.after_idle(tf, i + 1)
dt = datetime.datetime.utcnow() - t1
t = dt.seconds + 1e-6*dt.microseconds
G.log.insert('end -1 ch', '%s iterations in %6.2f sec\n'%(n,t))
t1 = datetime.datetime.utcnow()
tf(1)
G.app.bind_all('<Shift-F10>', traverse_speed)TotTime:
ncalls tottime percall cumtime percall filename:lineno(function)
2001 0.162 0.000 1.995 0.001 miniTkLeo.py:302(draw_loop)
30005 0.074 0.000 0.091 0.000 leoDataModel.py:482(display_items)
----------
159149 1.225 0.000 1.751 0.000 {method 'call' of '_tkinter.tkapp' objects}
64080 0.118 0.000 0.174 0.000 tkinter\__init__.py:1309(_options)
64062 0.108 0.000 1.065 0.000 tkinter\__init__.py:1460(_configure)
NCalls:
ncalls tottime percall cumtime percall filename:lineno(function)
30005 0.074 0.000 0.091 0.000 leoDataModel.py:482(display_items)
4001 0.002 0.000 0.026 0.000 leoDataModel.py:312(selectedIndex)
3000 0.004 0.000 1.187 0.001 miniTkLeo.py:452(proxycmd)
2001 0.162 0.000 2.006 0.001 miniTkLeo.py:302(draw_loop)
2001 0.008 0.000 2.045 0.001 miniTkLeo.py:290(draw_tree)
2001 0.003 0.000 0.012 0.000 miniTkLeo.py:469(rows_count)
----------
348928 0.054 0.000 0.054 0.000 {built-in method builtins.isinstance}
159149 1.234 0.000 1.764 0.000 {method 'call' of '_tkinter.tkapp' objects}
128160 0.026 0.000 0.026 0.000 {built-in method _tkinter._flatten}
128142 0.099 0.000 0.155 0.000 tkinter\__init__.py:93(_cnfmerge)
92088 0.008 0.000 0.008 0.000 {built-in method builtins.callable}
86022 0.032 0.000 0.032 0.000 {method 'splitlist' of '_tkinter.tkapp' objects}
84021 0.094 0.000 0.633 0.000 tkinter\__init__.py:2458(coords)
84021 0.013 0.000 0.013 0.000 tkinter\__init__.py:2461(<listcomp>)
65191 0.008 0.000 0.008 0.000 {method 'items' of 'dict' objects}
64098 0.015 0.000 0.015 0.000 {method 'update' of 'dict' objects}
64080 0.118 0.000 0.175 0.000 tkinter\__init__.py:1309(_options)
64062 0.033 0.000 1.105 0.000 tkinter\__init__.py:2565(itemconfigure)
64062 0.111 0.000 1.072 0.000 tkinter\__init__.py:1460(_configure)
63854 0.007 0.000 0.007 0.000 {built-in method builtins.len}