Metrics and Analysis¶
The metrics API computes aggregate scheduling statistics from simulation
traces. Metrics can be obtained either directly from a
MemoryTraceWriter after a run, or computed from a previously
saved JSON trace file.
For the equivalent C++ types, see I/O Library. For an end-to-end walkthrough, see Trace Analysis and Metrics.
SimulationMetrics¶
- class SimulationMetrics¶
Aggregate statistics computed from a simulation trace.
All scalar fields are read-write. Map-based fields (per-processor, per-task) are accessed through getter methods.
Scalar Fields¶
Field
Type
Description
total_jobsintTotal number of job arrivals observed in the trace.
completed_jobsintJobs that finished execution before their deadline (or at all).
deadline_missesintJobs whose absolute deadline elapsed before they completed.
preemptionsintNumber of preemption events (running job displaced by another).
context_switchesintNumber of context switch events across all processors.
total_energy_mjfloatTotal energy consumed by all processors in millijoules.
average_utilizationfloatMean processor utilization averaged across all processors. A value of 1.0 means fully loaded.
rejected_arrivalsintJob arrivals rejected by an admission controller.
cluster_migrationsintNumber of times a task was reassigned between clusters.
transitionsintTotal DVFS frequency transition events.
core_state_requestsintNumber of C-state change requests across all processors.
frequency_requestsintNumber of DVFS frequency change requests.
Map-Based Getter Methods¶
- get_energy_per_processor() dict[int, float]¶
Return energy consumption per processor.
- Returns:
A dictionary mapping processor ID to energy in millijoules.
- get_utilization_per_processor() dict[int, float]¶
Return utilization per processor.
- Returns:
A dictionary mapping processor ID to utilization in [0, 1].
- get_response_times_per_task() dict[int, list[float]]¶
Return all measured response times for each task.
A response time is the elapsed time from job arrival to job completion, in seconds.
- Returns:
A dictionary mapping task ID to a list of response times (one per completed job instance) in seconds.
- get_deadline_misses_per_task() dict[int, int]¶
Return deadline miss count per task.
- Returns:
A dictionary mapping task ID to the number of deadline misses recorded for that task.
- get_waiting_times_per_task() dict[int, list[float]]¶
Return all measured waiting times for each task.
A waiting time is the duration between job arrival and the first time that job begins executing, in seconds.
- Returns:
A dictionary mapping task ID to a list of waiting times in seconds.
ResponseTimeStats¶
- class ResponseTimeStats¶
Summary statistics for a list of response times.
Obtain an instance by calling
compute_response_time_stats(). All fields are read-write.Field
Type
Description
minfloatMinimum response time in seconds.
maxfloatMaximum response time in seconds.
meanfloatArithmetic mean of all response times in seconds.
medianfloatMedian (50th percentile) response time in seconds.
stddevfloatStandard deviation of response times in seconds.
percentile_95float95th percentile response time in seconds.
percentile_99float99th percentile response time in seconds.
Time-Series Interval Types¶
The MemoryTraceWriter.track_frequency_changes(),
MemoryTraceWriter.track_core_changes(), and
MemoryTraceWriter.track_config_changes() methods return lists of
interval objects. Each interval represents a period during which the
hardware configuration was constant.
- class FrequencyInterval¶
A time interval during which a cluster’s operating frequency was constant.
Field
Type
Description
startfloatInterval start time in seconds (inclusive).
stopfloatInterval end time in seconds (exclusive).
frequencyfloatFrequency value as recorded in the trace. See the warning in Python API Overview regarding units.
cluster_idintIdentifier of the clock domain (cluster) this interval applies to.
- class CoreCountInterval¶
A time interval during which the number of active cores in a cluster was constant.
Field
Type
Description
startfloatInterval start time in seconds (inclusive).
stopfloatInterval end time in seconds (exclusive).
active_coresintNumber of cores that were active during this interval.
cluster_idintIdentifier of the cluster this interval applies to.
- class ConfigInterval¶
A time interval during which both the frequency and the active core count of a cluster were constant. Combines the information of
FrequencyIntervalandCoreCountInterval.Field
Type
Description
startfloatInterval start time in seconds (inclusive).
stopfloatInterval end time in seconds (exclusive).
frequencyfloatFrequency value as recorded in the trace.
active_coresintNumber of cores that were active during this interval.
Standalone Functions¶
- compute_metrics_from_file(path: str) SimulationMetrics¶
Compute metrics directly from a JSON trace file.
Reads the file incrementally without loading all events into memory at once. Suitable for large trace files produced by
FileJsonTraceWriter.- Parameters:
path – Path to a JSON trace file.
- Returns:
A
SimulationMetricssummarising the trace.- Raises:
LoaderError – If the file cannot be opened or the JSON is invalid.
- compute_response_time_stats(response_times: list[float]) ResponseTimeStats¶
Compute summary statistics for a list of response times.
- Parameters:
response_times – A list of response time values in seconds. Must be non-empty.
- Returns:
A
ResponseTimeStatswith min, max, mean, median, stddev, and percentile values.
Examples¶
Computing Metrics from a MemoryTraceWriter¶
After an in-process simulation, call MemoryTraceWriter.compute_metrics()
directly:
import pyschedsim as sim
engine = sim.Engine()
# ... platform setup, task injection, scheduler, allocator ...
writer = sim.MemoryTraceWriter()
engine.set_trace_writer(writer)
engine.run()
metrics = writer.compute_metrics()
print(f"Jobs completed : {metrics.completed_jobs}/{metrics.total_jobs}")
print(f"Deadline misses: {metrics.deadline_misses}")
print(f"Preemptions : {metrics.preemptions}")
print(f"Energy : {metrics.total_energy_mj:.2f} mJ")
print(f"Avg utilization: {metrics.average_utilization:.2%}")
# Per-processor breakdown
for proc_id, util in metrics.get_utilization_per_processor().items():
energy = metrics.get_energy_per_processor().get(proc_id, 0.0)
print(f" Proc {proc_id}: util={util:.2%} energy={energy:.2f} mJ")
Computing Metrics from a Trace File¶
When the trace was written to disk by a FileJsonTraceWriter,
compute metrics without loading all events into memory:
import pyschedsim as sim
metrics = sim.compute_metrics_from_file("trace.json")
print(f"Jobs: {metrics.completed_jobs}/{metrics.total_jobs}")
print(f"Deadline misses: {metrics.deadline_misses}")
print(f"Energy: {metrics.total_energy_mj:.2f} mJ")
print(f"Rejected arrivals: {metrics.rejected_arrivals}")
print(f"DVFS transitions: {metrics.transitions}")
Per-Task Response Time Statistics¶
Retrieve per-task response times and compute detailed statistics:
import pyschedsim as sim
# ... run simulation and obtain metrics ...
metrics = writer.compute_metrics()
rt_map = metrics.get_response_times_per_task()
dm_map = metrics.get_deadline_misses_per_task()
for task_id, times in rt_map.items():
if not times:
continue
stats = sim.compute_response_time_stats(times)
misses = dm_map.get(task_id, 0)
print(
f"Task {task_id}: "
f"min={stats.min*1e3:.3f}ms "
f"mean={stats.mean*1e3:.3f}ms "
f"max={stats.max*1e3:.3f}ms "
f"p95={stats.percentile_95*1e3:.3f}ms "
f"p99={stats.percentile_99*1e3:.3f}ms "
f"misses={misses}"
)
Using Time-Series Interval Types¶
Analyse how DVFS and DPM configuration changes over simulation time:
import pyschedsim as sim
# ... run simulation with MemoryTraceWriter ...
# Frequency time-series: when did the clock domains change frequency?
freq_intervals = writer.track_frequency_changes()
for iv in freq_intervals:
duration = iv.stop - iv.start
print(
f"Cluster {iv.cluster_id}: "
f"[{iv.start:.6f}, {iv.stop:.6f}) "
f"{iv.frequency:.0f} MHz ({duration*1e3:.1f} ms)"
)
# Core count time-series: how many cores were active over time?
core_intervals = writer.track_core_changes()
for iv in core_intervals:
print(
f"Cluster {iv.cluster_id}: "
f"[{iv.start:.6f}, {iv.stop:.6f}) "
f"{iv.active_cores} active core(s)"
)
# Combined configuration: frequency + core count together
config_intervals = writer.track_config_changes()
for iv in config_intervals:
print(
f"[{iv.start:.6f}, {iv.stop:.6f}) "
f"{iv.frequency:.0f} MHz, {iv.active_cores} core(s)"
)
See Also¶
Trace Analysis and Metrics — complete analysis tutorial with C++ and Python examples
Trace Writers and Records — trace writer classes and
TraceRecordI/O Library — full C++ metrics and analysis API
CLI Reference —
schedviewcommand-line metrics tool