Skip to main content

How to Measure Execution Time of a Function in Python (With Examples)

Β· 6 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

Measuring how long your Python code takes to run is a critical skill for performance optimization, profiling, or benchmarking different approaches to solving a problem. Python offers many tools for tracking the execution time of a function - from simple built-in methods to full-blown profilers.

In this guide, we will explore multiple methods with code examples to help you choose the right one for your use case.


1. Using time.time()​

This is one of the simplest and most accessible ways to measure elapsed time.

import time

def my_function():
time.sleep(1)

start = time.time()
my_function()
end = time.time()

print(f"Execution time: {end - start:.4f} seconds")

Simple and quick Less accurate on very fast functions

Using time.perf_counter()​

For higher precision and accuracy, especially for short-running functions.

import time

def fast_function():
return sum(range(1000))

start = time.perf_counter()
fast_function()
end = time.perf_counter()

print(f"Execution time: {end - start:.6f} seconds")

Recommended for performance benchmarks High precision timer (includes sleep time)

Using time.process_time()​

Focuses only on the CPU execution time (does not count sleep or I/O waits).

import time

def cpu_bound_task():
for _ in range(10**6):
_ = 1 + 1

start = time.process_time()
cpu_bound_task()
end = time.process_time()

print(f"CPU execution time: {end - start:.6f} seconds")

Good for CPU-bound tasks Not suitable for I/O or async tasks

Using timeit Module (Best for Benchmarking)​

timeit automatically handles setup and repeat runs for statistical accuracy. If you want you can use it from code or CLI, here is code version:


def example():
return sum(range(100))

execution_time = timeit.timeit(example, number=10000)
print(f"Average execution time over 10,000 runs: {execution_time:.6f} seconds")

CLI version:

python -m timeit "sum(range(100))"

Best tool for comparing functions Automatically disables garbage collection

Using a Context Manager​

You can define your own timer context:

import time

class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self

def __exit__(self, *args):
self.end = time.perf_counter()
self.interval = self.end - self.start
print(f"Execution time: {self.interval:.6f} seconds")

with Timer():
sum(range(100000))

Clean syntax Reusable across your codebase

Using a Decorator​

Decorators are perfect for reusing timing logic across many functions.

import time
from functools import wraps

def timing_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} took {end - start:.6f} seconds")
return result
return wrapper

@timing_decorator
def slow_function():
time.sleep(1.5)

slow_function()

DRY and expressive Works on many functions

Using cProfile (Advanced Profiling)​

If you need a detailed performance breakdown:

import cProfile

def compute():
sum([i ** 2 for i in range(10000)])

cProfile.run('compute()')

Good for profiling large applications Includes function call stats


Using line_profiler (Third-party Tool)​

Install it first:

pip install line_profiler
Then with python:

@profile
def heavy_function():
for i in range(10000):
x = i **2
y = x** 0.5
Run with cli:

kernprof -l -v my_script.py

Line-by-line execution time External dependency

Using tracemalloc for Memory + Time Insights​

Bonus if you want to track memory usage + execution time:

import time
import tracemalloc

tracemalloc.start()
start = time.perf_counter()

[sum(range(1000)) for _ in range(10000)]

end = time.perf_counter()
current, peak = tracemalloc.get_traced_memory()
print(f"Time: {end - start:.6f} sec, Peak Memory: {peak / 10**6:.2f} MB")
tracemalloc.stop()

Conclusion​

MethodBest ForPrecisionEasy to Use
time.time()General purpose timingLowβœ…
time.perf_counter()Performance testingHighβœ…βœ…
timeitMicro-benchmarkingVery Highβœ…βœ…
cProfileProfiling function callsMediumβœ…βœ…
line_profilerLine-by-line profilingHigh❌ (extra install)
Decorators/ContextMgrReusable timing instrumentationHighβœ…βœ…βœ…

Further Reading​

You now have a full toolbox to choose from when measuring Python function execution times. Use the simplest for quick debugging, or go with profilers for full diagnostics.