configs: Add --pmu-{dump,reset}-stats-on to Arm baremetal.py.
Add `--pmu-dump-stats-on <event>` and `--pmu-reset-stats-on <event>` options to the Arm `baremetal.py` config to optionally dump and/or reset stats on various PMU events. These options allow the user to specify which PMU events should cause the dumping or resetting of gem5 stats. The available `<event>`s are PMU `enable`, `disable`, `reset`, and `interrupt`. Both these CLI options may be specified multiple times to enable more than one event to cause a stats dump/reset if desired. Stats are dumped before they are reset. These options are useful for sampled simulation workloads (e.g. SimPoints) which are controlled by the PMU. Change-Id: Ie2ffe11c6aa1f3a57a58425ccec3681c780065c8 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/69959 Maintainer: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
This commit is contained in:
@@ -44,6 +44,7 @@ import m5
|
||||
from m5.util import addToPath
|
||||
from m5.objects import *
|
||||
from m5.options import *
|
||||
from gem5.simulate.exit_event import ExitEvent
|
||||
import argparse
|
||||
|
||||
m5.util.addToPath("../..")
|
||||
@@ -72,6 +73,18 @@ cpu_types = {
|
||||
),
|
||||
}
|
||||
|
||||
pmu_control_events = {
|
||||
"enable": ExitEvent.PERF_COUNTER_ENABLE,
|
||||
"disable": ExitEvent.PERF_COUNTER_DISABLE,
|
||||
"reset": ExitEvent.PERF_COUNTER_RESET,
|
||||
}
|
||||
|
||||
pmu_interrupt_events = {
|
||||
"interrupt": ExitEvent.PERF_COUNTER_INTERRUPT,
|
||||
}
|
||||
|
||||
pmu_stats_events = dict(**pmu_control_events, **pmu_interrupt_events)
|
||||
|
||||
|
||||
def create_cow_image(name):
|
||||
"""Helper function to create a Copy-on-Write disk image"""
|
||||
@@ -158,9 +171,22 @@ def create(args):
|
||||
system.workload = workload_class(object_file, system)
|
||||
|
||||
if args.with_pmu:
|
||||
enabled_pmu_events = set(
|
||||
(*args.pmu_dump_stats_on, *args.pmu_reset_stats_on)
|
||||
)
|
||||
exit_sim_on_control = bool(
|
||||
enabled_pmu_events & set(pmu_control_events.keys())
|
||||
)
|
||||
exit_sim_on_interrupt = bool(
|
||||
enabled_pmu_events & set(pmu_interrupt_events.keys())
|
||||
)
|
||||
for cluster in system.cpu_cluster:
|
||||
interrupt_numbers = [args.pmu_ppi_number] * len(cluster)
|
||||
cluster.addPMUs(interrupt_numbers)
|
||||
cluster.addPMUs(
|
||||
interrupt_numbers,
|
||||
exit_sim_on_control=exit_sim_on_control,
|
||||
exit_sim_on_interrupt=exit_sim_on_interrupt,
|
||||
)
|
||||
|
||||
if args.exit_on_uart_eot:
|
||||
for uart in system.realview.uart:
|
||||
@@ -174,14 +200,35 @@ def run(args):
|
||||
if args.checkpoint:
|
||||
print(f"Checkpoint directory: {cptdir}")
|
||||
|
||||
pmu_exit_msgs = tuple(evt.value for evt in pmu_stats_events.values())
|
||||
pmu_stats_dump_msgs = tuple(
|
||||
pmu_stats_events[evt].value for evt in set(args.pmu_dump_stats_on)
|
||||
)
|
||||
pmu_stats_reset_msgs = tuple(
|
||||
pmu_stats_events[evt].value for evt in set(args.pmu_reset_stats_on)
|
||||
)
|
||||
|
||||
while True:
|
||||
event = m5.simulate()
|
||||
exit_msg = event.getCause()
|
||||
if exit_msg == "checkpoint":
|
||||
print("Dropping checkpoint at tick %d" % m5.curTick())
|
||||
if exit_msg == ExitEvent.CHECKPOINT.value:
|
||||
print(f"Dropping checkpoint at tick {m5.curTick():d}")
|
||||
cpt_dir = os.path.join(m5.options.outdir, "cpt.%d" % m5.curTick())
|
||||
m5.checkpoint(os.path.join(cpt_dir))
|
||||
print("Checkpoint done.")
|
||||
elif exit_msg in pmu_exit_msgs:
|
||||
if exit_msg in pmu_stats_dump_msgs:
|
||||
print(
|
||||
f"Dumping stats at tick {m5.curTick():d}, "
|
||||
f"due to {exit_msg}"
|
||||
)
|
||||
m5.stats.dump()
|
||||
if exit_msg in pmu_stats_reset_msgs:
|
||||
print(
|
||||
f"Resetting stats at tick {m5.curTick():d}, "
|
||||
f"due to {exit_msg}"
|
||||
)
|
||||
m5.stats.reset()
|
||||
else:
|
||||
print(f"{exit_msg} ({event.getCode()}) @ {m5.curTick()}")
|
||||
break
|
||||
@@ -283,6 +330,26 @@ def main():
|
||||
help="The number of the PPI to use to connect each PMU to its core. "
|
||||
"Must be an integer and a valid PPI number (16 <= int_num <= 31).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pmu-dump-stats-on",
|
||||
type=str,
|
||||
default=[],
|
||||
action="append",
|
||||
choices=pmu_stats_events.keys(),
|
||||
help="Specify the PMU events on which to dump the gem5 stats. "
|
||||
"This option may be specified multiple times to enable multiple "
|
||||
"PMU events.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pmu-reset-stats-on",
|
||||
type=str,
|
||||
default=[],
|
||||
action="append",
|
||||
choices=pmu_stats_events.keys(),
|
||||
help="Specify the PMU events on which to reset the gem5 stats. "
|
||||
"This option may be specified multiple times to enable multiple "
|
||||
"PMU events.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--exit-on-uart-eot",
|
||||
action="store_true",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017, 2019, 2021-2022 Arm Limited
|
||||
# Copyright (c) 2016-2017, 2019, 2021-2023 Arm Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
@@ -147,7 +147,13 @@ class ArmCpuCluster(CpuCluster):
|
||||
cpu.connectCachedPorts(self.toL2Bus.cpu_side_ports)
|
||||
self.toL2Bus.mem_side_ports = self.l2.cpu_side
|
||||
|
||||
def addPMUs(self, ints, events=[]):
|
||||
def addPMUs(
|
||||
self,
|
||||
ints,
|
||||
events=[],
|
||||
exit_sim_on_control=False,
|
||||
exit_sim_on_interrupt=False,
|
||||
):
|
||||
"""
|
||||
Instantiates 1 ArmPMU per PE. The method is accepting a list of
|
||||
interrupt numbers (ints) used by the PMU and a list of events to
|
||||
@@ -159,12 +165,21 @@ class ArmCpuCluster(CpuCluster):
|
||||
:type ints: List[int]
|
||||
:param events: Additional events to be measured by the PMUs
|
||||
:type events: List[Union[ProbeEvent, SoftwareIncrement]]
|
||||
:param exit_sim_on_control: If true, exit the sim loop when the PMU is
|
||||
enabled, disabled, or reset.
|
||||
:type exit_on_control: bool
|
||||
:param exit_sim_on_interrupt: If true, exit the sim loop when the PMU
|
||||
triggers an interrupt.
|
||||
:type exit_on_control: bool
|
||||
|
||||
"""
|
||||
assert len(ints) == len(self.cpus)
|
||||
for cpu, pint in zip(self.cpus, ints):
|
||||
int_cls = ArmPPI if pint < 32 else ArmSPI
|
||||
for isa in cpu.isa:
|
||||
isa.pmu = ArmPMU(interrupt=int_cls(num=pint))
|
||||
isa.pmu.exitOnPMUControl = exit_sim_on_control
|
||||
isa.pmu.exitOnPMUInterrupt = exit_sim_on_interrupt
|
||||
isa.pmu.addArchEvents(
|
||||
cpu=cpu,
|
||||
itb=cpu.mmu.itb,
|
||||
|
||||
Reference in New Issue
Block a user