Trace Writers and Records¶
Trace writers capture every simulation event and make the data available
for post-processing or persistent storage. All trace writers inherit from
the TraceWriter base class and are passed to
engine.set_trace_writer() before calling engine.run().
For the equivalent C++ types, see I/O Library.
TraceWriter¶
- class TraceWriter¶
Abstract base class for all trace writers. Do not instantiate directly.
A trace writer is registered with the engine via
engine.set_trace_writer(writer)and receives a callback for every event that the simulation generates. Concrete subclasses decide what to do with those events: discard them, buffer them in memory, or stream them to a file.
NullTraceWriter¶
- class NullTraceWriter¶
A trace writer that silently discards all events.
Useful for benchmarking the simulation itself without the overhead of recording or serialising trace data.
writer = sim.NullTraceWriter() engine.set_trace_writer(writer) engine.run() # No trace data is available after the run.
MemoryTraceWriter¶
- class MemoryTraceWriter¶
A trace writer that buffers all events in memory.
This is the most commonly used writer for programmatic analysis. After the simulation completes, the buffered records are available for iteration and can be summarised into a
SimulationMetricsobject without writing anything to disk.Properties
- record_count: int¶
Number of events currently stored in the buffer. Read-only.
Methods
- record(index: int) TraceRecord¶
Return the trace record at position index.
- Parameters:
index – Zero-based index into the event buffer.
- Returns:
The
TraceRecordat that position.- Raises:
IndexError – If index is out of range.
- clear() None¶
Discard all buffered records and reset the event count to zero.
Useful when running multiple simulations with the same writer instance without retaining data from earlier runs.
- compute_metrics() SimulationMetrics¶
Compute aggregate scheduling metrics from the buffered events.
Returns a
SimulationMetricsinstance populated with job counts, deadline misses, energy, per-task response times, and more. The buffer is not modified.- Returns:
A
SimulationMetricssummarising the trace.
- track_frequency_changes() list[FrequencyInterval]¶
Build a time-series of DVFS frequency changes from the buffered events.
Each interval spans the period during which a cluster’s frequency held a constant value. Intervals are non-overlapping and cover the full simulated time range for which frequency events were recorded.
- Returns:
A list of
FrequencyIntervalobjects, one per contiguous constant-frequency period.
- track_core_changes() list[CoreCountInterval]¶
Build a time-series of active core count changes from the buffered events.
- Returns:
A list of
CoreCountIntervalobjects, one per contiguous period with the same active core count.
- track_config_changes() list[ConfigInterval]¶
Build a time-series of combined hardware configuration changes.
Each interval captures both the frequency and the active core count simultaneously, allowing analysis of how the two dimensions of power management interact over time.
- Returns:
A list of
ConfigIntervalobjects.
FileJsonTraceWriter¶
- class FileJsonTraceWriter(filename: str)¶
A trace writer that streams events as JSON to a file.
Events are serialised incrementally as the simulation runs, so the output file grows continuously and memory usage does not scale with the number of events. The resulting file can be analysed offline with
compute_metrics_from_file()or theschedviewCLI tool.- Parameters:
filename – Path to the output JSON file. The file is created or overwritten when the writer is constructed.
- finalize() None¶
Close and flush the JSON file.
Must be called after
engine.run()completes. Failing to callfinalize()will produce a truncated, unparseable JSON file.
Warning
Always call
finalize()when usingFileJsonTraceWriter, even if an exception is raised during the simulation. Use atry/finallyblock to ensure cleanup:writer = sim.FileJsonTraceWriter("trace.json") engine.set_trace_writer(writer) try: engine.run() finally: writer.finalize()
TraceRecord¶
- class TraceRecord¶
A single simulation event captured by a
MemoryTraceWriter.Each record has a timestamp, a type name, and a dictionary of type-specific fields. The set of fields depends on the event type.
Properties
- time: float¶
Event timestamp in seconds (absolute simulation time). Read-only.
- type: str¶
Event type name string. Read-only. Common values include:
Type string
Description
"job_arrival"A job arrived and was submitted to the scheduler.
"job_completion"A job finished executing on a processor.
"job_deadline_miss"A job’s absolute deadline elapsed before completion.
"job_preemption"A running job was preempted by a higher-priority job.
"frequency_change"A clock domain changed its operating frequency.
"core_state_change"A processor entered or left a C-state.
"job_rejected"A job arrival was rejected by admission control.
- fields: dict[str, Any]¶
All event-specific fields as a Python dictionary. Read-only. Equivalent to calling
get_fields_dict().
Methods
- get_field(key: str) Any | None¶
Return the value of the field named key, or
Noneif the field is not present in this record.- Parameters:
key – Field name to look up.
- Returns:
The field value, or
Noneif absent.
- get_fields_dict() dict[str, Any]¶
Return all fields as a Python dictionary.
- Returns:
A
dictmapping field names to their values.
- get_field_names() list[str]¶
Return the names of all fields present in this record.
- Returns:
A list of field name strings.
Examples¶
Collecting and Iterating Over Events¶
Use a MemoryTraceWriter to buffer events and inspect them
after the simulation:
import pyschedsim as sim
engine = sim.Engine()
# ... platform setup, task injection, scheduler creation ...
writer = sim.MemoryTraceWriter()
engine.set_trace_writer(writer)
engine.run()
print(f"Recorded {writer.record_count} events")
# Iterate over every event
for i in range(writer.record_count):
rec = writer.record(i)
print(f" t={rec.time:.6f} type={rec.type}")
# Filter to deadline misses only
misses = [
writer.record(i)
for i in range(writer.record_count)
if writer.record(i).type == "job_deadline_miss"
]
print(f"Deadline misses: {len(misses)}")
for rec in misses:
task_id = rec.get_field("task_id")
print(f" Task {task_id} missed deadline at t={rec.time:.6f}s")
Writing a Trace File¶
Stream events to a JSON file for offline analysis with schedview or
compute_metrics_from_file():
import pyschedsim as sim
engine = sim.Engine()
# ... setup ...
writer = sim.FileJsonTraceWriter("trace.json")
engine.set_trace_writer(writer)
try:
engine.run()
finally:
writer.finalize() # always flush and close
# Analyse the file without loading it entirely into memory
metrics = sim.compute_metrics_from_file("trace.json")
print(f"Energy: {metrics.total_energy_mj:.2f} mJ")
Iterating Over TraceRecord Fields¶
Inspect all fields of individual records dynamically:
import pyschedsim as sim
# ... run simulation with MemoryTraceWriter ...
for i in range(writer.record_count):
rec = writer.record(i)
if rec.type == "frequency_change":
names = rec.get_field_names()
print(f"t={rec.time:.6f} frequency_change fields: {names}")
for name in names:
print(f" {name} = {rec.get_field(name)}")
break # show only the first occurrence
# Alternatively, access the fields dict directly
rec = writer.record(0)
for key, value in rec.fields.items():
print(f" {key}: {value}")
See Also¶
I/O Library — C++
TraceWriter,MemoryTraceWriter,JsonTraceWriter, andTraceRecordtypesMetrics and Analysis — computing metrics from a
MemoryTraceWriterTrace Analysis and Metrics — end-to-end trace analysis tutorial