blob: 583b318341e58d8fffd5e25a1ec26ebd7b5d63cd [file] [log] [blame]
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.ticks import fromSeconds
from m5.util.convert import toLatency, toMemoryBandwidth
from m5.objects import PyTrafficGen, Port
from .abstract_core import AbstractCore
from .abstract_generator_core import AbstractGeneratorCore
from ...utils.override import overrides
from enum import Enum
class TrafficModes(Enum):
"""The traffic mode class
This class is an enum to store traffic mode in a more meaningful way
"""
linear = 0
random = 1
class ComplexTrafficParams:
def __init__(
self,
mode: TrafficModes,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
):
"""The complex traffic params class
This class is a container for parameters to create either a linear or
random traffic. The complex generator core stores a list of complex
traffic params for resolution after m5.instantiate is called.
"""
self._mode = mode
self._duration = duration
self._rate = rate
self._block_size = block_size
self._min_addr = min_addr
self._max_addr = max_addr
self._rd_perc = rd_perc
self._data_limit = data_limit
class ComplexGeneratorCore(AbstractGeneratorCore):
def __init__(self):
"""The complex generator core interface.
This class defines the interface for a generator core that will create
a series of different types of traffic. This core uses PyTrafficGen to
create and inject the synthetic traffic. This generator could be used
to create more complex traffics that consist of linear and random
traffic in different phases.
"""
super().__init__()
self.generator = PyTrafficGen()
self._traffic_params = []
self._traffic = []
self._traffic_set = False
@overrides(AbstractCore)
def connect_dcache(self, port: Port) -> None:
self.generator.port = port
def add_linear(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function will add the params for a linear traffic to the list of
traffic params in this generator core. These params will be later
resolved by the start_traffic call. This core uses a PyTrafficGen to
create the traffic based on the specified params below.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
param = ComplexTrafficParams(
TrafficModes.linear,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic_params = self._traffic_params + [param]
self._traffic_set = False
def add_random(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function will add the params for a random traffic to the list of
traffic params in this generator core. These params will be later
resolved by the start_traffic call. This core uses a PyTrafficGen to
create the traffic based on the specified params below.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
param = ComplexTrafficParams(
TrafficModes.random,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic_params = self._traffic_params + [param]
self._traffic_set = False
def start_traffic(self) -> None:
"""
This function first checks if there are any pending traffics that
require creation, if so it will create the pending traffics based on
traffic_params list and adds them to the traffic list, then it starts
generating the traffic at the top of the traffic list. It also pops the
first element in the list so that every time this function is called a
new traffic is generated, each instance of a call to this function
should happen before each instance of the call to m5.simulate(). All
the instances of calls to this function should happen after
m5.instantiate()
"""
if not self._traffic_set:
self._set_traffic()
if self._traffic:
self.generator.start(self._traffic.pop(0))
else:
print("No phases left to generate!")
def _set_traffic(self) -> None:
"""
This function will pop params from traffic params list and create their
respective traffic and adds the traffic to the core's traffic list.
"""
while self._traffic_params:
param = self._traffic_params.pop(0)
mode = param._mode
duration = param._duration
rate = param._rate
block_size = param._block_size
min_addr = param._min_addr
max_addr = param._max_addr
rd_perc = param._rd_perc
data_limit = param._data_limit
if mode == TrafficModes.linear:
traffic = self._create_linear_traffic(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic = self._traffic + [traffic]
if mode == TrafficModes.random:
traffic = self._create_random_traffic(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic = self._traffic + [traffic]
self._traffic_set = True
def _create_linear_traffic(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function yields (creates) a linear traffic based on the input
params. Then it will yield (create) an exit traffic (exit traffic is
used to exit the simulation).
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
duration = fromSeconds(toLatency(duration))
rate = toMemoryBandwidth(rate)
period = fromSeconds(block_size / rate)
min_period = period
max_period = period
yield self.generator.createLinear(
duration,
min_addr,
max_addr,
block_size,
min_period,
max_period,
rd_perc,
data_limit,
)
yield self.generator.createExit(0)
def _create_random_traffic(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function yields (creates) a random traffic based on the input
params. Then it will yield (create) an exit traffic (exit traffic is
used to exit the simulation).
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
duration = fromSeconds(toLatency(duration))
rate = toMemoryBandwidth(rate)
period = fromSeconds(block_size / rate)
min_period = period
max_period = period
yield self.generator.createRandom(
duration,
min_addr,
max_addr,
block_size,
min_period,
max_period,
rd_perc,
data_limit,
)
yield self.generator.createExit(0)