A discrete-event simulation engine for time-based process benchmarking
Project description
SimTime
SimTime is a Python library for discrete-event simulation, supporting flexible event scheduling, detailed event recording, and custom metric collection. It is designed for simulating time-based processes, both synchronous and asynchronous, with periodic, rate-based, declared, or measured duration events.
Features
- Discrete-event simulation engine with customizable event queue and time advancement.
- Flexible event scheduling: absolute time, after delay, periodic, rate-based, or with custom callbacks.
- Support for synchronous and asynchronous (coroutine) event functions.
- Detailed event recording: logs of timing, results, errors, and metadata.
- Custom metric collection and management during simulation.
- Export results: events and metrics exportable as CSV/JSON (pandas optional; stdlib fallback included).
Installation
pip install simtime
# Optional: enable pandas-based DataFrame export
pip install "simtime[pandas]"
Quick Start
from simtime import TimeSimulator, EventType, prepare_func
# Define an event function
def my_event():
print("Event executed!")
# Prepare the function for simulation (required)
my_event = prepare_func(EventType.DECLARED_DURATION, my_event, value=10)
# Create the simulator
sim = TimeSimulator()
# Create and schedule the event at simulation time 10
event = sim.create_event("my_event", my_event)
sim.schedule(event, at=10)
# Run the simulation until time 20
sim.run(until_time=20)
Event Types and Scheduling
Declared Duration
The event's simulated duration is a fixed value set at preparation time.
def task():
print("Task with declared duration")
task = prepare_func(EventType.DECLARED_DURATION, task, value=50) # 50 ms simulated
event = sim.create_event("task", task)
sim.schedule(event, at=0)
Measured Duration
The event's simulated duration is scaled from its real wall-clock execution time.
def measured_task():
# Real computation here
pass
measured_task = prepare_func(EventType.MEASURED_DURATION, measured_task)
event = sim.create_event("measured", measured_task)
sim.schedule(event, at=0)
Periodic
The event is automatically rescheduled at a fixed interval.
def periodic_task():
print("Periodic event")
periodic_task = prepare_func(EventType.PERIODIC, periodic_task, value={"every_ms": 5})
event = sim.create_event("periodic", periodic_task)
sim.schedule(event, at=0)
sim.run(until_time=20) # fires at t=0, 5, 10, 15
Rate-Based
Events are generated at a statistical arrival rate using a chosen distribution.
def rate_task():
print("Rate-based event")
rate_task = prepare_func(
EventType.RATE_BASED,
rate_task,
value={"rate_per_ms": 0.1, "dist": "poisson", "max_events": 10}
)
event = sim.create_event("rate", rate_task)
sim.schedule(event, at=0)
Supported distributions: "poisson", "uniform", "normal", "constant".
Asynchronous Events
Async functions are supported for all event types.
import asyncio
async def async_task():
await asyncio.sleep(0.01)
return "done"
async_task = prepare_func(EventType.DECLARED_DURATION, async_task, value=10)
event = sim.create_event("async", async_task)
sim.schedule(event, at=0)
Event Recording and Metrics
Accessing Event Records
for record in sim.recorder.records:
print(record)
# As a list of dicts (no pandas needed)
dicts = sim.recorder.to_dicts()
# As a pandas DataFrame (requires pandas)
df = sim.recorder.to_dataframe()
Exporting Events
sim.recorder.save_csv("events.csv")
sim.recorder.save_json("events.json")
Using the Metric Store
sim.metrics_store.add(
category="performance",
type="latency",
name="request_latency",
value=123,
tags={"endpoint": "/api"}
)
# Filter by category
perf_metrics = sim.metrics_store.get_by_category("performance")
sim.metrics_store.save_csv("metrics.csv")
sim.metrics_store.save_json("metrics.json")
Temporary Metrics
Temporary metrics are keyed by id and can be updated or removed during simulation.
sim.metrics_store.add_temp("in_flight", 0)
record = sim.metrics_store.get_temp("in_flight")
print(record.value)
sim.metrics_store.remove_temp("in_flight")
API Reference
TimeSimulator
TimeSimulator(
step_ms: int = 1,
jump_to_next_event: bool = True,
scale_real_to_sim: float = 1.0,
seed: Optional[int] = None,
)
| Method | Description |
|---|---|
now() -> int |
Current simulation time in ms. |
pending_count() -> int |
Number of events waiting in the queue. |
create_event(name, func, args, kwargs, metadata, callback_event) -> Event |
Create an event from a prepared function. |
schedule(event, at=None, delay=None) -> Event |
Enqueue an event. |
run(until_time=None, until_events=None, stop_condition=None) |
Run the simulation. |
stop() |
Signal the simulation to stop after the current batch. |
reset() |
Reset clock, queue, recorder, and metrics to initial state. |
add_measured_time(function, value) |
Add extra simulated ms to a MEASURED_DURATION function. |
recorder |
Recorder instance for event logs. |
metrics_store |
MetricStore instance for metrics. |
prepare_func
prepare_func(event_type: EventType, func, value=None) -> Callable
Prepares a function for simulation. Returns a copy; the original is not mutated.
Recorder
| Method/Property | Description |
|---|---|
records |
List of EventRecord objects (copy). |
to_dicts() -> list[dict] |
Records as plain dicts (no pandas needed). |
to_dataframe() |
Records as pandas DataFrame. Requires pandas. |
save_csv(path) |
Save to CSV (uses stdlib if pandas absent). |
save_json(path) |
Save to JSON. |
MetricStore
| Method/Property | Description |
|---|---|
add(category, type, name, value, tags=None) |
Add a persistent metric. |
get_by_category(category) -> list[MetricRecord] |
Filter metrics by category. |
add_temp(id, value) |
Add/update a temporary metric. |
get_temp(id) -> TempMetricRecord | None |
Retrieve a temporary metric. |
remove_temp(id) |
Remove a temporary metric. |
metrics |
All persistent MetricRecord objects (copy). |
to_dicts() -> list[dict] |
Metrics as plain dicts. |
to_dataframe() |
Metrics as pandas DataFrame. Requires pandas. |
save_csv(path) |
Save to CSV. |
save_json(path) |
Save to JSON. |
Advanced Usage
- Reproducible simulations: Pass
seed=42toTimeSimulator. - Step-by-step time advance: Set
jump_to_next_event=Falseand configurestep_ms. - Custom stop conditions:
run(stop_condition=lambda sim: sim.now() >= 100). - Event chaining: Pass a
callback_eventtocreate_event; it fires after the parent completes. - Reset and rerun: Call
sim.reset()between benchmark runs instead of creating a new instance.
Requirements
- Python 3.9+
- Optional:
pandas>=1.3for DataFrame export
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simtime-0.2.0.tar.gz.
File metadata
- Download URL: simtime-0.2.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f681fb18c640d2c173ab40d0811e4b6c62ff9119feeeb6a3e55f3427a885182b
|
|
| MD5 |
26cb12fef81481013acd8da9e9726d4c
|
|
| BLAKE2b-256 |
cb6475af370a8a0362fc06ab28493fce9024dd64f8356e986355e0d54f1ee245
|
File details
Details for the file simtime-0.2.0-py3-none-any.whl.
File metadata
- Download URL: simtime-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0daa0e2d2ff3b61b33b45769081cf597d2a243f9f59b55472f568c0355e0db85
|
|
| MD5 |
41adccf167c776eee668e0945991dafa
|
|
| BLAKE2b-256 |
99763a34de4f6b3371f5b27266e3c01c766d3ab4d1f3a8a40b1ba237100e31c2
|