Python time.perf_counter Function
Last modified April 11, 2025
This comprehensive guide explores Python's time.perf_counter
function,
which provides the highest available resolution timer for benchmarking. We'll cover
performance measurement, timing comparisons, and practical examples.
Basic Definitions
The time.perf_counter
function returns a high-resolution performance
counter value in fractional seconds. It's designed for measuring short durations.
Key characteristics: highest available timer resolution, monotonic (always increases), not affected by system clock changes, and ideal for benchmarking. The reference point is undefined, so only differences are meaningful.
Basic Performance Timing
The simplest use of time.perf_counter
measures code execution time.
This example shows basic usage for timing a function call.
import time def calculate_sum(n): return sum(range(n)) # Start timer start = time.perf_counter() # Execute function result = calculate_sum(1000000) # Stop timer end = time.perf_counter() # Calculate duration duration = end - start print(f"Calculation took {duration:.6f} seconds") print(f"Result: {result}")
This example demonstrates how to measure the execution time of a function.
The perf_counter
provides high-resolution timing suitable for
performance measurements.
The :.6f
format specifier displays the duration with 6 decimal
places for microsecond precision.
Comparing Multiple Implementations
time.perf_counter
is ideal for comparing different implementations.
This example compares two approaches to summing numbers.
import time def sum_with_loop(n): total = 0 for i in range(n): total += i return total def sum_with_builtin(n): return sum(range(n)) n = 1000000 # Time loop implementation start = time.perf_counter() result = sum_with_loop(n) end = time.perf_counter() print(f"Loop: {end - start:.6f} sec") # Time built-in implementation start = time.perf_counter() result = sum_with_builtin(n) end = time.perf_counter() print(f"Built-in: {end - start:.6f} sec")
This pattern helps identify performance differences between approaches.
The built-in sum
is typically faster than a Python loop.
Multiple runs may be needed for reliable results due to system variability.
Timing Context Manager
A context manager provides a clean way to time code blocks. This example creates a reusable timing 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.duration = self.end - self.start print(f"Execution took {self.duration:.6f} seconds") # Using the context manager with Timer(): # Code to time data = [x**2 for x in range(10000)] filtered = [x for x in data if x % 2 == 0] total = sum(filtered) print(f"Total: {total}")
The context manager automatically handles timing start/stop and output. This pattern reduces boilerplate when timing multiple code sections.
The duration remains available as timer.duration
after the block.
Measuring Small Code Sections
perf_counter
excels at measuring very short operations. This
example times individual list operations.
import time def time_operation(operation, n=1000): start = time.perf_counter() for _ in range(n): operation() end = time.perf_counter() return (end - start) / n # Define operations def list_append(): lst = [] lst.append(1) def list_concat(): lst = [] lst = lst + [1] # Time operations append_time = time_operation(list_append) concat_time = time_operation(list_concat) print(f"Append: {append_time:.9f} sec/op") print(f"Concat: {concat_time:.9f} sec/op") print(f"Ratio: {concat_time/append_time:.1f}x")
By repeating operations and averaging, we can measure very short durations. This reveals performance differences between similar operations.
The :.9f
format shows nanosecond precision for these tiny durations.
Comparing with time.time
This example demonstrates the resolution difference between perf_counter
and time.time
for short intervals.
import time def empty_function(): pass # Test with time.time start = time.time() empty_function() end = time.time() print(f"time.time resolution: {end - start:.9f} sec") # Test with perf_counter start = time.perf_counter() empty_function() end = time.perf_counter() print(f"perf_counter resolution: {end - start:.9f} sec") # Measure smallest detectable difference def measure_resolution(func): min_diff = float('inf') for _ in range(100): start = func() end = func() diff = end - start if 0 < diff < min_diff: min_diff = diff return min_diff print(f"time.time min resolution: {measure_resolution(time.time):.9f}") print(f"perf_counter min resolution: {measure_resolution(time.perf_counter):.9f}")
perf_counter
typically shows much higher resolution than
time.time
, making it better for microbenchmarks.
The resolution test measures the smallest non-zero timing difference detectable.
Statistical Timing with Multiple Runs
For reliable benchmarks, multiple runs and statistical analysis help account for variability. This example shows advanced timing techniques.
import time import statistics def benchmark(func, n=1000): times = [] for _ in range(n): start = time.perf_counter() func() end = time.perf_counter() times.append(end - start) mean = statistics.mean(times) stdev = statistics.stdev(times) minimum = min(times) maximum = max(times) print(f"Mean: {mean:.9f} sec") print(f"StdDev: {stdev:.9f} sec") print(f"Min: {minimum:.9f} sec") print(f"Max: {maximum:.9f} sec") print(f"Range: {maximum/minimum:.1f}x") def test_function(): sum(x*x for x in range(1000)) print("Benchmark results:") benchmark(test_function)
This approach provides a more complete picture of performance characteristics than single measurements. It helps identify variability and outliers.
Statistical measures like standard deviation show timing consistency across runs.
Best Practices
- Use for short intervals: perf_counter is ideal for microbenchmarks
- Multiple runs: Measure several times for reliable results
- Warm-up: Consider discarding first measurements
- System load: Run benchmarks on quiet systems
- Relative comparisons: Compare implementations rather than absolute times
Source References
Author
List all Python tutorials.