-
Notifications
You must be signed in to change notification settings - Fork 0
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
Profiling and performance improvements #6
Comments
Found a way to reduce time of |
Great! Thank you. I’ll check out tomorrow.
T
…On Tue, Jan 9, 2024 at 7:14 PM krackers ***@***.***> wrote:
Found a way to reduce time of builtin.eval. Python can precompile string
to bytecode, with compile which can be passed to eval. Doing this
basically optimizes as much as possible I think, only remaining is
translate_preset_variables and string_splitter which is going to be
unavoidable
—
Reply to this email directly, view it on GitHub
<#6 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AYBHA75WL673NCDZYRZT3STYNYBSDAVCNFSM6AAAAAA37OBJQSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBUGEZDIOBTGU>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Hi,
Just getting back to this. Sorry, Hollywood was upended for a bit which
really affected me.
Do you have a version of pyp with all of your improvements?
I'd love to test it and then maybe incorporate some or all of them into a
beta.
what were your final quantitative numbers in terms of speedup?
thanks,
Toby
…On Tue, Jan 9, 2024 at 7:14 PM krackers ***@***.***> wrote:
Found a way to reduce time of builtin.eval. Python can precompile string
to bytecode, with compile which can be passed to eval. Doing this
basically optimizes as much as possible I think, only remaining is
translate_preset_variables and string_splitter which is going to be
unavoidable
—
Reply to this email directly, view it on GitHub
<#6 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AYBHA75WL673NCDZYRZT3STYNYBSDAVCNFSM6AAAAAA37OBJQSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBUGEZDIOBTGU>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
I've uploaded the version I use at https://gist.github.com/krackers/3443b5e175096ba5e790360353a864cc Note that since it's the version I use personally it's got some other fixes/changes as well, and is suited to my needs/tastes (e.g. look at the other issues I opened in this repo, some of these are probably API breaking – especially the switch to generators for If I remember correctly, this issue in particular came from two observations: we were splitting unnecessarily even the results were never going to be used, and the repeated As for benchmark, re-running the same command as in opening post
i get
But again this is with basically a mix of changes included and I don't really want to go through and create a clean PR for just the |
awesome, thank you for this. This is what I need. I can piece it together
for sure.
Do you happen to know what the stock pyp gives for the same test?
t
…On Thu, Nov 14, 2024 at 11:12 AM krackers ***@***.***> wrote:
I've uploaded the version I use at
https://gist.github.com/krackers/3443b5e175096ba5e790360353a864cc
Note that since it's the version I use it's got some other fixes/changes
as well (for the other issues I opened), but some of these are probably API
breaking (especially the switch to generators for pp). Note that if I
remember correctly, this issue in particular came from two observations: we
were splitting unnecessarily even the results were never going to be used,
and the repeated builtin.eval. "Fixing" the former technically requires
losing some features, while the latter can be fixed without any loss in
features.
As for benchmark, re-running the same command as in opening post
seq 1 235976 | python3 -m cProfile -s tottime $(which pyp) "p | pp[-1]"
i get
235976
10401075 function calls (10400749 primitive calls) in 2.735 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
235977 0.576 0.000 0.976 0.000 pyp:1843(process_line)
235976 0.331 0.000 0.985 0.000 pyp:443(__init__)
471952 0.226 0.000 0.383 0.000 posixpath.py:100(split)
235978 0.126 0.000 0.162 0.000 pyp:1484(update_history)
235976 0.118 0.000 0.212 0.000 pyp:1597(format_history)
235976 0.095 0.000 0.095 0.000 pyp:134(__init__)
235976 0.089 0.000 0.169 0.000 pyp:539(split)
235977 0.085 0.000 0.096 0.000 pyp:1416(safe_eval)
235977 0.083 0.000 1.251 0.000 pyp:2015(<genexpr>)
235979 0.077 0.000 2.304 0.000 pyp:1838(<genexpr>)
2 0.068 0.034 2.718 1.359 more.py:2437(_islice_helper)
235976 0.064 0.000 0.083 0.000 pyp:1990(strip_last_newline)
235976 0.062 0.000 0.062 0.000 pyp:741(__init__)
235977 0.061 0.000 2.634 0.000 pyp:1615(<genexpr>)
235976 0.059 0.000 0.086 0.000 pyp:751(__getitem__)
But again this is with basically a mix of changes included and I don't
really want to go through and create a clean PR for *just* the compile
change. Hopefully you can piece together something out of the above though.
—
Reply to this email directly, view it on GitHub
<#6 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AYBHA77FFSICVBIWTZ56YHT2ATYZ7AVCNFSM6AAAAABRZS3O2KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINZXGIYTINJSGQ>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Sure, tested pyp 3.0.9 source straight from pypi, and gives the result
|
fantastic!
thanks
t
…On Thu, Nov 14, 2024 at 11:29 AM krackers ***@***.***> wrote:
Sure, tested pyp 3.0.9 source straight from pypi, and gives the result
> seq 1 235976 | python3 -m cProfile -s tottime $(which pyp) "p | pp[-1]"
235976
98304563 function calls (98304330 primitive calls) in 40.519 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
4955517 8.215 0.000 16.163 0.000 pyp:407(__init__)
236005 5.113 0.000 5.113 0.000 {method 'pop' of 'list' objects}
9911034 4.359 0.000 7.222 0.000 posixpath.py:100(split)
235979 4.267 0.000 4.289 0.000 {built-in method builtins.eval}
4955517 1.833 0.000 19.723 0.000 pyp:1202(<genexpr>)
3 1.609 0.536 1.652 0.551 pyp:1604(stamp_history)
235977 1.336 0.000 36.755 0.000 pyp:1882(process_line)
4719540 1.265 0.000 16.715 0.000 pyp:1202(<listcomp>)
4719540 1.174 0.000 1.174 0.000 pyp:686(__init__)
235982 1.148 0.000 1.148 0.000 {built-in method builtins.dir}
235977 1.076 0.000 21.376 0.000 pyp:1157(string_splitter)
9911041 1.037 0.000 1.559 0.000 posixpath.py:41(_get_sep)
9911066 0.975 0.000 0.975 0.000 {method 'rfind' of 'str' objects}
235977 0.657 0.000 0.910 0.000 pyp:1325(translate_preset_variables)
7315301 0.623 0.000 0.623 0.000 {method 'split' of 'str' objects}
235977 0.606 0.000 2.367 0.000 pyp:1504(update_history)
2 0.576 0.288 2.306 1.153 pyp:1805(format_input)
4955496 0.568 0.000 0.568 0.000 pyp:1912(<genexpr>)
9911670 0.522 0.000 0.522 0.000 {built-in method builtins.isinstance}
707933 0.330 0.000 0.330 0.000 {method 'update' of 'dict' objects}
9911102 0.329 0.000 0.329 0.000 {built-in method posix.fspath}
4956618 0.287 0.000 0.287 0.000 {method 'rstrip' of 'str' objects}
235977 0.259 0.000 4.752 0.000 pyp:1429(safe_eval)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.Message ID: ***@***.***>
|
Hi again,
I've been playing around with this! Pretty cool, much bigger code
changes than I expected! Nice sophisticated iteration work. How long
did this take you?
One thing I found is that the powerPyp lists no longer work...for
example, pp.sort() doesn't work...this should take the whole input and
treat it like a line by line array, so it would give a result similar
to standard UNIX sort.
pp also has an "analysis" mode, so just a plain pp would return the
index per line so you can pick out particular lines easily...for
example:
[0]USER PID %CPU %MEM VSZ RSS TT STAT
STARTED TIME COMMAND
[1]_windowserver 149 40.5 0.7 410221616 62496 ?? Rs
Thu04PM 1046:55.26
/System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer
-daemon
[2]tobyrosen 606 9.7 0.0 408400832 2528 ?? S
Thu04PM 923:56.38
/System/Library/Frameworks/CoreMIDI.framework/MIDIServer
Was this working maybe in an earlier version for you?
cheers,
Toby
…On Thu, Nov 14, 2024 at 11:45 AM tobs ***@***.***> wrote:
fantastic!
thanks
t
On Thu, Nov 14, 2024 at 11:29 AM krackers ***@***.***> wrote:
>
> Sure, tested pyp 3.0.9 source straight from pypi, and gives the result
>
> > seq 1 235976 | python3 -m cProfile -s tottime $(which pyp) "p | pp[-1]"
>
> 235976
> 98304563 function calls (98304330 primitive calls) in 40.519 seconds
>
> Ordered by: internal time
>
> ncalls tottime percall cumtime percall filename:lineno(function)
> 4955517 8.215 0.000 16.163 0.000 pyp:407(__init__)
> 236005 5.113 0.000 5.113 0.000 {method 'pop' of 'list' objects}
> 9911034 4.359 0.000 7.222 0.000 posixpath.py:100(split)
> 235979 4.267 0.000 4.289 0.000 {built-in method builtins.eval}
> 4955517 1.833 0.000 19.723 0.000 pyp:1202(<genexpr>)
> 3 1.609 0.536 1.652 0.551 pyp:1604(stamp_history)
> 235977 1.336 0.000 36.755 0.000 pyp:1882(process_line)
> 4719540 1.265 0.000 16.715 0.000 pyp:1202(<listcomp>)
> 4719540 1.174 0.000 1.174 0.000 pyp:686(__init__)
> 235982 1.148 0.000 1.148 0.000 {built-in method builtins.dir}
> 235977 1.076 0.000 21.376 0.000 pyp:1157(string_splitter)
> 9911041 1.037 0.000 1.559 0.000 posixpath.py:41(_get_sep)
> 9911066 0.975 0.000 0.975 0.000 {method 'rfind' of 'str' objects}
> 235977 0.657 0.000 0.910 0.000 pyp:1325(translate_preset_variables)
> 7315301 0.623 0.000 0.623 0.000 {method 'split' of 'str' objects}
> 235977 0.606 0.000 2.367 0.000 pyp:1504(update_history)
> 2 0.576 0.288 2.306 1.153 pyp:1805(format_input)
> 4955496 0.568 0.000 0.568 0.000 pyp:1912(<genexpr>)
> 9911670 0.522 0.000 0.522 0.000 {built-in method builtins.isinstance}
> 707933 0.330 0.000 0.330 0.000 {method 'update' of 'dict' objects}
> 9911102 0.329 0.000 0.329 0.000 {built-in method posix.fspath}
> 4956618 0.287 0.000 0.287 0.000 {method 'rstrip' of 'str' objects}
> 235977 0.259 0.000 4.752 0.000 pyp:1429(safe_eval)
>
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> You are receiving this because you commented.Message ID: ***@***.***>
|
I think I was noodling with it around last Christmas? Didn't spend too much time on it, just enough so that I could use it as an
Hm this is a good catch. Explicitly converting to list like
works, but even then below does not
(actually python's
So I do know that the analysis feature works for arrays element wise
I don't know what i did that broke it in
would need to be updated, you already have access to |
Ok, cool. Thanks for that info. I'll take a look at it and hopefully it's
not too bad. The powerpipe setup is critical because I have a bunch of
cool methods overloaded for list functions and it simplifies operations
that work on the entire output by having a dedicated list variable. That's
great you found that analysis mode works for arrays element wise...this
implies that the powerpipes will work, but just are not being detected
properly. I'll take a look. Let me know if you have any other insights.
cheers,
Toby
PS this is pp info from the manual if interested. Much of this was to
replace common unix commands we were using constantly at Sony at the time.
pp LIST (all LIST methods like pp.sort(), pp[-1], and pp.reverse() work
-
- pp.before(STRING, N) searches for STRING, colsolidates N lines BEFORE
it to the same line. Default is 1
- pp.after(STRING, N) searches for STRING, colsolidates N lines AFTER it
to same line. Default is 1.
-
pp.matrix(STRING, N) returns pp.before(STRING, N) and pp.after(STRING,
N). Default is 1.
- pp.uniq() returns only unique elements
- pp.unlist() breaks up ALL arrays up into seperate single lines
- pp.oneline() combines all list elements to one line with spaces
…On Fri, Nov 15, 2024 at 7:45 PM krackers ***@***.***> wrote:
How long did this take you?
I think I was noodling with it around last Christmas? Didn't spend too
much time on it, just enough so that I could use it as an awk replacement
without blowing up memory.
pp.sort() doesn't work...this should take the whole input and treat it
like a line by line array
Hm this is a good catch. Explicitly converting to list like
seq 10 1 | pyp "sorted(list(pp))"
works, but even then
seq 10 1 | pyp "list(pp).sort()"
(actually python's sorted accepts generators so sorted(pp) is
sufficient). I'd need to look through the code again to see why this is,
I'm guessing it's something to do with the fact that since we no longer
operate in-place on a pre-materialized pp array, there's no way to
implicitly "pass" the output of an in-place sort onto the next stage: you
always need to explicitly return something.
pp also has an "analysis" mode, so just a plain pp would return the
index per line so you can pick out particular lines easily...for
example:
So I do know that the analysis feature works for arrays element wise
seq 10 1 | pyp "[p, p, p]"
I don't know what i did that broke it in pp mode. It should definitely be
possible to get it working since adding the indices is an easy operation on
generators. Probably the code near
for idx, out in enumerate(output):
self.n = idx
ignore, result = self.update_history(out,second_stream_input,file_input , None, return_output = True)
if not ignore:
print(result)
would need to be updated, you already have access to idx there, it's just
a matter of formatting it properly on powerpipe output.
—
Reply to this email directly, view it on GitHub
<#6 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AYBHA72FIVTEOQQDMBR2FYL2A25UFAVCNFSM6AAAAABRZS3O2KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOBQGM3TKMZVGY>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Hey again,
It's looking extremely promising...I've modified what you have to get back
the missing array methods and analysis mode behavior. Performance is still
dramatically better than the stock pyp. Still have to do more testing and
get back spp and fpp functions.
t
…On Sat, Nov 16, 2024 at 10:06 AM tobs ***@***.***> wrote:
Ok, cool. Thanks for that info. I'll take a look at it and hopefully
it's not too bad. The powerpipe setup is critical because I have a bunch
of cool methods overloaded for list functions and it simplifies operations
that work on the entire output by having a dedicated list variable. That's
great you found that analysis mode works for arrays element wise...this
implies that the powerpipes will work, but just are not being detected
properly. I'll take a look. Let me know if you have any other insights.
cheers,
Toby
PS this is pp info from the manual if interested. Much of this was to
replace common unix commands we were using constantly at Sony at the time.
pp LIST (all LIST methods like pp.sort(), pp[-1], and pp.reverse() work
-
- pp.before(STRING, N) searches for STRING, colsolidates N lines
BEFORE it to the same line. Default is 1
- pp.after(STRING, N) searches for STRING, colsolidates N lines AFTER
it to same line. Default is 1.
-
pp.matrix(STRING, N) returns pp.before(STRING, N) and pp.after(STRING,
N). Default is 1.
- pp.uniq() returns only unique elements
- pp.unlist() breaks up ALL arrays up into seperate single lines
- pp.oneline() combines all list elements to one line with spaces
On Fri, Nov 15, 2024 at 7:45 PM krackers ***@***.***> wrote:
> How long did this take you?
>
> I think I was noodling with it around last Christmas? Didn't spend too
> much time on it, just enough so that I could use it as an awk
> replacement without blowing up memory.
>
> pp.sort() doesn't work...this should take the whole input and treat it
> like a line by line array
>
> Hm this is a good catch. Explicitly converting to list like
>
> seq 10 1 | pyp "sorted(list(pp))"
>
> works, but even then
>
> seq 10 1 | pyp "list(pp).sort()"
>
> (actually python's sorted accepts generators so sorted(pp) is
> sufficient). I'd need to look through the code again to see why this is,
> I'm guessing it's something to do with the fact that since we no longer
> operate in-place on a pre-materialized pp array, there's no way to
> implicitly "pass" the output of an in-place sort onto the next stage: you
> always need to explicitly return something.
>
> pp also has an "analysis" mode, so just a plain pp would return the
> index per line so you can pick out particular lines easily...for
> example:
>
> So I do know that the analysis feature works for arrays element wise
>
> seq 10 1 | pyp "[p, p, p]"
>
> I don't know what i did that broke it in pp mode. It should definitely
> be possible to get it working since adding the indices is an easy operation
> on generators. Probably the code near
>
> for idx, out in enumerate(output):
> self.n = idx
> ignore, result = self.update_history(out,second_stream_input,file_input , None, return_output = True)
> if not ignore:
> print(result)
>
> would need to be updated, you already have access to idx there, it's
> just a matter of formatting it properly on powerpipe output.
>
> —
> Reply to this email directly, view it on GitHub
> <#6 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AYBHA72FIVTEOQQDMBR2FYL2A25UFAVCNFSM6AAAAABRZS3O2KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOBQGM3TKMZVGY>
> .
> You are receiving this because you commented.Message ID:
> ***@***.***>
>
|
Neat, can you post a diff somewhere? If I have time this Christmas I'll noodle around and see if I can squeeze out more performance improvements. |
ya, totally. Let me get it to the point where it's at parity in terms
of functionality with the released version, and then I'll send
it...should be way before christmas!
cheers,
Toby
…On Thu, Nov 21, 2024 at 2:04 PM krackers ***@***.***> wrote:
I've modified what you have to get back the missing array methods and analysis mode behavior
Neat, can you post a diff somewhere? If I have time this Christmas I'll noodle around and see if I can squeeze out more performance improvements.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.Message ID: ***@***.***>
|
Hey Krackers,
Here is my latest. I've kept all your great speed ups and restored
some of the "classic" pyp behavior. Here is a brief summary of the
fixes:
1) "p, p" evaluates now as a concatenated string, not a tuple. This
also works with "p,w" etc. These are pretty common workflows.
2) selected single powerpipe (ie pp[0]) element turns off powerpipe.
Basically, a one element powerpipe is useless, so we go directly to
one element. This was a surprisingly complicated fix to not disrupt
the generator.
3) sort, max, stats, etc fixed in powerpipes
4) "pp+['asdfd']" now works correctly. Added custom add and radd
methods to powerpipe
5) spp, fpp fixed
Anyways, this all hopefully jives with what you have been doing. I
had to rewrite a couple of the functions in order to get everything to
line up function wise. Anyways, let me know what you think. I'm
planning on sending this to Sony for testing in January. Let me know
if you come up with any more speed ups before then!
Cheers,
Toby
PS This is ver 3.0.11.
…On Thu, Nov 21, 2024 at 2:09 PM tobs ***@***.***> wrote:
ya, totally. Let me get it to the point where it's at parity in terms
of functionality with the released version, and then I'll send
it...should be way before christmas!
cheers,
Toby
On Thu, Nov 21, 2024 at 2:04 PM krackers ***@***.***> wrote:
>
> I've modified what you have to get back the missing array methods and analysis mode behavior
>
> Neat, can you post a diff somewhere? If I have time this Christmas I'll noodle around and see if I can squeeze out more performance improvements.
>
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> You are receiving this because you commented.Message ID: ***@***.***>
|
Is there supposed to be something attached? (Don't see anything in releases page either). Changes 2-4 seem good to me, especially (4) which is a good addition I overlooked. Personally don't like (1) but I realize it's needed for backwards compat, I'll probably just revert that one in my own copy. |
I'm manually reposting this since it didn't appear here although the email was sent. Sorry, I guess attachments don't work. I've posted the changes here as an alpha: https://github.com/thepyedpiper/pyp/releases/tag/v3.0.11 It should be easy to revert (1), it was just a few lines you can kill here: if hasattr(total_output[0], 'iter'): #checks for iterable, otherwise ints break it Glad you like the other stuff! cheers, Toby |
Made several fixes - https://gist.github.com/krackers/3443b5e175096ba5e790360353a864cc Changes were mostly fixing up the other methods in PowerPipeList class to properly handle streaming logic. Additionally some minor changes were made to fix when outputting to non-tty. I didn't test anything related to |
Also the non-minor version should probably be bumped since it's a fairly major rewrite touching a lot of deep internals. I assume you guys have some sort of test suite for this? (since there a lot of subtleties around history management, output formatting, etc. that may have been altered in the rewrite) |
Hey cool, I'll take a look. Ya, that's a good note about version numbers,
we'll bump it up for the beta release. I'll also look into lazy loading,
it's a cool idea, those functions tend to be seldom used in my experience,
but are absolute clutch functions when needed. We have a bunch of standard
tests we run, which caught a lot of the discrepancies in output from the
first revision. So far it's been passing them! I'll be passing this back
to Sony for further testing in the next few weeks. That's the true torture
test, then we'll see!
Hope you had happy holidays!
Toby
…On Sun, Dec 29, 2024 at 7:14 PM krackers ***@***.***> wrote:
Also the non-minor version should probably be bumped since it's a fairly
major rewrite touching a lot of deep internals. I assume you guys have some
sort of test suite for this? (since there a lot of subtleties around
history management, output formatting, etc. that may have been altered in
the rewrite)
—
Reply to this email directly, view it on GitHub
<#6 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AYBHA767NEAQU5JMGJDNW3D2IC3BJAVCNFSM6AAAAABRZS3O2KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNRUHE4DENJZGQ>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
shows a lot of time (~20 out of 28 seconds) is spent in
string_splitter
. Some of this might be unavoidable due to python slowness, but I wonder if there's some cleverness we can do to avoid such heavy performance?The slowdown is the particular line
It's not clear to me what exactly it's doing. If that is removed, then we get the following heavy hitters:
The text was updated successfully, but these errors were encountered: