timing provides simple and powerful timing utilities for measuring execution time, collecting statistics, and analyzing performance.
Sktimer Statistical timer that collects timing measurements and provides comprehensive statistics (mean, median, stdev, percentiles). Has more statistics that timeit.
timethis Decorator for timing function executions with automatic statistics collection.
TimeThis Context manager for timing code blocks with automatic start/stop.
With and you have 100% coverage. Anything and everything can be timed with one line of code.
Includes:
from suitkaise import timing
from suitkaise .timing import Sktimer , TimeThis , timethis , time, sleep, elapsed , clear_global_timers
time()Get the current Unix timestamp.
from suitkaise import timing
start_time = timing .time()
Wraps time.time() so that you don't have to import both and time.
Returns
float: Current Unix timestamp.
sleep()Sleep the current thread for a given number of seconds.
from suitkaise import timing
# sleep for 2 seconds
timing .sleep(2)
# returns current time after sleeping
end_time = timing .sleep(2)
Arguments
seconds: Number of seconds to sleep.
floatReturns
float: Current time after sleeping.
Use . for async contexts.
# in an async function
end_time = await timing .sleep.asynced()(2)
Uses asyncio.sleep internally.
elapsed ()Get the elapsed time between two timestamps.
from suitkaise import timing
start_time = timing .time()
timing .sleep(2)
end_time = timing .time()
# with two times
elapsed = timing .elapsed (start_time, end_time) # 2.0
# with one time (uses current time as end)
elapsed = timing .elapsed (start_time)
Arguments
time1: First timestamp.
floattime2: Second timestamp.
float | None = NoneNone, uses current timeReturns
float: Absolute elapsed time in seconds.
Note: Order doesn't matter - always returns positive elapsed time.
Sktimer Statistical timer for collecting and analyzing execution times.
from suitkaise import timing
timer = timing .Sktimer( )
for i in range(100):
timer .start ()
do_work()
timer .stop ()
print(f"Mean: {timer.mean:.3f}s")
print(f"Std Dev: {timer.stdev:.3f}s")
print(f"95th percentile: {timer.percentile(95):.3f}s")
Arguments
max_times: Keep only the most recent N measurements (rolling window).
int | None = NoneNone, keeps all measurementsstart ()Start timing a new measurement.
timer .start ()
Returns
float: Start timestamp.
Raises
UserWarning: If called while timing is already in progress (creates nested frame).
stop ()Stop timing and record the measurement.
timer .start ()
do_work()
elapsed = timer .stop () # returns elapsed time, records it
Returns
float: Elapsed time for this measurement.
Raises
RuntimeError: If timer was not started.
discard ()Stop timing but do NOT record the measurement.
timer .start ()
try:
result = risky_operation()
timer .stop () # record successful timing
except Exception:
timer .discard () # don't record failed timing
Use when you want to abandon the current timing without polluting statistics.
Returns
float: Elapsed time that was discarded.
Raises
RuntimeError: If timer was not started.
lap ()Record a lap time (stop + start in one call).
timer .start ()
for i in range(100):
do_work()
timer .lap () # records time since last lap/start, continues timing
timer .discard () # don't record the 101st measurement still running
print(timer .mean ) # 100 measurements recorded
Returns
float: Elapsed time for this lap.
Raises
RuntimeError: If timer was not started.
pause ()Pause the current timing measurement.
timer .start ()
do_work()
timer .pause ()
user_input = input("Continue? ") # not counted in timing
timer .resume ()
do_more_work()
elapsed = timer .stop () # only counts work, not user input
Time spent paused is excluded from the final elapsed time.
Raises
RuntimeError: If timer is not running. UserWarning: If already paused.
resume ()Resume a paused timing measurement.
timer .resume ()
Raises
RuntimeError: If timer is not running. UserWarning: If not currently paused.
add_time ()Manually add a timing measurement to the .
timer .add_time (1.5)
timer .add_time (2.3)
timer .add_time (1.8)
print(timer .mean ) # 1.867
Arguments
elapsed_time: Time to add to statistics (in seconds).
floatset_max_times ()Set the rolling window size for stored measurements.
timer .set_max_times (100) # keep only last 100 measurements
timer .set_max_times (None) # keep all measurements
Arguments
max_times: Keep only the most recent N times.
int | NoneNone keeps allreset ()Clear all timing measurements.
timer .reset () # clears all measurements, like a new Sktimer()
All statistics are accessed directly on the timer and are always up-to-date.
num_times: Number of recorded measurements.
intmost_recent: Most recent timing measurement.
float | None: Alias for most_recent.
float | Nonetotal_time: Sum of all times.
float | Nonetotal_time_paused: Total time spent paused across all measurements.
float | Nonemean: Average of all times.
float | Nonemedian: Median of all times.
float | Nonemin: Minimum (fastest) time.
float | Nonemax: Maximum (slowest) time.
float | Nonefastest_time: Alias for min.
float | Noneslowest_time: Alias for max.
float | Nonefastest_index: Index of fastest measurement.
int | Noneslowest_index: Index of slowest measurement.
int | Nonestdev: Standard deviation.
float | Nonevariance: Variance.
float | Nonemax_times: Current rolling window size.
int | Noneget_time()Get a specific measurement by index.
first_time = timer .get_time(0)
last_time = timer .get_time(-1)
Arguments
index: 0-based index of measurement.
intReturns
float | None: Timing measurement or None if index is invalid.
percentile ()Calculate any percentile of timing measurements.
p50 = timer .percentile (50) # median
p95 = timer .percentile (95) # 95th percentile
p99 = timer .percentile (99) # 99th percentile
Arguments
percent: Percentile to calculate (0-100).
floatReturns
float | None: Percentile value or None if no measurements.
Raises
ValueError: If percent is not between 0 and 100.
get_statistics() / get_stats()Get a frozen snapshot of all timing statistics.
snapshot = timer .get_statistics()
# snapshot won't change even if timer continues
timer .start ()
do_more_work()
timer .stop ()
# snapshot still has old values
print(snapshot.mean)
Returns
A TimerStats object containing all statistics calculated at the moment the method was called.
Returns
TimerStats | None: Snapshot or None if no measurements.
TimerStatsFrozen snapshot of statistics returned by .
All values are pre-computed and won't change even if the timer continues recording.
All properties from are available:
times, num_times, most_recent, most_recent_indextotal_time, total_time_pausedmean, median, min, maxslowest_time, fastest_time, slowest_index, fastest_indexstdev, variancepercentile ()Same as .
p95 = snapshot.percentile(95)
get_time()Same as .
first = snapshot.get_time(0)
timethis DecoratorDecorator that times function executions and records results in a .
from suitkaise import timing
@timing .timethis ()
def quick_function():
# ...
pass
quick_function()
# access the auto-created timer
print(f"Last time: {quick_function.timer.most_recent:.3f}s")
# calling multiple times builds statistics
for i in range(100):
quick_function()
print(f"Mean: {quick_function.timer.mean:.3f}s")
timer: to accumulate timing data in.
Sktimer | None = NoneNone, creates an auto-named global timer attached to the functionthreshold: Minimum elapsed time to record.
float = 0.0max_times: Keep only the most recent N measurements.
int | None = NoneWhen no timer is provided, the decorator creates a global timer with a naming convention:
module_function_timermodule_ClassName_method_timerThe timer is attached to the function as .:
@timing .timethis ()
def my_function():
pass
my_function()
print(my_function.timer .mean )
Use a single timer across multiple functions:
perf_timer = timing .Sktimer( )
perf_timer.set_max_times(1000)
@timing .timethis (perf_timer)
def multiply(a, b):
return a * b
@timing .timethis (perf_timer)
def divide(a, b):
return a / b
for a, b in zip(range(1000), range(1, 1001)):
multiply(a, b)
divide(a, b)
print(f"Combined mean: {perf_timer.mean:.6f}s")
Use both a shared timer and a function-specific timer:
perf_timer = timing .Sktimer( )
overall_timer = timing .Sktimer( )
# 2 stacked decorators on the same function
@timing .timethis (perf_timer)
@timing .timethis ()
def multiply(a, b):
return a * b
# supports infinite stacking
@timing .timethis (overall_timer)
@timing .timethis (perf_timer)
@timing .timethis ()
def divide(a, b):
return a / b
# ... call functions ...
# combined stats
print(f"Combined mean: {perf_timer.mean:.6f}s")
# individual stats
print(f"Multiply mean: {multiply.timer.mean:.6f}s")
print(f"Divide mean: {divide.timer.mean:.6f}s")
TimeThis Context ManagerContext manager for timing code blocks with automatic timer management.
from suitkaise import timing
with timing .TimeThis( ) as timer:
do_work()
print(f"Time taken: {timer.most_recent:.3f}s")
Arguments
timer: instance to use.
Sktimer | None = NoneNone, creates a new Sktimer threshold: Minimum elapsed time to record.
float = 0.0For quick, one-off measurements:
with timing .TimeThis( ) as timer:
compress_file_with_gzip("data.csv")
print(f"Compression took: {timer.most_recent:.3f}s")
For accumulating statistics across multiple runs:
api_timer = timing .Sktimer( )
with timing .TimeThis( api_timer):
response = requests.get("https://api.example.com/users")
with timing .TimeThis( api_timer):
response = requests.get("https://api.example.com/posts")
print(f"Average API time: {api_timer.mean:.3f}s")
with timing .TimeThis( ) as timer:
results = database.query("SELECT * FROM users")
timer .pause ()
user_wants_export = input("Export to CSV? (y/n): ")
timer .resume ()
if user_wants_export.lower() == 'y':
export_to_csv(results)
print(f"Database operation took: {timer.most_recent:.3f}s (excluding user input)")
: Pause timing.
: Resume timing.
: Record a lap and continue timing.
clear_global_timers ()Clear all auto-created global timers used by the decorator.
from suitkaise import timing
# ... many @timethis() decorated functions called ...
# clear data from auto-created timers to save resources
timing .clear_global_timers ()
Useful for:
All operations are thread-safe.
import threading
timer = timing .Sktimer( )
def worker():
for _ in range(100):
timer .start ()
do_work()
timer .stop ()
threads = [threading.Thread(target=worker) for _ in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
# 400 total measurements across all threads (4 threads * 100 iterations)
print(f"Total measurements: {timer.num_times}")
print(f"Mean: {timer.mean:.3f}s")