You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
timeit called from within Python should allow autoranging #50671
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee='https://github.com/stevendaprano'closed_at=<Date2019-03-28.09:50:03.233>created_at=<Date2009-07-05.15:15:10.511>labels= ['type-feature', 'library']
title='timeit called from within Python should allow autoranging'updated_at=<Date2019-03-28.09:50:03.232>user='https://bugs.python.org/scottdaniels'
In bpo-5442, I proposed leaving the architecture of the module alone, and
simply exposing the main module functionality as a high level helper
function:
Agreed with Nick's approach above.
Victor, if you want to improve timeit's reliability, please open a separate issue.
I'm confused by the feedback on the patch. It adds a single new function, doesn't alter the public interface for any existing functions, and seems fit for purpose. Could someone help me understand how its deficient?
The current patch moves print operations inside timeit() and repeat(), instead of leaving the main() function as the only one with side effects.
My counter-proposal was to instead extract the current main functionality out into a side-effect free public API of its own, and change the existing main function to call that new API and print the results.
This issue seems to have lost momentum, I'd like to revive it by proposing a slightly different interface for the autorange function.
Attached is a proof-of-concept patch. I've moved the code which determines the number of loops out of the main function into a new Timer method, autorange. The main difference between my approach and Scott's is that my autorange method doesn't do any printing directly, it takes an optional callback function. This lets the caller take responsibility for all output.
If this approach is acceptable, I hope to:
(in 3.6) add tests and docs for the new method;
(in 3.6 if time permits, otherwise 3.7) modify the timeit and repeat methods and functions so that they can optionally call autorange(), e.g. if the caller passes 0 as the number.
I'm not sure that there's a good reason to add a top-level autorange() function to match the timeit() and repeat() functions. Especially not once they gain the ability to autorange themselves.
I think my approach will be compatible with cleaning up and refactoring the main() function. At the moment, main() is a mess IMO, it handles argument processing, autoranging, units of time, and unreliable timing detection all from one function.
I would suggest making the 0.2 tunable as an optional argument. Different applications (benchmarks) may want different duration / precision tradeoffs.
I also notice the repeat functionality isn't included in the patch, is there a reason?
The embedded side-effects were my main concern with Scott's original patch, so Steven's callback-based approach strikes me as a definite improvement. However, the awkwardness of the revised calling code in main does make me wonder whether or not this might be better implemented as a generator rather than as a function accepting a callback:
try:
results = list(t.autorange())
except:
t.print_exc()
return 1
if verbose:
for number, time_taken in results:
msg = "{} loops -> {:.{}g} secs"
print(msg.format(number, time_taken, precision))
(Originally I had the "if verbose: print" embedded in a direct loop over t.autorange(), but writing it that way made it immediately clear that the scope of the exception handler was too broad, so I changed it to extract all the results and only then print them)
On Thu, May 12, 2016 at 04:49:59AM +0000, Nick Coghlan wrote:
The embedded side-effects were my main concern with Scott's original
patch, so Steven's callback-based approach strikes me as a definite
improvement. However, the awkwardness of the revised calling code in
main does make me wonder whether or not this might be better
implemented as a generator rather than as a function accepting a
callback:
I thought about a generator too, but then I thought about the *non*
verbose case, where you don't care about the intermediate results, only
the final (number, time_taken) pair.
# function with callback:
number, time_taken = t.autorange()
Good point - given that, +1 from me for the callback based version, especially since exception chaining will still disambiguate failures in the callback from other errors.
Nick gave a +1 to my auto-range patch with callback on 2016-05-13, and there's been no negative feedback since. Should I go ahead and check it in for 3.6?
Thank you. Yes, I was thinking the same thing. But it might be better at this point for that change to have its own ticket, so I'll open a new issue for it.
Activity
vstinner commentedon Jun 28, 2012
Oh, I forgot to mention that it computes the precision in Python, it doesn't read the precision announced by the OS or the precision of the C structure.
https://bitbucket.org/haypo/misc/src/bfacfb9a1224/python/benchmark.py#cl-66
pitrou commentedon Aug 21, 2012
Agreed with Nick's approach above.
Victor, if you want to improve timeit's reliability, please open a separate issue.
rbtcollins commentedon Mar 17, 2015
I'm confused by the feedback on the patch. It adds a single new function, doesn't alter the public interface for any existing functions, and seems fit for purpose. Could someone help me understand how its deficient?
rbtcollins commentedon Mar 17, 2015
Filed bpo-23693 for the accuracy thing.
ncoghlan commentedon Mar 22, 2015
The current patch moves print operations inside timeit() and repeat(), instead of leaving the main() function as the only one with side effects.
My counter-proposal was to instead extract the current main functionality out into a side-effect free public API of its own, and change the existing main function to call that new API and print the results.
stevendaprano commentedon May 11, 2016
This issue seems to have lost momentum, I'd like to revive it by proposing a slightly different interface for the autorange function.
Attached is a proof-of-concept patch. I've moved the code which determines the number of loops out of the main function into a new Timer method,
autorange. The main difference between my approach and Scott's is that my autorange method doesn't do any printing directly, it takes an optional callback function. This lets the caller take responsibility for all output.If this approach is acceptable, I hope to:
(in 3.6) add tests and docs for the new method;
(in 3.6 if time permits, otherwise 3.7) modify the timeit and repeat methods and functions so that they can optionally call autorange(), e.g. if the caller passes 0 as the number.
I'm not sure that there's a good reason to add a top-level autorange() function to match the timeit() and repeat() functions. Especially not once they gain the ability to autorange themselves.
I think my approach will be compatible with cleaning up and refactoring the main() function. At the moment, main() is a mess IMO, it handles argument processing, autoranging, units of time, and unreliable timing detection all from one function.
pitrou commentedon May 11, 2016
I would suggest making the 0.2 tunable as an optional argument. Different applications (benchmarks) may want different duration / precision tradeoffs.
I also notice the repeat functionality isn't included in the patch, is there a reason?
stevendaprano commentedon May 11, 2016
Sounds like a good idea to me.
I don't understand which repeat functionality you're referring to.
pitrou commentedon May 11, 2016
https://docs.python.org/3/library/timeit.html#timeit.Timer.repeat
(or, similarly, what timeit's __main__ does: report the minimum of all N runs)
ncoghlan commentedon May 12, 2016
The embedded side-effects were my main concern with Scott's original patch, so Steven's callback-based approach strikes me as a definite improvement. However, the awkwardness of the revised calling code in main does make me wonder whether or not this might be better implemented as a generator rather than as a function accepting a callback:
(Originally I had the "if verbose: print" embedded in a direct loop over t.autorange(), but writing it that way made it immediately clear that the scope of the exception handler was too broad, so I changed it to extract all the results and only then print them)
stevendaprano commentedon May 12, 2016
On Thu, May 12, 2016 at 04:49:59AM +0000, Nick Coghlan wrote:
I thought about a generator too, but then I thought about the *non*
verbose case, where you don't care about the intermediate results, only
the final (number, time_taken) pair.
# function with callback:
number, time_taken = t.autorange()
# generator
number, time_taken = list(t.autorange())[-1]
Which hints that your code snippet is buggy, or at least incomplete:
If verbose is False, you never set number and time_taken. So you need an
else clause:
ncoghlan commentedon May 13, 2016
Good point - given that, +1 from me for the callback based version, especially since exception chaining will still disambiguate failures in the callback from other errors.
stevendaprano commentedon Aug 8, 2016
Nick gave a +1 to my auto-range patch with callback on 2016-05-13, and there's been no negative feedback since. Should I go ahead and check it in for 3.6?
rhettinger commentedon Aug 8, 2016
I think the patch is good to go.
python-dev commentedon Aug 14, 2016
New changeset 424eb46f7f3a by Steven D'Aprano in branch 'default':
bpo-6422 add autorange method to timeit.Timer
https://hg.python.org/cpython/rev/424eb46f7f3a
stevendaprano commentedon Aug 15, 2016
Still to do (coming soon):
timeitandrepeatmethods (and functions) fall backon
autorangeif the number is set to 0 or None.csabella commentedon Mar 27, 2019
Hello Steven,
Were you working on the additional functionality that you mentioned in msg272704 or would that be open for someone else to do? Thanks!
stevendaprano commentedon Mar 28, 2019
Please consider it open. I don't expect it to be difficult, it's just
finding the Round Tuits. Perhaps an easy first issue for someone?
csabella commentedon Mar 28, 2019
Steven,
Thank you. Yes, I was thinking the same thing. But it might be better at this point for that change to have its own ticket, so I'll open a new issue for it.
csabella commentedon Mar 28, 2019
The new ticket is bpo-36461.