Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screen optimizations #160

Open
wants to merge 54 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8513fe8
Upgrade pyperf (drop support for Python 2.x)
eldipa Jun 17, 2022
cabc0a5
Allow change the screen geometry
eldipa Jun 17, 2022
940e19b
Impl benchmark tests for screen.display, .reset and .resize
eldipa Jun 17, 2022
0b8007a
Impl script to run a full benchmark
eldipa Jun 18, 2022
e0b0e8b
Fix benchmark.py using ByteStream and not Stream
eldipa Jul 2, 2022
eec4a2e
Enable optionally tracemalloc on full benchmark
eldipa Jun 26, 2022
f899535
display meth: iterate over data entries filling the gap between
eldipa Jun 18, 2022
b3b7db4
Inline generator into display inner loop
eldipa Jun 18, 2022
de59245
Move assert out of prod code
eldipa Jun 20, 2022
020fce6
Cache in Char its width
eldipa Jun 20, 2022
8e7ee07
Pre-fetch attributes on screen.draw (x1.20 to x2.0 faster)
eldipa Jun 26, 2022
d4d2e4a
Allow temporal cursor_x > columns (x1.05 to x1.14 faster)
eldipa Jun 26, 2022
945b19b
Make Char mutable (not a namedtuple) (API may break)
eldipa Jun 26, 2022
e881d25
Refactor Char's style in a separated namedtuple object.
eldipa Jun 26, 2022
5f784ec
Reuse/share char styles (x1.05 to x1.30 lighter)
eldipa Jun 26, 2022
9721698
Update Chars in-place instead of recreating them (x1.20 and x1.90 fas…
eldipa Jun 27, 2022
e49fb3f
Fix test_reverse_index (history) due old API
eldipa Jun 29, 2022
d94299d
Use binary search over non-empty lines on index/reverse_index
eldipa Jun 29, 2022
912028f
Minor optimizations.
eldipa Jul 2, 2022
4c04935
Calculate statistics about buffer's and lines' internals (no stable API)
eldipa Jul 2, 2022
84cd21f
On screen.buffer return a read-only view (BufferView/LineView)
eldipa Jul 4, 2022
5ae46bc
Minor lookup prefetch.
eldipa Jul 5, 2022
da66a7e
Do not unintentionally create empty lines
eldipa Jul 5, 2022
1fd373a
Add blankcs Stats
eldipa Jul 6, 2022
b8250ea
Use a space for padding screen.display
eldipa Jul 6, 2022
8d71528
Replace line's default style instead overwriting its char
eldipa Jul 6, 2022
71ab12a
Fix a bug on index that top line was not removed.
eldipa Jul 6, 2022
01f96bc
BufferView not longer add new lines on iteration.
eldipa Jul 6, 2022
70d4b15
Try to delete entries on erase instead of write spaces
eldipa Jul 6, 2022
4a15d3a
Impl prev_page/next_page with sparse iteration
eldipa Jul 8, 2022
6b4f088
Make lines in history a LineView and make Line raise on non-key
eldipa Jul 8, 2022
13cf059
Test sparsity on index and reverse_index
eldipa Jul 8, 2022
a4e7ed5
Test sparsity of insert_lines/delete_lines (fix bug on delete_lines)
eldipa Jul 8, 2022
3056742
Test sparsity on insert_characters/delete_characters/erase_characters
eldipa Jul 8, 2022
f96ab6b
Impl repr of a Char
eldipa Jul 8, 2022
70763b6
Extend erase_* meth tests for sparsity and cursor attr usage (fixed a…
eldipa Jul 8, 2022
51e79a6
Make erase_in_display conformant (test with non-default cursor attrs)
eldipa Jul 8, 2022
47d7c62
Sparse iteration of insert_characters and delete_characters
eldipa Jul 8, 2022
b4258e1
Add more checks to tests; fix bug on after_event and make it sparse-a…
eldipa Jul 8, 2022
f178712
Impl sparse iteration for insert_lines/delete_lines; fix insert_chara…
eldipa Jul 9, 2022
05c8c2c
Sparse iter for erase_characters/erase_in_line
eldipa Jul 9, 2022
80aa50a
Impl resize with sparse iter
eldipa Jul 9, 2022
1bee165
Optional use a dummy set for tracking dirty lines
eldipa Jul 9, 2022
065b31d
Binary search for the tabstop
eldipa Jul 9, 2022
8f11049
Make (0, lines-1) the default margin instead of None
eldipa Jul 9, 2022
01b7d56
Make internal _buffer a dict and not a defaultdict
eldipa Jul 9, 2022
e3fdf41
Optionally disable display graphic attributes
eldipa Jul 9, 2022
7839ded
Replace explicit for-loops with map calls
eldipa Jul 9, 2022
2ca29a5
Pass track_dirty_lines and disable_display_graphic to HistoryScreen
eldipa Jul 10, 2022
c589265
Document what are and how to interpret the LineStats and BufferStats
eldipa Jul 10, 2022
1b42c89
Fuzzy tests *_characters and *_lines methods
eldipa Jul 10, 2022
c65ac82
Improve the docs (plus minor fixes on Line and BufferView)
eldipa Jul 10, 2022
f4ea46a
Impl compressed_display to optionally avoid left/right spaces, top/bo…
eldipa Jul 10, 2022
ba980a0
Optimize the insert/delete characters/lines with map-loops
eldipa Jul 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ Contributors
- Byron Roosa
- Andrew Crozier
- @eight04
- Martin Di Paola @eldipa
67 changes: 59 additions & 8 deletions benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
.....................
ls.input: Mean +- std dev: 644 ns +- 23 ns

$ BENCHMARK=tests/captured/ls.input GEOMETRY=1024x1024 python benchmark.py -o results.json
.....................
ls.input: Mean +- std dev: 644 ns +- 23 ns

Environment variables:

BENCHMARK: the input file to feed pyte's Stream and render on the Screen
GEOMETRY: the dimensions of the screen with format "<lines>x<cols>" (default 24x80)

:copyright: (c) 2016-2021 by pyte authors and contributors,
see AUTHORS for details.
:license: LGPL, see LICENSE for more details.
Expand All @@ -27,21 +36,63 @@

import pyte


def make_benchmark(path, screen_cls):
with io.open(path, "rt", encoding="utf-8") as handle:
def setup(path, screen_cls, columns, lines, optimize_conf):
with io.open(path, "rb") as handle:
data = handle.read()

stream = pyte.Stream(screen_cls(80, 24))
extra_args = {}
if optimize_conf:
extra_args = {
'track_dirty_lines': False,
'disable_display_graphic': True,
}

screen = screen_cls(columns, lines, **extra_args)
stream = pyte.ByteStream(screen)

return data, screen, stream

def make_stream_feed_benchmark(path, screen_cls, columns, lines, optimize_conf):
data, _, stream = setup(path, screen_cls, columns, lines, optimize_conf)
return partial(stream.feed, data)

def make_screen_display_benchmark(path, screen_cls, columns, lines, optimize_conf):
data, screen, stream = setup(path, screen_cls, columns, lines, optimize_conf)
stream.feed(data)
return lambda: screen.display

def make_screen_reset_benchmark(path, screen_cls, columns, lines, optimize_conf):
data, screen, stream = setup(path, screen_cls, columns, lines, optimize_conf)
stream.feed(data)
return screen.reset

def make_screen_resize_half_benchmark(path, screen_cls, columns, lines, optimize_conf):
data, screen, stream = setup(path, screen_cls, columns, lines, optimize_conf)
stream.feed(data)
return partial(screen.resize, lines=lines//2, columns=columns//2)

if __name__ == "__main__":
benchmark = os.environ["BENCHMARK"]
sys.argv.extend(["--inherit-environ", "BENCHMARK"])
lines, columns = map(int, os.environ.get("GEOMETRY", "24x80").split('x'))
optimize_conf = int(os.environ.get("OPTIMIZECONF", "0"))
sys.argv.extend(["--inherit-environ", "BENCHMARK,GEOMETRY,OPTIMIZECONF"])

runner = Runner()

for screen_cls in [pyte.Screen, pyte.DiffScreen, pyte.HistoryScreen]:
name = os.path.basename(benchmark) + "->" + screen_cls.__name__
runner.bench_func(name, make_benchmark(benchmark, screen_cls))
metadata = {
'input_file': benchmark,
'columns': columns,
'lines': lines,
'optimize_conf': optimize_conf
}

benchmark_name = os.path.basename(benchmark)
for screen_cls in [pyte.Screen, pyte.HistoryScreen]:
screen_cls_name = screen_cls.__name__
for make_test in (make_stream_feed_benchmark, make_screen_display_benchmark, make_screen_reset_benchmark, make_screen_resize_half_benchmark):
scenario = make_test.__name__[5:-10] # remove make_ and _benchmark

name = f"[{scenario} {lines}x{columns}] {benchmark_name}->{screen_cls_name}"
metadata.update({'scenario': scenario, 'screen_cls': screen_cls_name})
runner.bench_func(name, make_test(benchmark, screen_cls, columns, lines, optimize_conf), metadata=metadata)

51 changes: 51 additions & 0 deletions full_benchmark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/bash

if [ "$#" != "1" -a "$#" != "2" ]; then
echo "Usage benchmark.sh <outputfile>"
echo "Usage benchmark.sh <outputfile> tracemalloc"
exit 1
fi

if [ "$2" = "tracemalloc" ]; then
tracemalloc="--tracemalloc"
elif [ "$2" = "" ]; then
tracemalloc=""
else
echo "Usage benchmark.sh <outputfile>"
echo "Usage benchmark.sh <outputfile> tracemalloc"
exit 1
fi

outputfile=$1

if [ ! -f benchmark.py ]; then
echo "File benchmark.py missing. Are you in the home folder of pyte project?"
exit 1
fi

for inputfile in $(ls -1 tests/captured/*.input); do
export GEOMETRY=24x80
echo "$inputfile - $GEOMETRY"
echo "======================"
BENCHMARK=$inputfile python benchmark.py $tracemalloc --append $outputfile

export GEOMETRY=240x800
echo "$inputfile - $GEOMETRY"
echo "======================"
BENCHMARK=$inputfile python benchmark.py $tracemalloc --append $outputfile

export GEOMETRY=2400x8000
echo "$inputfile - $GEOMETRY"
echo "======================"
BENCHMARK=$inputfile python benchmark.py $tracemalloc --append $outputfile

export GEOMETRY=24x8000
echo "$inputfile - $GEOMETRY"
echo "======================"
BENCHMARK=$inputfile python benchmark.py $tracemalloc --append $outputfile

export GEOMETRY=2400x80
echo "$inputfile - $GEOMETRY"
echo "======================"
BENCHMARK=$inputfile python benchmark.py $tracemalloc --append $outputfile
done
Loading