How to measure elapsed time in Python?

2,216,684

Solution 1

Use time.time() to measure the elapsed wall-clock time between two points:

import time

start = time.time()
print("hello")
end = time.time()
print(end - start)

This gives the execution time in seconds.


Another option since Python 3.3 might be to use perf_counter or process_time, depending on your requirements. Before 3.3 it was recommended to use time.clock (thanks Amber). However, it is currently deprecated:

On Unix, return the current processor time as a floating point number expressed in seconds. The precision, and in fact the very definition of the meaning of “processor time”, depends on that of the C function of the same name.

On Windows, this function returns wall-clock seconds elapsed since the first call to this function, as a floating point number, based on the Win32 function QueryPerformanceCounter(). The resolution is typically better than one microsecond.

Deprecated since version 3.3: The behaviour of this function depends on the platform: use perf_counter() or process_time() instead, depending on your requirements, to have a well defined behaviour.

Solution 2

Use timeit.default_timer instead of timeit.timeit. The former provides the best clock available on your platform and version of Python automatically:

from timeit import default_timer as timer

start = timer()
# ...
end = timer()
print(end - start) # Time in seconds, e.g. 5.38091952400282

timeit.default_timer is assigned to time.time() or time.clock() depending on OS. On Python 3.3+ default_timer is time.perf_counter() on all platforms. See Python - time.clock() vs. time.time() - accuracy?

See also:

Solution 3

Python 3 only:

Since time.clock() is deprecated as of Python 3.3, you will want to use time.perf_counter() for system-wide timing, or time.process_time() for process-wide timing, just the way you used to use time.clock():

import time

t = time.process_time()
#do some stuff
elapsed_time = time.process_time() - t

The new function process_time will not include time elapsed during sleep.

Solution 4

Measuring time in seconds:

from timeit import default_timer as timer
from datetime import timedelta

start = timer()

# ....
# (your code runs here)
# ...

end = timer()
print(timedelta(seconds=end-start))

Output:

0:00:01.946339

Solution 5

Given a function you'd like to time,

test.py:

def foo(): 
    # print "hello"   
    return "hello"

the easiest way to use timeit is to call it from the command line:

% python -mtimeit -s'import test' 'test.foo()'
1000000 loops, best of 3: 0.254 usec per loop

Do not try to use time.time or time.clock (naively) to compare the speed of functions. They can give misleading results.

PS. Do not put print statements in a function you wish to time; otherwise the time measured will depend on the speed of the terminal.

Share:
2,216,684
gilbert8
Author by

gilbert8

Updated on July 08, 2022

Comments

  • gilbert8
    gilbert8 almost 2 years

    What I want is to start counting time somewhere in my code and then get the passed time, to measure the time it took to execute few function. I think I'm using the timeit module wrong, but the docs are just confusing for me.

    import timeit
    
    start = timeit.timeit()
    print("hello")
    end = timeit.timeit()
    print(end - start)
    
    • Llopeth
      Llopeth about 3 years
      timeit.timeit() prints the time that it takes to execute its argument, which is "pass" by default. you have to instead use start= time.time() end = time.time()
  • Inca
    Inca over 12 years
    and for microseconds, use datetime.time()
  • Amber
    Amber over 12 years
    (For performance measurement, time.clock() is actually preferred, since it can't be interfered with if the system clock gets messed with, but .time() does mostly accomplish the same purpose.)
  • Visgean Skeloru
    Visgean Skeloru over 10 years
    I think that python -mtimeit is way better as it runs more times and it is build as a native way to measure time in python
  • sidgeon smythe
    sidgeon smythe about 10 years
    All this is fine, but AFAICT this still measures CPU time, not wall clock time.
  • sidgeon smythe
    sidgeon smythe about 10 years
    Actually there is some confusion; it appears cProfile does look at wall-clock time by default. I've upvoted your answer.
  • jfs
    jfs over 9 years
    Use timeit.default_timer instead of time.perf_counter. The former will choose the appropriate timer to measure the time performance tuned for your platform and Python version. process_time() does not include the time during sleep and therefore it is not appropriate to measure elapsed time.
  • Danijel
    Danijel over 8 years
    Is there a nice way of converting resulting execturion time in seconds to something like HH:MM::SS?
  • jfs
    jfs about 8 years
    @Amber: time.clock() meaning (what is measured) and its accuracy and precision (resolution) differ between platforms. The docs no longer recommend time.clock() for benchmarking. timeit.default_timer() could be used instead.
  • jfs
    jfs about 8 years
    @Danijel: print(timedelta(seconds=execution_time)). Though it is a separate question.
  • Jérôme
    Jérôme about 8 years
    Other context manager example: dabeaz.blogspot.fr/2010/02/…
  • AlejandroVD
    AlejandroVD about 8 years
    time.clock() didnt work for me. See the timeit answer by @J.F.Sebastian
  • ugotchi
    ugotchi almost 8 years
    I'm using the implementation suggested by Pierre, are the values given in seconds?
  • lkgarrison
    lkgarrison over 7 years
    Excellent answer - using timeit will produce far more accurate results since it will automatically account for things like garbage collection and OS differences
  • raacer
    raacer over 7 years
    It worth to mention it is possible to pass flags to %timeit, for example -n specifies how many times the code should be repeated.
  • Brian Burns
    Brian Burns over 7 years
    @Jérôme nice example - I adapted it as another answer - stackoverflow.com/a/41408510/243392
  • Katie
    Katie over 7 years
    This gives time in ms or seconds?
  • jfs
    jfs over 7 years
    @KhushbooTiwari in fractional seconds.
  • KGS
    KGS almost 7 years
    I think this note from the official documentation needs to be added default_timer() measurations can be affected by other programs running on the same machine, so the best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. The -r option is good for this; the default of 3 repetitions is probably enough in most cases. On Unix, you can use time.clock() to measure CPU time.
  • jfs
    jfs almost 7 years
    @KGS: Performance measurement is very tricky in a subtle way (it is easy to mislead yourself). There are many other remarks that could be relevant here. Follow the links in the answer. You might be also interested in the perf module (nonexistent at the time of the answer) that provides the same interface but it sometimes makes different from the timeit module decisions about how to measure time performance.
  • Reddspark
    Reddspark almost 7 years
    I prefer this. Timeit doc is far too confusing. from datetime import datetime startTime= datetime.now() # INSERT YOUR CODE timeElapsed=datetime.now()-startTime print('Time elpased (hh:mm:ss.ms) {}'.format(timeElapsed))
  • Basil Musa
    Basil Musa over 6 years
    I dont like how the import took place. "from timeit import default_timer as timer". Got lost while reading the code. Could have been clearer without having the "as timer" part.
  • Otieno Rowland
    Otieno Rowland over 6 years
    How can I print very small times? I kind of am getting 0.0sec always
  • Sreehari R
    Sreehari R over 6 years
    I was told that timeit calculates the CPU time, does datetime also take into account CPU time used? Are these the same thing?
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com over 5 years
    A lambda would be more succinct: print(timeit.timeit(lambda: naive_func(1_000), number=1_000_000))
  • not2qubit
    not2qubit over 5 years
    What is main()? Would be more useful if you could provide a simple code example.
  • Daniel Moskovich
    Daniel Moskovich over 5 years
    You can turn this into a decorator; this looks even better to me.
  • JayRizzo
    JayRizzo over 5 years
    FYI: If you get python -m pstats timeStats.profile ValueError: bad marshal data (unknown type code) check your python version you are running. I got this when i ran python3 -m cProfile... and python -m pstats. My mistake but got me for a second, so, I wanted to share don't forget consistency. =)
  • noah
    noah almost 5 years
    time.clock() is deprecated at of Python 3.3 docs.python.org/3.3/library/time.html#time.clock
  • hlg
    hlg almost 5 years
    It would be good to explain the advantage of using this library over other approaches.
  • PetarMI
    PetarMI almost 5 years
    The nested functionality is actually broken. I opened an issue describing where the problem in the code is but the repo hasn't been maintained in a year so I wouldn't expect a change.
  • user1318499
    user1318499 almost 5 years
    It's risky to measure elapsed time this way because datetime.now() can change between the two calls for reasons like network time syncing, daylight savings switchover or the user twiddling the clock.
  • Franklin Piat
    Franklin Piat almost 5 years
    This answer seems off-topic (well, the question wasn't very specific). There are two "time" measurement : wall-clock time between two points, of the cpu consumption of the process.
  • RoG
    RoG over 4 years
    @VisgeanSkeloru But sometimes you simply want the time that a particular command took in a particular instance, rather than profiling. Running it n times to get more accuracy takes n times longer after all. What is "better" depends on the situation.
  • KIC
    KIC over 4 years
    what is this? ms?
  • ScottieB
    ScottieB over 4 years
    I find the nesting a little confusing. If I were to come across t.tic() buried in the code, it's up to me the developer to keep a mental list of where in the series I should expect this to be. Do you find yourself setting up nests or just multiple tictocs?
  • Tapomay
    Tapomay over 4 years
    Concise lambda: ``` lang-python from timeit import default_timer as timer timed = lambda f, s=None: (f(), round(timer() - s, 3)) if s else timed(f, timer()) (result, elapsed) = timed(some_function) ```
  • H. Sánchez
    H. Sánchez about 4 years
    @PetarMI : FYI, I just fixed the issue with ttictoc. Quite a mess I had, but it should be good now.
  • Dave Liu
    Dave Liu about 4 years
    This is the most concise answer with the cleanest output.
  • xjcl
    xjcl about 4 years
    time.time() is a bad idea because the system clock can be reset which will make you go back in time. time.monotonic() takes care of this (monotonic = it only goes forward). time.perf_counter() is also monotonic but has even higher accuracy, so this is recommended for wall-clock time.
  • Danny
    Danny almost 4 years
    This is super cool, thank you for sharing. I have not encountered the typing library or the nonlocal keyword -- fun to find new things to learn about. I'm having trouble wrapping my head around this: Callable[[AnyF], AnyF]. What does it mean?
  • ruohola
    ruohola almost 4 years
    @Danny On the top I've defined the type alias AnyF to mean Callable[..., Any], so AnyF is a function that can take any amount of any type arguments and return anything. So Callable[[AnyF], AnyF] would expand to Callable[[Callable[..., Any]], Callable[..., Any]]. This is the type of the return value of timer aka the full type of decorator. It is a function that takes any kind of function as its only argument and returns any kind of function.
  • Danny
    Danny almost 4 years
    Thanks for the explanation! I'm still trying to fully wrap my head around the internals of decorators. This helped a lot!
  • Guimoute
    Guimoute almost 4 years
    @KIC It's in seconds.
  • user1318499
    user1318499 almost 4 years
    Don't do this because time.time() doesn't necessarily increment uniformly. You can get a negative duration if there's a daylight savings adjustment or whatever. Replace time.time() with time.monotonic().
  • mic
    mic almost 4 years
    From Shital Shah's answer: "First, if you are debating between timeit and time.time, the timeit has two advantages: timeit selects the best timer available on your OS and Python version. timeit disables garbage collection, however, this is not something you may or may not want."
  • mic
    mic almost 4 years
    Regarding "Ability to disable printing in block timing (use with utils.MeasureBlockTime() as t and then t.elapsed).": this doesn't work as is, as t is None. I think __enter__ needs to return self, and to disable printing, we have to construct it as utils.MeasureBlockTime(no_print=True).
  • Shital Shah
    Shital Shah almost 4 years
    @mic - thanks for pointing this out. I've updated the answer with this and several other enhancements.
  • frakman1
    frakman1 almost 4 years
    Is there a Python2.x way of doing this without having to import print_function from __future__? I tried to use join but I don't understand it well enough to get it to work.
  • frakman1
    frakman1 almost 4 years
    UPDATE. I figured it out and used this: print(''.join(["time elapsed in ",(func.__name__),": ",str(end - start)]))
  • Harry Moreno
    Harry Moreno over 3 years
    what do you mean by output? does timeit write to stdout?
  • David
    David over 3 years
    Nop. I mean the returned value.
  • Henri
    Henri over 3 years
    @hlg If I remember correctly, MATLAB uses functions with similar names to time stuff. So I guess the advantage is the resemblance, for people who liked this in MATLAB but switched to Python.
  • thepunitsingh
    thepunitsingh over 3 years
    The function time.clock() has been removed, after having been deprecated since Python 3.3. time.perf_counter() or time.process_time() can be used instead. Ref: stackoverflow.com/a/58569410/6701627
  • howdoicode
    howdoicode over 3 years
    And now with f-strings and format specifications included: time_str = f"{h:02d}:{m:02d}:{s:02d}"
  • ruohola
    ruohola over 3 years
    @fjs timeit.default_timer uses time.perf_counter in Python >=3.3 docs.python.org/3/library/timeit.html#timeit.default_timer
  • Paolo
    Paolo about 3 years
    @user1318499 it's not that it returns negative values, it can return a lower value than a previous call. docs.python.org/3/library/time.html#time.time
  • Vega
    Vega over 2 years
    elapsed_time return 0.07812 for example. How do I interpret that? Would a second be 1.000 so my script ran in 7,812 milliseconds?
  • MEMark
    MEMark over 2 years
    I can't get this to work. unsupported operand type(s) for -: 'datetime.datetime' and 'function'
  • ingyhere
    ingyhere over 2 years
    @MEMark Uncertainty here without seeing the code, but note that this was made for Python 3. The error means a the wrong datatype is being used in place of a datetime object. Could the code be trying t_diff(t_diff()) or t_diff(t()) instead of t_diff(t) (where t is a scalar set earlier as t = t_set())?
  • alexsmail
    alexsmail over 2 years
    It is better to use time.monotonic_ns(), see docs.python.org/3/library/time.html#time.monotonic_ns
  • Dan Nissenbaum
    Dan Nissenbaum over 2 years
    This is simple and excellent - easy to code; I'm surprised that (a) this kind of functionality isn't present in ANY of the existing Python profilers; and (b) that this answer, including a simple class that can be copied-and-pasted, wasn't offered to this question years ago with many more upvotes.
  • Will Croxford
    Will Croxford over 2 years
    easy to read, easy to use, accurate enough for approx tests or comparisons. But, as I cannot seem to edit at time of writing, to, 'compare the time of two operations', this should have t0 = time.time() I feel after import line. Then print(t1 -t0) is first operation time. 2 times are needed to compare 2 operations.
  • NeilG
    NeilG about 2 years
    Yes, @BasilMusa, I don't know why peeps sometimes like to rename canonical library identifiers, especially to something that is identical to another canonical library identiier altogether! Talk about generating deliberate ambiguity. Just to reduce line length? Perhaps they're still struggling with the ridiculous 80 character line limit, for when peeps used to have vewy vewy small monitors. Just hike it to 120. I recommend 160, oh yeah!
  • jfs
    jfs almost 2 years
    @NeilG part of the import functionality acts like = as in x=1. timer is used for the same reason x may be used instead of 1. Think about it.
  • NeilG
    NeilG almost 2 years
    I'm supporting Basil Musa's objection, @jfs, your objection is not clear. To demonstrate, we could make it worse by using from timeit import default_timer as os. Even shorter, but catastrophically misleading. Importing as timer is misleading, to wit, it misled Basil, and I concur. from timeit import default_timer is clearer. Some recommend (may be in a PEP can't remember) import timeit and then use timeit.default_timer, maximum clarity. That could be overkill but why add a different identifier, especially one that collides with an identifier from another popular module?