├── .gitignore ├── CHANGELOG.md ├── IHI0092_B_amba_atp_engine_guide.pdf ├── LICENSE ├── Makefile ├── PROGRAMMABILITY.md ├── README.md ├── SConscript ├── configs ├── cpu_memcpy.atp ├── cpu_pointer_chase.atp ├── example.atp ├── flowid_reads.atp ├── gui_examples │ ├── cpu_mc_only.atp │ ├── cpu_pc_mc.atp │ ├── cpu_pc_only.atp │ ├── dpu.atp │ └── gpu.atp ├── slave.atp ├── standard.atp └── stream.atp ├── doxygen.cfg ├── event.cc ├── event.hh ├── event_manager.cc ├── event_manager.hh ├── fifo.cc ├── fifo.hh ├── gem5 ├── ATPDevice.py ├── ProfileGen.py ├── SConscript ├── atp.py ├── atp_device.cc ├── atp_device.hh ├── baremetal_atp.py ├── profile_gen.cc └── profile_gen.hh ├── images └── programmability │ ├── address_reg.svg │ ├── atp_gem5_config.svg │ ├── components.svg │ ├── control_reg.svg │ ├── id_32_reg.svg │ ├── id_64_reg.svg │ ├── range_reg.svg │ └── status_reg.svg ├── kronos.cc ├── kronos.hh ├── linux ├── .gitignore ├── Kbuild ├── Makefile ├── atp_buffer_manager.c ├── atp_buffer_manager.h ├── atp_buffer_manager_user.h ├── atp_device.c ├── atp_device.h ├── atp_device_user.h ├── test │ ├── Makefile │ ├── main.cc │ ├── test_atp_buf.cc │ ├── test_atp_buf.hh │ ├── test_atp_dev.cc │ └── test_atp_dev.hh └── uapi │ ├── Makefile │ ├── atp.c │ └── atp.h ├── logger.cc ├── logger.hh ├── packet_desc.cc ├── packet_desc.hh ├── packet_tagger.cc ├── packet_tagger.hh ├── packet_tracer.cc ├── packet_tracer.hh ├── proto ├── SConscript ├── tp_config.proto ├── tp_packet.proto └── tp_stats.proto ├── random_generator.cc ├── random_generator.hh ├── shell.cc ├── shell.hh ├── stats.cc ├── stats.hh ├── test.cc ├── test_atp.cc ├── test_atp.hh ├── traffic_profile_checker.cc ├── traffic_profile_checker.hh ├── traffic_profile_delay.cc ├── traffic_profile_delay.hh ├── traffic_profile_desc.cc ├── traffic_profile_desc.hh ├── traffic_profile_manager.cc ├── traffic_profile_manager.hh ├── traffic_profile_master.cc ├── traffic_profile_master.hh ├── traffic_profile_slave.cc ├── traffic_profile_slave.hh ├── types.hh ├── utilities.cc ├── utilities.hh └── utils ├── analyzer.py ├── base.py ├── cpu.py ├── dpu.py ├── generic.py ├── gpu.py ├── profiler.py └── ui.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | *.pyc 4 | atpeng 5 | proto/*.cc 6 | proto/*.h 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This document lists the version history of the software and describes relevant changes introduced in each version. 4 | Versions are ordered from most to less recent. 5 | 6 | ## Version 3.2 (06/02/2024) 7 | 8 | - New ProfileDescriptor field (flowID) representing MPAM Partition ID has been added as optional field to traffic profile configuration files; Added example configuration using new flowID field 9 | - Use gem5 PartitionFieldsExtension extension to store flowIDs in generated packets 10 | - Consolidated internal packet metadata tagging functionality into PacketTagger 11 | - Bump C++ version used to 17 to retain compatibility with current libabseil and protobuf 12 | - Add gem5 v22.0+ compatibility; drop gem5 v20.1 support; note that gem5 v23.1+ is required to map flowIDs to PartitionFieldsExtensions 13 | - Updated documentation file to show new features 14 | 15 | ## Version 3.1 (03/02/2020) 16 | 17 | - `ATPDevice` gem5 model is a programmable device enabling run-time configuration of traffic generation 18 | - Supports generation of [DeviceTree](https://www.devicetree.org/) entry for discovery by Linux 19 | - Support for integration with gem5 v20.1 20 | - New `baremetal_atp.py` configuration for instantiating ProfileGen and ATPDevice in a gem5 simulation 21 | - New Linux kernel modules under `linux` for driving ATPDevice based simulations 22 | - Enable allocation of shared memory buffers, configuration and activation of traffic profiles 23 | - Complementary user API under `linux/uapi` for applications to access driving capabilities 24 | - Integration tests under `linux/test` for verifying kernel module and user API correctness 25 | - New programmability.md document, which specifies 26 | - The *Programmers Model* implemented by ATPDevice 27 | - The Linux kernel modules and user API design and usage 28 | - Version history now in CHANGELOG.md document 29 | - Other fixes 30 | 31 | ## Version 3.0 (19/05/2020) [initial release] 32 | 33 | - Standalone Engine C++ code, Protocol Buffer data layer and build files 34 | - Standalone Engine test suite in `test_atp.[hh|cc]` 35 | - Examples of traffic profiles in `.atp` files under `configs` 36 | - `ProfileGen` gem5 model is an adapter enabling integration with open-source [gem5 simulator](https://github.com/gem5/gem5) 37 | - See [building with ATP Engine with gem5](https://github.com/ARM-software/ATP-Engine#hosted-gem5) for details 38 | - Standard `atp.py` configuration for instantiating ProfileGen in a gem5 simulation 39 | - Python utilities under `utils` to use for exploration of traffic profiles and Engine traces 40 | - Software specification in Arm AMBA ATP Engine Specification (IHI0092) - Issue A 41 | - License statement - Clear BSD License 42 | - Usage instructions in README.md 43 | -------------------------------------------------------------------------------- /IHI0092_B_amba_atp_engine_guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARM-software/ATP-Engine/e411a12f54eef54b6b51689a5efb3c34db31500d/IHI0092_B_amba_atp_engine_guide.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Clear BSD License 2 | 3 | Copyright (c) 2012-2020 ARM Limited 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted (subject to the limitations in the disclaimer 8 | below) provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY 22 | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 30 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2016-2019 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | 7 | # ATP Engine standalone Makefile 8 | # it is required that you register or export in you library path both google protocol 9 | # buffer and cppunit libraries. i.e. 10 | # 11 | # export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/lib 12 | # export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/lib 13 | # 14 | 15 | CXX := g++ 16 | PROTOC := protoc 17 | PROTOBUF_C_FLAGS:= $(shell pkg-config --cflags protobuf) 18 | CPPUNIT_C_FLAGS := $(shell pkg-config --cflags cppunit) 19 | PROTOBUF_L_FLAGS:= $(shell pkg-config --libs protobuf) 20 | CPPUNIT_L_FLAGS := $(shell pkg-config --libs cppunit) 21 | CXX_FLAGS := $(PROTOBUF_C_FLAGS) -std=c++17 -Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-variable $(CPPUNIT_C_FLAGS) -fPIC $(EXTRA_CXX_FLAGS) 22 | LD_FLAGS := $(PROTOBUF_L_FLAGS) $(CPPUNIT_L_FLAGS) $(EXTRA_LD_FLAGS) 23 | PROTO_SRC_DIR := ./proto/ 24 | PROTO_SRC := $(wildcard $(PROTO_SRC_DIR)tp*.proto) 25 | PROTO_DIR := ./proto/ 26 | LIB_CPP_FILES := kronos.cc utilities.cc event.cc event_manager.cc fifo.cc logger.cc packet_desc.cc packet_tagger.cc \ 27 | packet_tracer.cc random_generator.cc stats.cc \ 28 | traffic_profile_desc.cc traffic_profile_manager.cc traffic_profile_master.cc traffic_profile_checker.cc \ 29 | traffic_profile_slave.cc traffic_profile_delay.cc 30 | LIB_H_FILES := $(LIB_CPP_FILES:.cc=.hh) types.hh 31 | LIB_OBJ_FILES := $(LIB_CPP_FILES:.cc=.o) 32 | TEST_CPP_FILES := shell.cc test_atp.cc test.cc 33 | TEST_H_FILES := test_atp.hh shell.hh 34 | TEST_OBJ_FILES := $(TEST_CPP_FILES:.cc=.o) 35 | CPP_FILES := $(LIB_CPP_FILES) $(TEST_CPP_FILES) 36 | H_FILES := $(LIB_H_FILES) $(TEST_H_FILES) 37 | PROTO_OBJ_FILES := $(addprefix $(PROTO_DIR), $(notdir $(PROTO_SRC:.proto=.pb.o))) 38 | PROTO_CPP_FILES := $(PROTO_OBJ_FILES:.o=.cc) 39 | PROTO_H_FILES := $(PROTO_OBJ_FILES:.o=.h) 40 | 41 | # install command (MKDIR and FILE) and install directory for the make install target 42 | prefix ?= ./install 43 | exec_prefix ?= $(prefix) 44 | bindir ?= $(exec_prefix)/bin 45 | libdir ?= $(exec_prefix)/lib 46 | includedir ?= $(prefix)/include/arm/atp 47 | INSTALL_EXEC := install -m 755 48 | INSTALL_MKDIR := $(INSTALL_EXEC) -d 49 | INSTALL_FILE := install -m 644 50 | 51 | # binary name 52 | BIN := atpeng 53 | STATIC_LIB := libatp.a 54 | # log file name for debug_file target 55 | LOG_FILE_NAME := atp.log 56 | 57 | # create protocol buffer directory if it does not exist 58 | $(shell mkdir -p $(PROTO_DIR)) 59 | 60 | all: CXX_FLAGS += -O3 61 | all: $(BIN) $(STATIC_LIB) 62 | 63 | debug: CXX_FLAGS += -O0 -ggdb 64 | debug: $(BIN) 65 | 66 | debug_file: CXX_FLAGS += -DLOG_FILE="\"$(LOG_FILE_NAME)\"" 67 | debug_file: debug 68 | 69 | .PHONY: clean cleanest install install-include install-include-proto install-lib 70 | 71 | %.pb.cc %.pb.h: %.proto 72 | $(PROTOC) -I $(PROTO_SRC_DIR) --cpp_out=$(PROTO_DIR) $< 73 | 74 | $(BIN): $(TEST_OBJ_FILES) $(STATIC_LIB) 75 | $(CXX) $^ $(LD_FLAGS) -o $@ 76 | 77 | $(STATIC_LIB): $(LIB_OBJ_FILES) $(PROTO_OBJ_FILES) 78 | ar rcs $(STATIC_LIB) $^ 79 | 80 | %.o: %.cc $(PROTO_H_FILES) $(H_FILES) 81 | $(CXX) $(CPPFLAGS) $(CXX_FLAGS) -c -o $@ $< 82 | 83 | clean: 84 | @rm -rf $(PROTO_OBJ_FILES) 85 | @rm -rf $(PROTO_H_FILES) 86 | @rm -rf $(PROTO_CPP_FILES) 87 | @rm -rf *.o 88 | @rm -rf $(STATIC_LIB) 89 | 90 | cleanest: clean 91 | @rm -rf $(BIN) 92 | 93 | count: 94 | @echo "Source code lines:" 95 | @find . -name '*.cc' -o -name '*.hh'| xargs wc -l 96 | @echo "Google Protocol Buffer code lines:" 97 | @find $(PROTO_SRC_DIR) -name 'tp*.proto' | xargs wc -l 98 | 99 | doc: $(H_FILES) $(CPP_FILES) 100 | @doxygen doxygen.cfg 101 | 102 | install: install-include install-include-proto install-lib install-bin 103 | 104 | install-include-proto: $(PROTO_H_FILES) 105 | $(INSTALL_MKDIR) $(includedir)/proto 106 | $(INSTALL_FILE) $^ $(includedir)/proto 107 | 108 | install-include: $(LIB_H_FILES) 109 | $(INSTALL_MKDIR) $(includedir) 110 | $(INSTALL_FILE) $^ $(includedir) 111 | 112 | install-lib: $(STATIC_LIB) 113 | $(INSTALL_MKDIR) $(libdir) 114 | $(INSTALL_FILE) $^ $(libdir) 115 | 116 | install-bin: $(BIN) 117 | $(INSTALL_MKDIR) $(bindir) 118 | $(INSTALL_EXEC) $^ $(bindir) 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AMBA ATP Engine 2 | 3 | AMBA *Adaptive Traffic Profiles* (ATP) Engine is a C++11 implementation of the AMBA ATP specification ([ARM IHI 0082A](http://infocenter.arm.com/help/topic/com.arm.doc.ihi0082a/IHI0082A_amba_adaptive_traffic_profiles_specification.pdf)). The latter describes *Traffic Profiles* as definitions of the transaction characteristics of an interface. With AMBA ATP Engine, Traffic Profiles may be defined and composed in order to model master / slave component behaviours within a system. 4 | 5 | ## Description 6 | 7 | The following are central concepts to AMBA ATP Engine: 8 | 9 | * **FIFO Model** - Tracks data either read or written by a master or slave device. Imposes data rate constraints. 10 | * **Packet Descriptor** - Defines patterns for both addresses and sizes of packets generated. 11 | * **Traffic Profile Descriptor** - Abstract entity defining a Traffic Profile as per the specification. 12 | * **Master Traffic Profile** - Sends requests and receives responses based on its FIFO model and Packet Descriptor. 13 | * **Checker Traffic Profile** - Tracks another Traffic Profile Descriptor and records its transactions. 14 | * **Delay Traffic Profile** - Implements a simple delay block. Useful for defining pauses on combining Traffic Profiles. 15 | * **Slave Traffic Profile** - Fixed latency and bandwidth memory slave. Receives requests and sends responses based on its FIFO model. 16 | * **Events** - Drive interactions among Traffic Profiles. They represent occurrences within the Engine. 17 | * **Kronos** - Engine internal Future Event List (FEL) for event handling. 18 | * **Traffic Profile Manager (TPM)** - Central entity that manages all configured Traffic Profiles and arbitrates their activation and deactivation. 19 | * **Stream** - Buffered sequence of packets defined by one or more Traffic Profiles chained together on *termination* events. 20 | * TPM provides Stream Management APIs for initialization, configuration and activation of Streams. 21 | * **ATP Files (.atp)** - Protocol Buffer based files for Traffic Profile definitions. 22 | * **Adapter** - When integrating the Engine with a host platform, this entity defines the interface between both. 23 | 24 | A copy of the official Guide is included in this repository. Please refer to it for further information. 25 | 26 | ## Installation 27 | 28 | The Engine may be built as a standalone executable or as part of a host platform, such as [gem5](https://www.gem5.org). GNU/Linux and macOS environments are supported. 29 | 30 | ### Requirements 31 | 32 | * Build process: [g++](https://gcc.gnu.org/install/) v4.8.1+ or [clang++](https://clang.llvm.org/get_started.html) v3.3+ and [make](https://www.gnu.org/software/make/) v3.80+ 33 | * Traffic Profile definitions: [protobuf](https://github.com/protocolbuffers/protobuf/blob/master/src/README.md) v3.6.1+ 34 | * Unit testing: [cppunit](https://www.freedesktop.org/wiki/Software/cppunit/) v1.13.0+ 35 | * Documentation: [doxygen](http://www.doxygen.nl/manual/install.html) v1.8.10+ 36 | 37 | If building as part of a host platform, verify host platform requirements are satisfied. For gem5, see [requirements](https://www.gem5.org/documentation/general_docs/building). 38 | 39 | ```bash 40 | git clone https://github.com/ARM-software/ATP-Engine 41 | ``` 42 | 43 | ### Standalone 44 | 45 | ```bash 46 | cd ATP-Engine/ 47 | make -j $(nproc) 48 | ``` 49 | 50 | An executable ``atpeng`` and a static library ``libatp.a`` are produced as a result. 51 | 52 | ### Hosted (gem5) 53 | 54 | ```bash 55 | git clone https://github.com/gem5/gem5 -b v20.1.0.2 56 | cd gem5/ 57 | scons EXTRAS=../ATP-Engine -j $(nproc) build/ARM/gem5.opt 58 | ``` 59 | 60 | ATP Engine is integrated in the resulting ``gem5/build/ARM/gem5.opt`` binary. 61 | 62 | ## Usage 63 | 64 | ### Traffic Profiles Definition 65 | 66 | Traffic Profiles are defined in ATP files (``.atp``), which are later loaded into the Engine through TPM. Several example ATP files may be found under ``configs/``. See *Appendix A - AMBA ATP Engine Configuration* in the official Guide for documentation on ``.atp`` syntax. 67 | 68 | ### Standalone 69 | 70 | #### Basic use 71 | 72 | ```bash 73 | ./atpeng [.atp file, ...] 74 | ``` 75 | 76 | This will instantiate and activate the Traffic Profiles defined in those files along with a default Slave Traffic Profile defined by ``rate`` and ``latency``. 77 | 78 | #### Interactive mode (experimental) 79 | 80 | ```bash 81 | ./atpeng -i 82 | ``` 83 | 84 | This will spawn an interactive shell. Type ``help`` from within for more information. 85 | 86 | #### Output 87 | 88 | At the end of a usage, the Engine produces a set of statistics, both global and per maste / slave component. See *3.4 - Statistics* in the official Guide. 89 | 90 | ### Hosted (gem5) 91 | 92 | The ``gem5/`` directory contains models and configurations for integration with the gem5 simulator, in particular: 93 | 94 | * ``ProfileGen`` - gem5 Adapter layer for the Engine. Handles interactions between both entities and exposes Engine APIs to the rest of gem5. 95 | * ``atp.py`` - gem5 configuration script with integrated ProfileGen support. 96 | 97 | #### Basic use 98 | 99 | gem5 may parse, configure, instantiate and run the simulation from ``atp.py`` as follows: 100 | 101 | ```bash 102 | gem5/build/ARM/gem5.opt ATP-Engine/gem5/atp.py 103 | ``` 104 | 105 | The following are some examples of ``atp.py`` usage: 106 | 107 | ```bash 108 | # Load and activate standard.atp 109 | [...]/atp.py --config_files ATP-Engine/configs/example.atp 110 | # Configure a STREAM_A read Stream and STREAM_B write Stream each on its own master; provide base, range and simulation ID 111 | # Note: these Streams are required to exist within the Engine, i.e. loaded via "config_files" or "config-paths" 112 | [...]/atp.py --streams STREAM_A,MASTER_A,R,0x1000,0x2000,123456 STREAM_B,MASTER_B,R,0x5000,0x2000,123457 113 | # Load all ATP files and activate Traffic Profiles under gui_examples/ 114 | [...]/atp.py --config-paths ATP-Engine/configs/gui_examples 115 | ``` 116 | 117 | #### Output 118 | 119 | Engine statistics are combined into gem5 statistics when running along it. See [Understanding gem5 statistics and output](https://www.gem5.org/documentation/learning_gem5/part1/gem5_stats/) for more information. 120 | 121 | ## Testing 122 | 123 | Engine unit tests are based on the [cppunit](https://www.freedesktop.org/wiki/Software/cppunit/) library. To run all tests: 124 | 125 | ```bash 126 | ./atpeng 127 | ``` 128 | 129 | ## Authors and acknowledgment 130 | 131 | * AMBA ATP Specification (ARM IHI 0082A) 132 | * Author - Bruce Mathewson (bruce.mathewson@arm.com) 133 | * AMBA ATP Engine (ARM IHI 0092A) 134 | * Author - Matteo Andreozzi (matteo.andreozzi@arm.com) 135 | * Maintainers - Matteo Andreozzi, Adrian Herrera (adrian.herrera@arm.com) 136 | 137 | ## License 138 | 139 | AMBA ATP Engine code is licensed under the *Clear BSD License*, see ``LICENSE`` for details. 140 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | 3 | # SPDX-License-Identifier: BSD-3-Clause-Clear 4 | # 5 | # Copyright (c) 2012 ARM Limited 6 | # All rights reserved. 7 | # Authors: Matteo Andreozzi 8 | 9 | Import('*') 10 | 11 | # Only build the traffic generator if we have support for protobuf as the 12 | # tracing relies on it 13 | if env['CONF']['HAVE_PROTOBUF']: 14 | Source('traffic_profile_manager.cc') 15 | Source('traffic_profile_desc.cc') 16 | Source('traffic_profile_master.cc') 17 | Source('traffic_profile_checker.cc') 18 | Source('traffic_profile_slave.cc') 19 | Source('traffic_profile_delay.cc') 20 | Source('random_generator.cc') 21 | Source('packet_desc.cc') 22 | Source('packet_tagger.cc') 23 | Source('packet_tracer.cc') 24 | Source('event.cc') 25 | Source('event_manager.cc') 26 | Source('logger.cc') 27 | Source('fifo.cc') 28 | Source('stats.cc') 29 | Source('kronos.cc') 30 | Source('utilities.cc') 31 | -------------------------------------------------------------------------------- /configs/cpu_memcpy.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2015 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | # 7 | # AMBA Traffic Profile CPU MEM COPY in foreground (flat bandwidth) 8 | # It does simulate a CPU doing a mem copy operation 9 | # 10 | # OT: 32 11 | # FIFO : 2048 12 | # Total bandwidth 24 GB/s (READS/WRITES 1:1) 13 | 14 | profile { 15 | type: READ 16 | master_id: "CPU_MEMCPY_R" 17 | fifo { 18 | Full: 2048 19 | TxnLimit: 32 20 | Total_txn: 800000 21 | Rate: "12 GB/s" 22 | } 23 | pattern { 24 | address { 25 | Base: 0 26 | Increment:64 27 | } 28 | } 29 | name: "CPU_MEMCPY_READS" 30 | } 31 | 32 | profile { 33 | type: WRITE 34 | master_id: "CPU_MEMCPY_W" 35 | fifo { 36 | Full: 2048 37 | TxnLimit: 32 38 | Total_txn: 800000 39 | Rate: "12 GB/s" 40 | } 41 | pattern { 42 | address { 43 | base: 0 44 | increment:64 45 | } 46 | } 47 | name: "CPU_MEMCPY_WRITES" 48 | wait_for: "CPU_MEMCPY_READS PROFILE_LOCKED" 49 | } 50 | -------------------------------------------------------------------------------- /configs/cpu_pointer_chase.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2015 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | # 7 | # AMBA Traffic Profile CPU Pointer Chasing (flat bandwidth) 8 | # It does simulate a CPU issuing instruction with 1 max OT 9 | # 10 | # OT: 1 11 | # FIFO : diabled (rate 0, level 0) 12 | # Total bandwidth OT Limited (READS/WRITES 1:1) 13 | 14 | profile { 15 | type: READ 16 | master_id: "CPU_POINTER_R" 17 | fifo { 18 | Full: 0 19 | TxnLimit: 1 20 | Total_txn: 800000 21 | Rate: "0" 22 | } 23 | pattern { 24 | address { 25 | base: 0 26 | increment:64 27 | } 28 | } 29 | name: "CPU_POINTER_READS" 30 | } 31 | 32 | profile { 33 | type: WRITE 34 | master_id: "CPU_POINTER_W" 35 | fifo { 36 | Full: 0 37 | TxnLimit: 1 38 | Total_txn: 800000 39 | Rate: "0" 40 | } 41 | pattern { 42 | cmd: WRITE_REQ 43 | address { 44 | base: 0 45 | increment:64 46 | } 47 | } 48 | name: "CPU_POINTER_WRITES" 49 | wait_for: "CPU_POINTER_READS PROFILE_LOCKED" 50 | } 51 | -------------------------------------------------------------------------------- /configs/example.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2015 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | 7 | profile { 8 | type: WRITE 9 | master_id: "EXAMPLE" 10 | fifo { 11 | Full: 2048 12 | TxnLimit: 32 13 | Start: EMPTY 14 | Rate: "12GB/s" 15 | FrameSize: "2MB" 16 | } 17 | pattern { 18 | address { 19 | base: 0x0000 20 | increment:64 21 | } 22 | } 23 | name: "EXAMPLE_WRITES" 24 | } 25 | 26 | 27 | profile { 28 | type: READ 29 | master_id: "EXAMPLE" 30 | fifo { 31 | Full: 2048 32 | TxnLimit : 32 33 | Start: FULL 34 | Rate: "12GB/s" 35 | FrameSize: "2MB" 36 | } 37 | pattern { 38 | address { 39 | base: 0xFFFF 40 | increment: 64 41 | } 42 | } 43 | name: "EXAMPLE_READS" 44 | } 45 | -------------------------------------------------------------------------------- /configs/flowid_reads.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2024 ARM Limited 4 | # All rights reserved 5 | # Authors: Hristo Belchev 6 | 7 | # This configuration features two masters with different flow_ids operating in 8 | # parallel; Each master reads an address range of 256KiB twice, once to 9 | # simulate filling up a cache, and once to simulate reading from cache. This 10 | # profile is intented to test resource partitioning. 11 | 12 | profile { 13 | type: READ 14 | master_id: "READS_1" 15 | flow_id: 1 16 | fifo { 17 | start_fifo_level: EMPTY 18 | full_level: 0 19 | ot_limit: 30 20 | total_txn: 8192 21 | rate: "0" 22 | } 23 | pattern { 24 | address { 25 | base: 0 26 | } 27 | stride { 28 | Stride: 64 29 | Xrange: "262144B" 30 | } 31 | size: 64 32 | } 33 | name: "READS_1" 34 | } 35 | 36 | profile { 37 | type: READ 38 | master_id: "READS_2" 39 | flow_id: 2 40 | fifo { 41 | start_fifo_level: EMPTY 42 | full_level: 0 43 | ot_limit: 30 44 | total_txn: 8192 45 | rate: "0" 46 | } 47 | pattern { 48 | address { 49 | base: 262144 50 | } 51 | stride { 52 | Stride: 64 53 | Xrange: "262144B" 54 | } 55 | size: 64 56 | } 57 | name: "READS_2" 58 | } 59 | -------------------------------------------------------------------------------- /configs/gui_examples/cpu_mc_only.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2017 ARM Limited 4 | # All rights reserved 5 | # Author: Riken Gohil 6 | # 7 | # AMBA Traffic Profile CPU: 8 | # 9 | # 100.0% CPU MEM COPY in foreground (flat bandwidth) 10 | # It does simulate a CPU doing a mem copy operation 11 | # MC OT: 5 12 | # MC FIFO : 10 13 | # MC Total bandwidth 100.0 KB/s (READS/WRITES 1:1) 14 | # MC READ Address Type: NORMAL 15 | # MC READ Address Standard Deviation: 4 16 | # MC READ Address Mean: 4096 17 | # MC WRITE Address Type: WEIBULL 18 | # MC WRITE Address Shape: 1 19 | # MC WRITE Address Scale: 10 20 | # 21 | # Total Data Transferred: 22 | # CPU MC Data: 10000*64 Bytes 23 | 24 | lowId:0 25 | highId:2014 26 | profile { 27 | type: READ 28 | master_id: "CPU_1" 29 | fifo { 30 | start_fifo_level: FULL 31 | full_level: 10 32 | ot_limit: 5 33 | total_txn: 10000 34 | rate: "50.0 KB/s" 35 | } 36 | pattern { 37 | cmd: READ_REQ 38 | random_address { 39 | type: NORMAL 40 | normal_desc { 41 | mean: 4096 42 | std_dev: 4 43 | } 44 | } 45 | size: 64 46 | } 47 | name: "CPU_MEMCPY_READS" 48 | } 49 | 50 | profile { 51 | type: WRITE 52 | master_id: "CPU_1" 53 | fifo { 54 | start_fifo_level: EMPTY 55 | full_level: 10 56 | ot_limit: 5 57 | total_txn: 10000 58 | rate: "50.0 KB/s" 59 | } 60 | pattern { 61 | cmd: WRITE_REQ 62 | random_address { 63 | type: WEIBULL 64 | weibull_desc { 65 | shape: 1 66 | scale: 10 67 | } 68 | } 69 | size: 64 70 | } 71 | name: "CPU_MEMCPY_WRITES" 72 | wait_for: "CPU_MEMCPY_READS PROFILE_LOCKED" 73 | } 74 | -------------------------------------------------------------------------------- /configs/gui_examples/cpu_pc_mc.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2017 ARM Limited 4 | # All rights reserved 5 | # Author: Riken Gohil 6 | # 7 | # AMBA Traffic Profile CPU: 8 | # 9 | # 71.0% CPU Pointer Chasing: 10 | # It does simulate a CPU issuing instruction with 10 max OT each 11 | # PC OT: 10 12 | # PC FIFO : disabled (rate 0, level 0) 13 | # PC Total bandwidth OT Limited (READS/WRITES 1:1) 14 | # PC READ Address Type: LINEAR 15 | # PC READ Address Base: 0 16 | # PC READ Address Increment: 64 17 | # PC WRITE Address Type: UNIFORM 18 | # PC WRITE Address Min: 1024 19 | # PC WRITE Address Max: 8192 20 | # 21 | # 29.0% CPU MEM COPY in foreground (flat bandwidth) 22 | # It does simulate a CPU doing a mem copy operation 23 | # MC OT: 5 24 | # MC FIFO : 10 25 | # MC Total bandwidth 100.0 KB/s (READS/WRITES 1:1) 26 | # MC READ Address Type: NORMAL 27 | # MC READ Address Standard Deviation: 4 28 | # MC READ Address Mean: 4096 29 | # MC WRITE Address Type: WEIBULL 30 | # MC WRITE Address Shape: 1 31 | # MC WRITE Address Scale: 10 32 | # 33 | # Total Data Transferred: 34 | # CPU PC Data: 7100*64 Bytes 35 | # CPU MC Data: 2900*64 Bytes 36 | 37 | lowId:0 38 | highId:2014 39 | profile { 40 | type: READ 41 | master_id: "CPU_1" 42 | fifo { 43 | start_fifo_level: EMPTY 44 | full_level: 0 45 | ot_limit: 10 46 | total_txn: 7100 47 | rate: "0" 48 | } 49 | pattern { 50 | cmd: READ_REQ 51 | address { 52 | base: 0 53 | increment: 64 54 | } 55 | size: 64 56 | } 57 | name: "CPU_POINTER_READS_1" 58 | } 59 | 60 | profile { 61 | type: WRITE 62 | master_id: "CPU_1" 63 | fifo { 64 | start_fifo_level: EMPTY 65 | full_level: 0 66 | ot_limit: 10 67 | total_txn: 7100 68 | rate: "0" 69 | } 70 | pattern { 71 | cmd: WRITE_REQ 72 | random_address { 73 | type: UNIFORM 74 | uniform_desc { 75 | min: 1024 76 | max: 8192 77 | } 78 | } 79 | size: 64 80 | } 81 | name: "CPU_POINTER_WRITES_1" 82 | wait_for: "CPU_POINTER_READS_1 PROFILE_LOCKED" 83 | } 84 | 85 | profile { 86 | type: READ 87 | master_id: "CPU_1" 88 | fifo { 89 | start_fifo_level: FULL 90 | full_level: 10 91 | ot_limit: 5 92 | total_txn: 2900 93 | rate: "50.0 KB/s" 94 | } 95 | pattern { 96 | cmd: READ_REQ 97 | random_address { 98 | type: NORMAL 99 | normal_desc { 100 | mean: 4096 101 | std_dev: 4 102 | } 103 | } 104 | size: 64 105 | } 106 | name: "CPU_MEMCPY_READS" 107 | wait_for: "CPU_POINTER_READS_1" 108 | wait_for: "CPU_POINTER_WRITES_1" 109 | } 110 | 111 | profile { 112 | type: WRITE 113 | master_id: "CPU_1" 114 | fifo { 115 | start_fifo_level: EMPTY 116 | full_level: 10 117 | ot_limit: 5 118 | total_txn: 2900 119 | rate: "50.0 KB/s" 120 | } 121 | pattern { 122 | cmd: WRITE_REQ 123 | random_address { 124 | type: WEIBULL 125 | weibull_desc { 126 | shape: 1 127 | scale: 10 128 | } 129 | } 130 | size: 64 131 | } 132 | name: "CPU_MEMCPY_WRITES" 133 | wait_for: "CPU_MEMCPY_READS PROFILE_LOCKED" 134 | wait_for: "CPU_POINTER_READS_1" 135 | wait_for: "CPU_POINTER_WRITES_1" 136 | } 137 | -------------------------------------------------------------------------------- /configs/gui_examples/cpu_pc_only.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2017 ARM Limited 4 | # All rights reserved 5 | # Author: Riken Gohil 6 | # 7 | # AMBA Traffic Profile CPU: 8 | # 9 | # 100.0% CPU Pointer Chasing: 10 | # It does simulate a CPU issuing instruction with 10 max OT each 11 | # PC OT: 10 12 | # PC FIFO : disabled (rate 0, level 0) 13 | # PC Total bandwidth OT Limited (READS/WRITES 1:1) 14 | # PC READ Address Type: LINEAR 15 | # PC READ Address Base: 0 16 | # PC READ Address Increment: 64 17 | # PC WRITE Address Type: UNIFORM 18 | # PC WRITE Address Min: 1024 19 | # PC WRITE Address Max: 8192 20 | # 21 | # Total Data Transferred: 22 | # CPU PC Data: 10000*64 Bytes 23 | 24 | lowId:0 25 | highId:2014 26 | profile { 27 | type: READ 28 | master_id: "CPU_1" 29 | fifo { 30 | start_fifo_level: EMPTY 31 | full_level: 0 32 | ot_limit: 10 33 | total_txn: 10000 34 | rate: "0" 35 | } 36 | pattern { 37 | cmd: READ_REQ 38 | address { 39 | base: 0 40 | increment: 64 41 | } 42 | size: 64 43 | } 44 | name: "CPU_POINTER_READS_1" 45 | } 46 | 47 | profile { 48 | type: WRITE 49 | master_id: "CPU_1" 50 | fifo { 51 | start_fifo_level: EMPTY 52 | full_level: 0 53 | ot_limit: 10 54 | total_txn: 10000 55 | rate: "0" 56 | } 57 | pattern { 58 | cmd: WRITE_REQ 59 | random_address { 60 | type: UNIFORM 61 | uniform_desc { 62 | min: 1024 63 | max: 8192 64 | } 65 | } 66 | size: 64 67 | } 68 | name: "CPU_POINTER_WRITES_1" 69 | wait_for: "CPU_POINTER_READS_1 PROFILE_LOCKED" 70 | } -------------------------------------------------------------------------------- /configs/gui_examples/dpu.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2017 ARM Limited 4 | # All rights reserved 5 | # Author: Riken Gohil 6 | # 7 | # AMBA Traffic Profile DPU: 8 | # 9 | # It does simulate DPU processing 10 | # X pixels: 3840 11 | # Y pixels: 2160 12 | # FPS: 120 13 | # Bits per Pixel: 10 14 | # Layers: 4 15 | # Data Size: 64 16 | # Total Transactions: 1296000 17 | # Timings: 1.5e-07 18 | # READ Address Type: POISSON 19 | # READ Address Mean: 10 20 | # Total needed rate: 3840 * 2160 * 120 * 10 / 8 = 21 | # 1.24416 GB/s on 4 layers. 22 | # FULL Level : data rate * 1.5e-07s 23 | # OT : FULL Level / Packet Size 24 | 25 | lowId:0 26 | highId:1024 27 | profile { 28 | type: READ 29 | master_id: "DPU_1" 30 | fifo { 31 | start_fifo_level: FULL 32 | full_level: 486 33 | ot_limit: 4 34 | total_txn: 1296000 35 | rate: "1.24416 GB/s" 36 | } 37 | pattern { 38 | cmd: READ_REQ 39 | random_address { 40 | type: POISSON 41 | poisson_desc { 42 | mean: 10 43 | } 44 | } 45 | size: 64 46 | } 47 | name: "DPU_1_LAYER_1" 48 | } 49 | 50 | profile { 51 | type: READ 52 | master_id: "DPU_1" 53 | fifo { 54 | start_fifo_level: FULL 55 | full_level: 486 56 | ot_limit: 4 57 | total_txn: 1296000 58 | rate: "1.24416 GB/s" 59 | } 60 | pattern { 61 | cmd: READ_REQ 62 | random_address { 63 | type: POISSON 64 | poisson_desc { 65 | mean: 10 66 | } 67 | } 68 | size: 64 69 | } 70 | name: "DPU_1_LAYER_2" 71 | } 72 | 73 | profile { 74 | type: READ 75 | master_id: "DPU_1" 76 | fifo { 77 | start_fifo_level: FULL 78 | full_level: 486 79 | ot_limit: 4 80 | total_txn: 1296000 81 | rate: "1.24416 GB/s" 82 | } 83 | pattern { 84 | cmd: READ_REQ 85 | random_address { 86 | type: POISSON 87 | poisson_desc { 88 | mean: 10 89 | } 90 | } 91 | size: 64 92 | } 93 | name: "DPU_1_LAYER_3" 94 | } 95 | 96 | profile { 97 | type: READ 98 | master_id: "DPU_1" 99 | fifo { 100 | start_fifo_level: FULL 101 | full_level: 486 102 | ot_limit: 4 103 | total_txn: 1296000 104 | rate: "1.24416 GB/s" 105 | } 106 | pattern { 107 | cmd: READ_REQ 108 | random_address { 109 | type: POISSON 110 | poisson_desc { 111 | mean: 10 112 | } 113 | } 114 | size: 64 115 | } 116 | name: "DPU_1_LAYER_4" 117 | } 118 | -------------------------------------------------------------------------------- /configs/gui_examples/gpu.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2017 ARM Limited 4 | # All rights reserved 5 | # Author: 6 | # 7 | # AMBA Traffic Profile GPU (flat bandwidth): 8 | # 9 | # Reading / Writing data equal to 3840 * 2160 * 4 bytes per pixel 10 | # (10 frame) at 60 Frames per second: 19.90656 GB/s 11 | # 12 | # X pixels: 3840 13 | # Y pixels: 2160 14 | # FPS: 60 15 | # Bytes per Pixel: 4 16 | # Frames: 10 17 | # Data Size: 64 18 | # Total Transactions: 128000 19 | # OT: 10 20 | # FIFO : OT*PacketSize = 7776 21 | # READ Address Type: LINEAR 22 | # READ Address Base: 0 23 | # READ Address Increment: 64 24 | # WRITE Address Type: NORMAL 25 | # WRITE Address Standard Deviation: 10 26 | # WRITE Address Mean: 4096 27 | # 28 | 29 | lowId:0 30 | highId:1024 31 | profile { 32 | type: READ 33 | master_id: "GPU" 34 | fifo { 35 | start_fifo_level: FULL 36 | full_level: 7776 37 | ot_limit: 10 38 | total_txn: 128000 39 | rate: "19.90656 GB/s" 40 | } 41 | pattern { 42 | cmd: READ_REQ 43 | address { 44 | base: 0 45 | increment: 64 46 | } 47 | size: 64 48 | } 49 | name: "GPU_READS" 50 | } 51 | 52 | profile { 53 | type: WRITE 54 | master_id: "GPU" 55 | fifo { 56 | start_fifo_level: EMPTY 57 | full_level: 7776 58 | ot_limit: 10 59 | total_txn: 128000 60 | rate: "19.90656 GB/s" 61 | } 62 | pattern { 63 | cmd: WRITE_REQ 64 | random_address { 65 | type: NORMAL 66 | normal_desc { 67 | mean: 4096 68 | std_dev: 10 69 | } 70 | } 71 | size: 64 72 | } 73 | name: "GPU_WRITES" 74 | wait_for: "GPU_READS PROFILE_LOCKED" 75 | } 76 | -------------------------------------------------------------------------------- /configs/slave.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2015 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | 7 | profile { 8 | slave { 9 | TxnSize: 32 10 | TxnLimit: 50 11 | Latency: "10ns" 12 | Rate: "10GB/s" 13 | Master: "EXAMPLE" 14 | } 15 | name : "SLAVE" 16 | } 17 | -------------------------------------------------------------------------------- /configs/standard.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2015 ARM Limited 4 | # All rights reserved 5 | # Authors: Matteo Andreozzi 6 | 7 | 8 | profile { 9 | type: WRITE 10 | master_id: "ALPHA" 11 | fifo { 12 | Full: 10000 13 | FrameSize: "2KB" 14 | Rate: "20MBps" 15 | } 16 | pattern { 17 | random_address { 18 | type: UNIFORM 19 | uniform_desc { 20 | min: 50 21 | max: 500 22 | } 23 | } 24 | alignment: 64 25 | } 26 | name: "PIPPO" 27 | } 28 | 29 | 30 | 31 | profile { 32 | type: READ 33 | master_id: "OMEGA" 34 | fifo { 35 | Full: 10000 36 | TxnLimit: 40 37 | FrameTime : "10ns" 38 | Rate: "20MBps" 39 | } 40 | pattern { 41 | address { 42 | Base: 0 43 | Yrange: "4096B" 44 | } 45 | stride { 46 | Stride: 64 47 | Xrange: "256B" 48 | } 49 | } 50 | name: "PLUTO" 51 | wait_for: "PIPPO" 52 | } 53 | -------------------------------------------------------------------------------- /configs/stream.atp: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2019 ARM Limited 4 | # All rights reserved 5 | # Author: Matteo Andreozzi 6 | 7 | 8 | profile { 9 | master_id: "STREAM" 10 | delay { 11 | time : "0s" 12 | } 13 | 14 | name: "ROOT" 15 | wait_for: "ROOT ACTIVATION" 16 | } 17 | 18 | profile { 19 | type: READ 20 | master_id: "STREAM" 21 | fifo { 22 | start_fifo_level: FULL 23 | full_level: 256 24 | ot_limit: 4 25 | total_txn: 10 26 | rate: "100 MBps" 27 | } 28 | pattern { 29 | address { 30 | base: 0 31 | increment:64 32 | } 33 | size: 64 34 | 35 | } 36 | name: "STREAM_NODE1" 37 | wait_for: "ROOT" 38 | } 39 | 40 | profile { 41 | type: READ 42 | master_id: "STREAM" 43 | fifo { 44 | start_fifo_level: FULL 45 | full_level: 256 46 | ot_limit: 4 47 | total_txn: 10 48 | rate: "100 MBps" 49 | } 50 | pattern { 51 | address { 52 | base: 0 53 | increment:64 54 | } 55 | size: 64 56 | 57 | } 58 | name: "STREAM_NODE2" 59 | wait_for: "ROOT" 60 | } 61 | 62 | profile { 63 | type: READ 64 | master_id: "STREAM" 65 | fifo { 66 | start_fifo_level: FULL 67 | full_level: 256 68 | ot_limit: 4 69 | total_txn: 10 70 | rate: "100 MBps" 71 | } 72 | pattern { 73 | address { 74 | base: 0 75 | increment:64 76 | } 77 | size: 64 78 | 79 | } 80 | name: "STREAM_NODE3" 81 | wait_for: "ROOT" 82 | } 83 | 84 | profile { 85 | type: READ 86 | master_id: "STREAM" 87 | fifo { 88 | start_fifo_level: FULL 89 | full_level: 256 90 | ot_limit: 4 91 | total_txn: 10 92 | rate: "100 MBps" 93 | } 94 | pattern { 95 | address { 96 | base: 0 97 | increment:64 98 | } 99 | size: 64 100 | 101 | } 102 | name: "STREAM_LAYER1_NODE1" 103 | wait_for: "STREAM_NODE1" 104 | } 105 | 106 | profile { 107 | type: READ 108 | master_id: "STREAM" 109 | fifo { 110 | start_fifo_level: FULL 111 | full_level: 256 112 | ot_limit: 4 113 | total_txn: 10 114 | rate: "100 MBps" 115 | } 116 | pattern { 117 | address { 118 | base: 0 119 | increment:64 120 | } 121 | size: 64 122 | 123 | } 124 | name: "STREAM_LAYER1_NODE2" 125 | wait_for: "STREAM_NODE2" 126 | } 127 | -------------------------------------------------------------------------------- /event.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * 7 | * Created on: 22 Jan 2016 8 | * Author: Matteo Andreozzi 9 | */ 10 | 11 | #include "event.hh" 12 | #include "logger.hh" 13 | #include 14 | 15 | namespace TrafficProfiles { 16 | 17 | // default event configuration separator 18 | const string Event::separator = " "; 19 | 20 | const string Event::text[]= { 21 | [NONE] = "NONE", 22 | [ACTIVATION] = "ACTIVATION", 23 | [TERMINATION] ="TERMINATION", 24 | [FIFO_EMPTY] = "FIFO_EMPTY", 25 | [FIFO_FULL] = "FIFO_FULL", 26 | [FIFO_NOT_EMPTY] = "FIFO_NOT_EMPTY", 27 | [FIFO_NOT_FULL] = "FIFO_NOT_FULL", 28 | [PROFILE_LOCKED] = "PROFILE_LOCKED", 29 | [PROFILE_UNLOCKED] = "PROFILE_UNLOCKED", 30 | [PACKET_REQUEST_RETRY] = "PACKET_REQUEST_RETRY", 31 | [TICK] = "TICK" 32 | }; 33 | 34 | const Event::Category Event::category[] = { 35 | [NONE] = NO_CATEGORY, 36 | [ACTIVATION] = PROFILE, 37 | [TERMINATION] = PROFILE, 38 | [FIFO_EMPTY] = FIFO_LEVEL, 39 | [FIFO_FULL] = FIFO_LEVEL, 40 | [FIFO_NOT_EMPTY] = FIFO_LEVEL, 41 | [FIFO_NOT_FULL] = FIFO_LEVEL, 42 | [PROFILE_LOCKED] = SEND_STATUS, 43 | [PROFILE_UNLOCKED] = SEND_STATUS, 44 | [PACKET_REQUEST_RETRY] = PACKET, 45 | [TICK] = CLOCK 46 | }; 47 | 48 | const bool Event::allowConcurrency[] = { 49 | [NO_CATEGORY] = true, 50 | [PROFILE] = true, 51 | [FIFO_LEVEL] = false, 52 | [SEND_STATUS] = false, 53 | [PACKET] = true, 54 | [CLOCK] = false 55 | }; 56 | 57 | 58 | Event::Event(const Type ty, const Action a, 59 | const uint64_t eId, const uint64_t t): 60 | type(ty), action(a), id(eId), time(t) { 61 | } 62 | 63 | bool 64 | Event::parse(Type& t, string& profile, const string& in) { 65 | 66 | bool ok = false; 67 | 68 | size_t pos = in.find_first_of(separator); 69 | // try to extract Profile name, even from 70 | // a full string in case the separator is 71 | // not present 72 | profile = in.substr(0, pos); 73 | 74 | // if the separator is present 75 | // try to extract the type 76 | if (pos != string::npos) { 77 | string typeStr = in.substr(pos+1,string::npos); 78 | for (uint64_t i=0; i 14 | #include 15 | 16 | using namespace std; 17 | 18 | namespace TrafficProfiles { 19 | /*! 20 | *\brief AMBA Traffic Profile Event 21 | * 22 | * An ATP Event can be triggered by a Profile and 23 | * is propagated by the ATP Manager to all other 24 | * Profiles subscribed to it 25 | */ 26 | class Event { 27 | private: 28 | //! Event configuration string separator 29 | static const string separator; 30 | 31 | public: 32 | 33 | /*! ATP Event Categories by which 34 | * Events are grouped 35 | */ 36 | enum Category { 37 | NO_CATEGORY = 0, 38 | PROFILE = 1, 39 | FIFO_LEVEL = 2, 40 | SEND_STATUS = 3, 41 | PACKET = 4, 42 | CLOCK = 5, 43 | N_CATEGORIES = 6 44 | }; 45 | 46 | /*! 47 | * Event Type 48 | * NONE: an empty event 49 | * ACTIVATION: a profile is active for the first time 50 | * TERMINATION : a profile has issued all its transactions 51 | * FIFO_EMPTY : a profile FIFO has become empty 52 | * FIFO_FULL : a profile FIFO has become full 53 | * FIFO_NOT_EMPTY : a FIFO becomes non empty after being empty 54 | * FIFO_NOT_FULL : a FIFO becomes non full after being full 55 | * PROFILE_LOCKED : a profile is unable to send data 56 | * PROFILE_UNLOCKED: a profile is able to send data after being unable 57 | * PACKET_REQUEST_RETRY: a rejected request is due to be retried 58 | * TICK: special clock event, triggers TPM tick 59 | */ 60 | const enum Type { 61 | NONE = 0, 62 | ACTIVATION = 1, 63 | TERMINATION = 2, 64 | FIFO_EMPTY = 3, 65 | FIFO_FULL = 4, 66 | FIFO_NOT_EMPTY = 5, 67 | FIFO_NOT_FULL = 6, 68 | PROFILE_LOCKED = 7, 69 | PROFILE_UNLOCKED = 8, 70 | PACKET_REQUEST_RETRY = 9, 71 | TICK = 10, 72 | N_EVENTS = 11 73 | } type; 74 | 75 | /*! 76 | * Action Type 77 | * AWAITED = event waited for 78 | * TRIGGERED = event occurred 79 | */ 80 | const enum Action { 81 | AWAITED = 0, 82 | TRIGGERED = 1 83 | } action; 84 | 85 | /*! 86 | * Event type to category map 87 | */ 88 | static const Category category[]; 89 | 90 | /*! 91 | * Event type to string name map 92 | */ 93 | static const string text[]; 94 | 95 | /*! 96 | * Event category to allow concurrency flag map 97 | */ 98 | static const bool allowConcurrency[]; 99 | 100 | /*! 101 | * Unique ID 102 | */ 103 | const uint64_t id; 104 | 105 | /*! 106 | * Event time 107 | */ 108 | const uint64_t time; 109 | 110 | public: 111 | 112 | /*! 113 | * Parses a string into Event Type and Profile name 114 | *\param t returned Event Type 115 | *\param profile returned Profile name 116 | *\param in input string 117 | *\return true if both type and id are successfully 118 | * parsed, false otherwise 119 | */ 120 | static bool parse(Type&, string&, const string&); 121 | 122 | /*! 123 | * Event Constructor 124 | *\param ty the type of the Event 125 | *\param a the Event action 126 | *\param eId this event ID 127 | *\param t Event time 128 | */ 129 | Event(const Type, const Action, const uint64_t, const uint64_t); 130 | 131 | //! Default destructor 132 | virtual ~Event(); 133 | 134 | /*! 135 | * Equality operator 136 | *\param ev1 the first Event to be compared 137 | *\param ev2 the second Event to be compared 138 | *\return true if the events compare equal 139 | */ 140 | inline friend bool operator==(const Event& ev1, const Event& ev2) { 141 | return (ev1.type == ev2.type && ev1.id == ev2.id); 142 | } 143 | 144 | /*! 145 | * Inequality operator 146 | *\param ev1 the first Event to be compared 147 | *\param ev2 the second Event to be compared 148 | *\return true if the events compare equal 149 | */ 150 | inline friend bool operator!=(const Event& ev1, const Event& ev2) { 151 | return (ev1.type != ev2.type || ev1.id != ev2.id); 152 | } 153 | 154 | /*! 155 | * Ostream operator 156 | *\param os the ostream where to output the event 157 | *\param ev the event to be output to ostream 158 | *\return reference to the modified ostream 159 | */ 160 | friend ostream& operator<<(ostream& os, const Event& ev); 161 | }; 162 | 163 | } /* namespace TrafficProfiles */ 164 | 165 | //! the C++ standard template library namespace 166 | namespace std { 167 | /*!\brief ATP Event Hash function 168 | * 169 | * Computes the hash value of an ATP event 170 | */ 171 | template<> 172 | struct hash { 173 | size_t operator()(const TrafficProfiles::Event& object) const { 174 | return hash()((object.type + 1) * object.id); 175 | } 176 | }; 177 | } 178 | 179 | #endif /* __AMBA_TRAFFIC_PROFILE_EVENT_HH__ */ 180 | -------------------------------------------------------------------------------- /event_manager.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 30 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #include "event_manager.hh" 11 | #include "traffic_profile_manager.hh" 12 | #include "logger.hh" 13 | 14 | namespace TrafficProfiles { 15 | 16 | EventManager::EventManager(const uint64_t id, 17 | TrafficProfileManager* const manager): 18 | eventId(id), tpm(manager) { 19 | sent.fill(make_pair(Event::NONE, 0)); 20 | waitedCount.fill(0); 21 | } 22 | 23 | EventManager::EventManager():EventManager(0, nullptr) { 24 | 25 | } 26 | 27 | EventManager::~EventManager() { 28 | } 29 | 30 | void 31 | EventManager::reset() { 32 | LOG("EventManager::reset this id " 33 | "[", eventId, "] reset requested"); 34 | waited.clear(); 35 | waitedCount.fill(0); 36 | sent.fill(make_pair(Event::NONE, 0)); 37 | 38 | for (const auto& e: retainedEvents) { 39 | LOG("EventManager::reset this id " 40 | "[", eventId, "] restoring event", e); 41 | waitEvent(e.type, e.id); 42 | } 43 | } 44 | 45 | void 46 | EventManager::waitEvent(const Event::Type type, 47 | const uint64_t id, const bool retain) { 48 | if (type!=Event::NONE) { 49 | Event ev(type, Event::AWAITED, id, tpm->getTime()); 50 | waited[ev.id].insert(ev); 51 | waitedCount[Event::category[type]]++; 52 | if (tpm) tpm->subscribe(eventId, ev); 53 | if (retain) retainedEvents.push_back(ev); 54 | LOG("EventManager::waitEvent this id " 55 | "[", eventId, "] waiting for",ev, 56 | retain?"- event will be retained upon reset":""); 57 | } 58 | } 59 | 60 | void EventManager::emitEvent(const Event::Type type) { 61 | 62 | if (type!=Event::NONE && tpm) { 63 | // lookup category for the event type requested 64 | Event::Category cat = Event::category[type]; 65 | 66 | // if the last sent event for its category is not 67 | // the requested one, and if either event concurrency 68 | // for this category is allowed or the last sent event 69 | // was not sent at this current time, then send it 70 | 71 | auto& sentCat = sent[cat]; 72 | 73 | if ((sentCat.first == Event::NONE) || 74 | (sentCat.first != type && ( 75 | (sentCat.second < tpm->getTime()) || 76 | Event::allowConcurrency[cat]))) { 77 | sentCat = make_pair(type,tpm->getTime()); 78 | Event ev (type, Event::TRIGGERED, eventId, tpm->getTime()); 79 | LOG("EventManager::emitEvent this id [", eventId, "] sent event",ev); 80 | tpm->event(ev); 81 | } else { 82 | LOG("EventManager::emitEvent this id [", eventId, "] " 83 | "not sent event of type", Event::text[type], 84 | "due to last sent", Event::text[sentCat.first], 85 | "at time",sentCat.second); 86 | } 87 | } 88 | } 89 | 90 | bool 91 | EventManager::receiveEvent(const Event& ev) { 92 | bool ok = false; 93 | 94 | if (ev.action!=Event::TRIGGERED) { 95 | ERROR("EventManager::receiveEvent this id [", 96 | eventId 97 | ,"] action is not TRIGGERED", ev); 98 | } 99 | 100 | if ((waited.find(ev.id)!=waited.end()) && 101 | (waited.at(ev.id).find(ev)!=waited.at(ev.id).end())) { 102 | 103 | waited[ev.id].erase(ev); 104 | waitedCount[Event::category[ev.type]]--; 105 | if (waited[ev.id].empty()) { 106 | waited.erase(ev.id); 107 | } 108 | 109 | ok=true; 110 | LOG("EventManager::receiveEvent this id [", eventId, "] event",ev, 111 | "received"); 112 | } 113 | 114 | // special handling for TERMINATION events 115 | if (ev.type==Event::TERMINATION) { 116 | // release any event this profile might be still waiting 117 | // for related to the terminated event 118 | if (waited.count(ev.id) > 0) { 119 | for (auto& e:waited[ev.id]) { 120 | waitedCount[Event::category[e.type]]--; 121 | } 122 | waited.erase(ev.id); 123 | LOG("EventManager::receiveEvent this id [", eventId, "] event",ev, 124 | "removed all waited events for id", ev.id); 125 | } 126 | 127 | } 128 | 129 | return ok; 130 | } 131 | 132 | } /* namespace TrafficProfiles */ 133 | -------------------------------------------------------------------------------- /event_manager.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 30 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef __AMBA_TRAFFIC_PROFILE_EVENT_MANAGER_HH__ 11 | #define __AMBA_TRAFFIC_PROFILE_EVENT_MANAGER_HH__ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "event.hh" 19 | 20 | using namespace std; 21 | 22 | namespace TrafficProfiles { 23 | 24 | class TrafficProfileManager; 25 | 26 | /*! 27 | *\brief ATP Event Manager 28 | * 29 | * An ATP Event Manager object supports generation and 30 | * reception of ATP Events. 31 | */ 32 | class EventManager { 33 | 34 | protected: 35 | 36 | /*! 37 | * ID of the generated events 38 | */ 39 | uint64_t eventId; 40 | 41 | /*! 42 | * Pointer to the TPM 43 | */ 44 | TrafficProfileManager* tpm; 45 | 46 | /*! 47 | * Last sent event and time per Category 48 | */ 49 | array, Event::N_CATEGORIES> sent; 50 | 51 | /*! 52 | * Map: event ID, Events waited for with 53 | * that ID 54 | */ 55 | map> waited; 56 | 57 | /*! 58 | * Number of events waited for per category 59 | */ 60 | array waitedCount; 61 | 62 | /*! 63 | *\brief list of events to be retained upon reset 64 | * 65 | * This list is populated with events on a wait invoked 66 | * with the retain flag set 67 | * Upon reset, this list is parsed and the events contained 68 | * in it are waited for. 69 | */ 70 | list retainedEvents; 71 | 72 | public: 73 | /*! 74 | * Default constructor 75 | */ 76 | EventManager(); 77 | 78 | /*! 79 | * Constructor 80 | *\param id ID of the generated events 81 | *\param manager pointer to the TPM 82 | */ 83 | EventManager(const uint64_t, TrafficProfileManager* const); 84 | 85 | //! Default Destructor 86 | virtual ~EventManager(); 87 | 88 | /*! 89 | *\brief reset support 90 | * 91 | * restores the EventManager 92 | * to its initial state, and 93 | * reinstates retained events 94 | */ 95 | virtual void reset(); 96 | 97 | /*! 98 | * Set the ID with which events will be emitted 99 | *\param id event id to be set 100 | */ 101 | inline void setEventId(const uint64_t id) { 102 | eventId = id; 103 | } 104 | ; 105 | 106 | /*! 107 | * Set the TPM to which events will be emitted 108 | * and registered 109 | *\param manager pointer to the TPM 110 | */ 111 | inline void setTpm(TrafficProfileManager * const manager) { 112 | tpm = manager; 113 | } 114 | ; 115 | 116 | /*! 117 | * Waits for an event 118 | *\param type waited for event type 119 | *\param id waited for event id 120 | *\param retain flag - optional - indicates that 121 | * the wait shall be restored upon a reset 122 | */ 123 | virtual void waitEvent(const Event::Type, 124 | const uint64_t, const bool=false); 125 | 126 | /*! 127 | * Receives an event 128 | *\param ev event to be received 129 | *\return true if the event was waited for 130 | */ 131 | virtual bool receiveEvent(const Event&); 132 | 133 | /*! 134 | * Returns a constant reference to the waited events set 135 | *\return constant reference to waited events set 136 | */ 137 | virtual const map>& 138 | getWaited() const {return waited;} 139 | 140 | /*! 141 | * Builds and sends an event 142 | *\param type of the event to be sent 143 | */ 144 | void emitEvent(const Event::Type); 145 | 146 | /*! 147 | * Returns if the EventManager is waiting 148 | * for events 149 | *\return true if waiting for any events 150 | */ 151 | inline bool waiting() const { 152 | return !waited.empty(); 153 | } 154 | 155 | /*! 156 | * Returns how many events per category are waited for 157 | *\param c Event Category 158 | *\return the number of events waited for of the specified 159 | * category 160 | */ 161 | inline uint64_t getWaitedCount(const Event::Category c) { 162 | return waitedCount[c]; 163 | } 164 | }; 165 | 166 | } /* namespace TrafficProfiles */ 167 | 168 | #endif /* __AMBA_TRAFFIC_PROFILE_EVENT_MANAGER_HH__ */ 169 | -------------------------------------------------------------------------------- /gem5/ATPDevice.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2019-2020 ARM Limited 4 | # All rights reserved. 5 | # Authors: Adrian Herrera 6 | 7 | from m5.objects.RealView import AmbaDmaDevice 8 | from m5.params import Param 9 | from m5.proxy import Parent 10 | from m5.util.fdthelper import FdtPropertyStrings 11 | 12 | class ATPDevice(AmbaDmaDevice): 13 | """AMBA ATP generic device""" 14 | 15 | type = 'ATPDevice' 16 | cxx_header = "gem5/atp_device.hh" 17 | cxx_class = 'ATP::Device' 18 | 19 | _node_name = "atpdevice" 20 | _pio_size = 0x1000 21 | 22 | adapter = Param.ProfileGen(Parent.any, "Reference to the ATP Adapter") 23 | atp_id = Param.String("ATP device ID, same as in .atp files") 24 | amba_id = 0x0 25 | 26 | def generateDeviceTree(self, state): 27 | node = self.generateBasicPioDeviceNode(state, self._node_name, 28 | self.pio_addr, self._pio_size, 29 | [ self.interrupt ]) 30 | node.appendCompatible("arm,{}".format(self._node_name)) 31 | self.addIommuProperty(state, node) 32 | node.append(FdtPropertyStrings("atp-id", [ self.atp_id ])) 33 | 34 | yield node 35 | -------------------------------------------------------------------------------- /gem5/ProfileGen.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2012 ARM Limited 4 | # All rights reserved. 5 | # Authors: Matteo Andreozzi 6 | 7 | from m5.params import * 8 | from m5.proxy import * 9 | from m5.util.pybind import PyBindMethod 10 | from m5.SimObject import SimObject 11 | 12 | #ATP GEM5 adaptor SimObject 13 | 14 | class ProfileGen(SimObject): 15 | type = 'ProfileGen' 16 | cxx_header = "gem5/profile_gen.hh" 17 | cxx_exports = [ PyBindMethod('initStream') ] 18 | 19 | # Vector Port used for sending ATP requests and receiving responses 20 | port = VectorMasterPort("Vector of ATP Masters ports") 21 | 22 | # System used to determine the mode of the memory system 23 | system = Param.System(Parent.any, "System this generator is part of") 24 | 25 | #AMBA traffic protocol file 26 | config_files = VectorParam.String("ATP configuration files") 27 | # flag to enable ATP exit the simulation when all profiles have depleted their packets 28 | exit_when_done = Param.Bool(True, "Exit the simulation when all profiles have depleted their packets") 29 | 30 | # flag to enable ATP exit the simulation when at least one master depletes its packets 31 | exit_when_one_master_ends = Param.Bool(False, "Exit the simulation when at least one master terminates") 32 | 33 | # flag to enable tracing the generated time/addresses pattern and relative file name 34 | trace_atp = Param.Bool(False, "Enables the tracing of ATP generated packets in time") 35 | 36 | trace_gem = Param.Bool(False, "Enables the tracing of GEM5 generated packets in time") 37 | trace_gem_file = Param.String("gem5.trace", "File where to trace GEM5 generated packets in time") 38 | 39 | trace_m3i = Param.Bool(False, "Enables the tracing of ATP masters in M3I format") 40 | trace_m3i_bus = Param.Int(16, "BUS width in bytes used to generate the ATP master M3I traces") 41 | 42 | # flag to enable/disable error on suppressed out-of-range addresses 43 | out_of_range_addresses = Param.Bool(False, "Allows out of range addresses to be generated by ATP Engine") 44 | # flag to enable/disable debug mode to create one master per configured profile 45 | profiles_as_masters = Param.Bool(False, "Enables the creation of one master per configured profile (debug mode)") 46 | # flag to enable/disable ATP tracker latency 47 | tracker_latency = Param.Bool(False, "Enables the ATP tracker latency") 48 | core_engine_debug = Param.Bool(False, "Enables ATP Engine debug mode") 49 | init_only = Param.Bool(False, "Initialises ATP Engine but does not trigger an update immediately after") 50 | disable_watchdog = Param.Bool(False, "Disables ProfileGen watchdog") 51 | disable_mem_check = Param.Bool(False, "Disables check for ATP Engine valid physical memory addresses") 52 | 53 | def __init__(self, **kwargs): 54 | super(ProfileGen, self).__init__(**kwargs) 55 | self._streams = [] 56 | 57 | def initStream(self, master, rootp, rbase=MaxAddr, rrange=MaxAddr, 58 | wbase=MaxAddr, wrange=MaxAddr, task_id=1024): 59 | self._streams.append((master, rootp, rbase, rrange, 60 | wbase, wrange, task_id)) 61 | 62 | def init(self): 63 | self.getCCObject().init() 64 | for stream in self._streams: 65 | self.getCCObject().initStream(*stream) 66 | -------------------------------------------------------------------------------- /gem5/SConscript: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | 3 | # SPDX-License-Identifier: BSD-3-Clause-Clear 4 | # 5 | # Copyright (c) 2012 ARM Limited 6 | # All rights reserved. 7 | # Authors: Matteo Andreozzi 8 | 9 | Import('*') 10 | 11 | # Only build the traffic generator if we have support for protobuf as the 12 | # tracing relies on it 13 | if env['CONF']['HAVE_PROTOBUF']: 14 | SimObject('ProfileGen.py', sim_objects=['ProfileGen']) 15 | SimObject('ATPDevice.py', sim_objects=['ATPDevice']) 16 | Source('profile_gen.cc') 17 | Source('atp_device.cc') 18 | DebugFlag('ATP') 19 | -------------------------------------------------------------------------------- /gem5/atp_device.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_DEVICE_HH__ 10 | #define __ATP_DEVICE_HH__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "base/addr_range.hh" 20 | #include "base/types.hh" 21 | #include "dev/arm/amba_device.hh" 22 | #include "mem/packet.hh" 23 | #include "params/ATPDevice.hh" 24 | #include "sim/eventq.hh" 25 | 26 | class ProfileGen; 27 | 28 | namespace ATP { 29 | 30 | //! AMBA Adaptive Traffic Profiles (ATP) device 31 | /*! 32 | * Generic ATP device. Provides MMIO programmability and ATP APIs 33 | * access from system software. 34 | */ 35 | class Device : public gem5::AmbaDmaDevice { 36 | public: 37 | PARAMS(gem5::ATPDevice); 38 | Device(const Params &p); 39 | 40 | protected: 41 | //! MMIO registers offsets 42 | enum Offset : gem5::Addr { 43 | //! Stream name address base 44 | STREAM_NAME_BASE = 0x00, 45 | //! Stream name address range 46 | STREAM_NAME_RANGE = 0x08, 47 | //! Read DMA buffer address base 48 | READ_BASE = 0x10, 49 | //! Read DMA buffer address range 50 | READ_RANGE = 0x18, 51 | //! Write DMA buffer address base 52 | WRITE_BASE = 0x20, 53 | //! Write DMA buffer address range 54 | WRITE_RANGE = 0x28, 55 | //! Stream ID for Play Stream API 56 | STREAM_ID = 0x30, 57 | //! Task ID, uniquely identifies dataflow 58 | TASK_ID = 0x38, 59 | //! Request ID of incoming request 60 | IN_REQUEST_ID = 0x3c, 61 | //! Request ID of served request 62 | OUT_REQUEST_ID = 0x40, 63 | //! Control register 64 | /*! 65 | * CONTROL[1:0]: DMA operation type 66 | * 0b00: READ / 0b01: WRITE / 0b11: RDWR 67 | * CONTROL[3:2]: Action 68 | * 0b01: Play Stream 69 | * 0b10: Acknowledge interrupt 70 | * 0b11: Unique Stream 71 | */ 72 | CONTROL = 0x44, 73 | //! Status register 74 | /*! Polled for served requests */ 75 | STATUS = 0x45 76 | }; 77 | 78 | //! MMIO registers 79 | struct Registers { 80 | uint64_t streamNameBase, streamNameRange, readBase, readRange, 81 | writeBase, writeRange, streamId; 82 | uint32_t taskId, inRequestId, outRequestId; 83 | std::bitset<8> control; 84 | uint8_t status; 85 | 86 | static const std::unordered_map names; 87 | 88 | void readOnly(const gem5::Addr addr) const; 89 | void writeOnly(const gem5::Addr addr) const; 90 | void invalidSize(const gem5::Addr addr, const unsigned size) const; 91 | void unexpectedAddr(const gem5::Addr addr) const; 92 | } regs; 93 | 94 | //! Play Stream API request 95 | enum DmaOperation : unsigned char { READ, WRITE, RDWR }; 96 | struct Request { 97 | const uint64_t readBase, readRange, writeBase, writeRange; 98 | const uint32_t id, taskId; 99 | const DmaOperation dmaOp; 100 | }; 101 | 102 | //! Stream descriptor 103 | struct Stream { 104 | bool active{ false }; 105 | std::queue pendingRequests; 106 | }; 107 | 108 | //! Reference to the ATP Adapter 109 | ProfileGen *adapter; 110 | //! ATP Device ID, same as in .atp files 111 | const std::string atpId; 112 | //! IOMMU stream ID for request annotation 113 | const uint32_t sid; 114 | //! IOMMU substream ID for request annotation 115 | const uint32_t ssid; 116 | 117 | //! Stream name read DMA operation completion event 118 | gem5::EventFunctionWrapper streamNameRead; 119 | //! Stream name storage buffer 120 | std::vector streamNameBuffer; 121 | 122 | //! Stream -> Active status and pending requests 123 | std::unordered_map streams; 124 | 125 | //! Served requests to notify 126 | std::queue servedRequests; 127 | //! True if interrupt acknowledgement is pending 128 | bool intAckPending{ false }; 129 | 130 | //! Provides device address ranges 131 | gem5::AddrRangeList getAddrRanges() const override; 132 | //! MMIO read handler 133 | gem5::Tick read(gem5::PacketPtr pkt) override; 134 | //! MMIO write handler 135 | gem5::Tick write(gem5::PacketPtr pkt) override; 136 | 137 | //! Play Stream API handler 138 | /*! Builds a new request. If no pending requests, serves it */ 139 | void playStreamHandler(void); 140 | //! Extracts DMA operation from CONTROL 141 | DmaOperation extractDmaOp(void) const; 142 | //! Triggers DMA configuration and activates the stream through adapter 143 | void serveRequest(const uint64_t str_id, const Request &req); 144 | //! Configures stream DMA operation paramaters through adapter 145 | void configureDmaOp(const uint64_t str_id, const Request &req); 146 | //! Callback for when stream completes and associated request is served 147 | /*! If possible, notifies the served request and serves the next pending */ 148 | void servedRequestHandler(const uint64_t str_id, const uint32_t req_id); 149 | //! Callback for when a request is issued from the adapter 150 | /*! Annotates IOMMU IDs and request task ID */ 151 | void annotateRequest(gem5::RequestPtr req, const uint32_t task_id); 152 | 153 | //! Interrupt acknowledgment handler 154 | /*! Clears interrupt and if possible notifies next served request */ 155 | void intAckHandler(void); 156 | //! Publishes served request in OUT_REQUEST_ID and sends interrupt 157 | void notifyServedRequest(const uint32_t req_id); 158 | 159 | //! Unique Stream API handler 160 | /*! Initialises DMA operation to read the stream name */ 161 | void uniqueStreamHandler(void); 162 | //! Stream name read DMA operation completion handler 163 | /*! 164 | * Calls uniqueStream, publishes stream id and notifies system software 165 | * through STATUS 166 | */ 167 | void streamNameHandler(void); 168 | }; 169 | 170 | } // namespace ATP 171 | 172 | #endif /* __ATP_DEVICE_HH__ */ 173 | -------------------------------------------------------------------------------- /gem5/baremetal_atp.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause-Clear 2 | # 3 | # Copyright (c) 2020 ARM Limited 4 | # All rights reserved. 5 | # Authors: Adrian Herrera 6 | 7 | """ 8 | Official script for use with meta-atp Yocto layer 9 | """ 10 | 11 | from m5 import options 12 | from m5.objects import * 13 | from m5.util import addToPath 14 | from argparse import ArgumentParser 15 | from os import getenv 16 | from pathlib import Path 17 | from tempfile import NamedTemporaryFile 18 | 19 | gem5_datadir = Path(getenv("GEM5_DATADIR")) 20 | gem5_configs_dir = gem5_datadir / "configs" 21 | atp_datadir = Path(getenv("ATP_DATADIR")) 22 | atp_configs_dir = atp_datadir / "configs" 23 | outdir = Path(options.outdir) 24 | 25 | addToPath(gem5_configs_dir) 26 | 27 | from common import (Benchmarks, CacheConfig, FSConfig, MemConfig, Options, 28 | Simulation) 29 | 30 | def connect_adapter(adapter, smmu): 31 | """Helper function to connect the adapter port to the SMMU""" 32 | interface = SMMUv3DeviceInterface() 33 | adapter.port = interface.device_port 34 | smmu.device_interfaces.append(interface) 35 | 36 | def create_cow_image(name): 37 | """Helper function to create a Copy-on-Write disk image""" 38 | image = CowDiskImage() 39 | image.child.image_file = name 40 | return image 41 | 42 | def create(args): 43 | # System 44 | CpuClass, mem_mode, _ = Simulation.setCPUClass(args) 45 | sys_cfg = Benchmarks.SysConfig(args.script, args.mem_size) 46 | system = FSConfig.makeArmSystem(mem_mode, "VExpress_GEM5_V2", 47 | args.num_cpus, sys_cfg, bare_metal=True) 48 | system.voltage_domain = VoltageDomain(voltage=args.sys_voltage) 49 | system.clk_domain = SrcClockDomain(clock=args.sys_clock, 50 | voltage_domain=system.voltage_domain) 51 | system.workload.object_file = args.kernel 52 | # CPU cluster 53 | system.cpu_voltage_domain = VoltageDomain() 54 | system.cpu_clk_domain = SrcClockDomain(clock=args.cpu_clock, 55 | voltage_domain=system.cpu_voltage_domain) 56 | system.cpu = [CpuClass(clk_domain=system.cpu_clk_domain, cpu_id=i) 57 | for i in range(args.num_cpus)] 58 | for cpu in system.cpu: 59 | cpu.createThreads() 60 | CacheConfig.config_cache(args, system) 61 | # Devices 62 | system.realview.atp_adapter = ProfileGen(config_files=args.atp_file, 63 | exit_when_done=False, 64 | init_only=True, 65 | disable_watchdog=True, 66 | disable_mem_check=True) 67 | system.realview.atp_device = ATPDevice(pio_addr=0x2b500000, 68 | interrupt=ArmSPI(num=104), 69 | atp_id="STREAM") 70 | system.realview.attachSmmu([system.realview.atp_device], system.membus) 71 | # Enable SMMUv3 interrupt interface to boot Linux 72 | system.realview.smmu.irq_interface_enable = True 73 | connect_adapter(system.realview.atp_adapter, system.realview.smmu) 74 | if args.disk_image: 75 | system.disk = [PciVirtIO(vio=VirtIOBlock(image=create_cow_image(disk))) 76 | for disk in args.disk_image] 77 | for disk in system.disk: 78 | system.realview.attachPciDevice(disk, system.iobus) 79 | # Memory 80 | MemConfig.config_mem(args, system) 81 | 82 | return system 83 | 84 | def main(): 85 | parser = ArgumentParser(epilog=__doc__) 86 | Options.addCommonOptions(parser) 87 | Options.addFSOptions(parser) 88 | parser.add_argument("--atp-file", action="append", type=str, 89 | default=[str(atp_configs_dir / "stream.atp")], 90 | help=".atp file to load in Engine") 91 | parser.add_argument("--dtb-gen", action="store_true", 92 | help="Doesn't run simulation, it generates a DTB only") 93 | parser.add_argument("--checkpoint", action="store_true") 94 | args = parser.parse_args() 95 | 96 | if args.checkpoint: 97 | script = NamedTemporaryFile() 98 | script.write(b"#!/bin/sh\nm5 checkpoint && m5 readfile | sh\n") 99 | script.flush() 100 | args.script = script.name 101 | args.max_checkpoints = 1 102 | 103 | system = create(args) 104 | root = Root(full_system=True, system=system) 105 | 106 | if args.dtb_gen: 107 | # No run, autogenerate DTB and exit 108 | system.generateDtb(str(outdir / "system.dtb")) 109 | else: 110 | Simulation.run(args, root, system, None) 111 | 112 | if __name__ == "__m5_main__": 113 | main() 114 | -------------------------------------------------------------------------------- /images/programmability/address_reg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Address
Address
0
0
63
63
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /images/programmability/id_32_reg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Identifier
Identifier
0
0
31
31
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /images/programmability/id_64_reg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Identifier
Identifier
0
0
63
63
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /images/programmability/range_reg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Range (bytes)
Range (bytes)
0
0
63
63
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /images/programmability/status_reg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
0
0
8
8
Value
Value
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /kronos.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 1, 2016 7 | * Author: Matteo Andreozzi 8 | * 9 | */ 10 | 11 | #include 12 | #include "kronos.hh" 13 | #include "traffic_profile_manager.hh" 14 | #include "logger.hh" 15 | 16 | namespace TrafficProfiles { 17 | 18 | Kronos::Kronos(TrafficProfileManager* const t) : 19 | tpm(t), bucketWidth(0), epoch(0), bucket(0), 20 | counter(0), initialized(false) { 21 | } 22 | 23 | void Kronos::init() { 24 | 25 | bucketWidth = tpm->getKronosConfiguration().first; 26 | 27 | calendar.resize(tpm->getKronosConfiguration().second / bucketWidth); 28 | 29 | initialized = true; 30 | 31 | LOG("Kronos initialised with bucket size", 32 | bucketWidth, "calendar buckets", 33 | calendar.size()); 34 | } 35 | 36 | Kronos::~Kronos() { 37 | } 38 | 39 | void Kronos::schedule(const Event ev) { 40 | 41 | if (initialized) { 42 | // compute epoch and bucket 43 | const uint64_t quantum = ev.time / bucketWidth; 44 | const uint64_t bucket = quantum % calendar.size(); 45 | 46 | // add to the calendar queue 47 | auto& l = calendar[bucket]; 48 | if (!l.empty()) { 49 | auto pos = begin(l); 50 | // search for position where to insert element; 51 | while (pos->time < ev.time && pos != end(l)) 52 | pos++; 53 | l.insert(pos, ev); 54 | } else { 55 | // insertion in empty list 56 | l.push_back(ev); 57 | } 58 | 59 | // update counter 60 | ++counter; 61 | 62 | LOG("Kronos::schedule event", ev, "epoch", 63 | quantum / calendar.size(), 64 | "bucket", bucket, 65 | "bucket size", calendar[bucket].size(), 66 | "total events", 67 | counter); 68 | } else { 69 | ERROR("Kronos::schedule Kronos uninitialized"); 70 | } 71 | } 72 | 73 | void Kronos::get(list& q) { 74 | if (initialized) { 75 | // access current time 76 | const uint64_t& time = tpm->getTime(); 77 | const uint64_t quantum = time / bucketWidth; 78 | // Lookup epoch and bucket for new TPM time 79 | const uint64_t target_epoch = quantum / calendar.size(); 80 | const uint64_t target_bucket = quantum % calendar.size(); 81 | // detect epoch change 82 | LOG("Kronos::get time", time, "current epoch", 83 | epoch, "current bucket", 84 | bucket, "target epoch", 85 | target_epoch, "target bucket", 86 | target_bucket); 87 | 88 | // access corresponding calendar bucket an 89 | // retrieve all events matching current epoch 90 | // the signed integer conversion handles wrap around 91 | int64_t distance = target_bucket - bucket; 92 | const uint64_t stop = (bucket + (distance > 0 ? distance : 93 | (calendar.size()-distance))); 94 | 95 | LOG("Kronos::get searching from", bucket, 96 | "to", stop%calendar.size(), "(", stop, 97 | ") distance:", distance); 98 | 99 | for (uint64_t i = bucket; i <= stop; ++i) { 100 | const uint64_t b = i % calendar.size(); 101 | auto& events = calendar[b]; 102 | while (!events.empty() && events.front().time <= time) { 103 | LOG("Kronos::get match found:", events.front(), 104 | "in bucket",b); 105 | q.push_back(events.front()); 106 | events.pop_front(); 107 | // update the event counter 108 | if (counter > 0) { 109 | --counter; 110 | } else { 111 | ERROR("Kronos::schedule event counter in inconsistent state"); 112 | } 113 | } 114 | } 115 | LOG("Kronos::get found", q.size(), "events triggered at time", time, 116 | "still active events", counter); 117 | // update current epoch and bucket 118 | uint64_t new_epoch = target_epoch; 119 | uint64_t new_bucket = target_bucket; 120 | 121 | // skip empty buckets 122 | while ((counter>0) && calendar.at(new_bucket).empty()) { 123 | if (++new_bucket >= calendar.size()) { 124 | new_bucket=0; 125 | new_epoch++; 126 | } 127 | } 128 | 129 | epoch = new_epoch; 130 | bucket = new_bucket; 131 | LOG("Kronos::get setting epoch to",epoch,"bucket to",bucket); 132 | } else { 133 | ERROR("Kronos::get Kronos uninitialized"); 134 | } 135 | } 136 | 137 | uint64_t Kronos::next() const { 138 | uint64_t ret = 0; 139 | if (initialized) { 140 | bool found = false; 141 | if (counter > 0) { 142 | // next epoch events 143 | list nextEpochEvents; 144 | 145 | // search for next event starting from current day/time 146 | for (uint64_t i = bucket; i < (bucket + calendar.size()); ++i) { 147 | auto& b = calendar[(i % calendar.size())]; 148 | 149 | if (!b.empty()) { 150 | const uint64_t front_epoch = 151 | (b.front().time/bucketWidth)/calendar.size(); 152 | // check if current epoch or calendar wrapped around 153 | LOG("Kronos::next found at bucket", i%calendar.size(), 154 | "front epoch", front_epoch,"current",epoch); 155 | 156 | if (front_epoch == epoch) { 157 | // next event found 158 | ret = b.front().time; 159 | found=true; 160 | LOG("Kronos::next - next event found:", b.front()); 161 | break; 162 | } else { 163 | nextEpochEvents.push_back(b.front().time); 164 | } 165 | } 166 | } 167 | if (!found && !nextEpochEvents.empty()) { 168 | nextEpochEvents.sort(); 169 | ret = nextEpochEvents.front(); 170 | } 171 | 172 | LOG("Kronos::next - next event is at time", ret,"total events",counter); 173 | } else { 174 | LOG("Kronos::next - no events scheduled"); 175 | } 176 | } else { 177 | ERROR("Kronos::next Kronos uninitialized"); 178 | } 179 | return ret; 180 | } 181 | 182 | } /* namespace TrafficProfiles */ 183 | -------------------------------------------------------------------------------- /kronos.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 1, 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | #ifndef __AMBA_TRAFFIC_PROFILE_KRONOS_HH__ 10 | #define __AMBA_TRAFFIC_PROFILE_KRONOS_HH__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "proto/tp_packet.pb.h" 16 | #include "event.hh" 17 | 18 | using namespace std; 19 | 20 | namespace TrafficProfiles { 21 | 22 | class TrafficProfileManager; 23 | 24 | /*! 25 | *\brief Kronos is the simulation engine for ATP 26 | * 27 | * Kronos schedules and triggers events in order to allow ATP 28 | * run in standalone mode or adaptor-driven mixed memory 29 | * mode, when requests go both to ATP and adaptor serviced memory 30 | * slaves. 31 | * 32 | * Kronos intercepts calls to send and receive API in the 33 | * TrafficProfileManager, of which it is an object. It matches 34 | * packets against ATP routing policies, then routes all packets 35 | * matching with internal ATP slaves to their destinations. 36 | * 37 | * If a packet is rejected by the slave, it gets scheduled to be 38 | * re-sent at the appropriate time. This happens by adding an 39 | * appropriate entry into its calendar queue. When a packet is 40 | * otherwise accepted by a slave, its corresponding response 41 | * is scheduled also in the form of a Kronos Event. 42 | * 43 | * Kronos Events are processed from the calendar queue 44 | * whenever a send/receive event is triggered in the ATP TPM. 45 | * 46 | * "In the Orphic cosmogony, the unaging Chronos produced 47 | * Aether and Chaos, and made a silvery egg in the divine Aether. 48 | * It produced the hermaphroditic god Phanes and Hydros who gave 49 | * birth to the first generation of gods and is the ultimate 50 | * creator of the cosmos." 51 | */ 52 | class Kronos { 53 | 54 | protected: 55 | 56 | //! Pointer to container ATP Manager 57 | TrafficProfileManager* const tpm; 58 | 59 | /*! 60 | *\brief Width of the calendar bucket 61 | * Duration of a time slice expressed 62 | * in ATP time units 63 | */ 64 | uint64_t bucketWidth; 65 | 66 | //! the Kronos calendar queue 67 | vector > calendar; 68 | 69 | //! current epoch 70 | uint64_t epoch; 71 | 72 | //! current bucket 73 | uint64_t bucket; 74 | 75 | /*! 76 | *\brief Events counter 77 | * Keeps track of the number of 78 | * currently active events 79 | */ 80 | uint64_t counter; 81 | 82 | //! initialization flag 83 | bool initialized; 84 | 85 | public: 86 | 87 | /*! 88 | * Kronos constructor 89 | *\param t pointer to parent TPM object 90 | */ 91 | Kronos(TrafficProfileManager* const); 92 | 93 | /*! 94 | * Initializes Kronos with parameters 95 | * from the TPM 96 | */ 97 | void init(); 98 | 99 | /*! 100 | * Kronos destructor 101 | */ 102 | virtual ~Kronos(); 103 | 104 | /*! 105 | *\brief Event schedule function 106 | * 107 | * Inserts an ATP Event 108 | * into the calendar queue 109 | * 110 | *\param ev ATP Event 111 | */ 112 | void schedule(const Event); 113 | 114 | /*! 115 | * Returns Events which happen 116 | * at the current time 117 | *\param q returned by reference list of Events 118 | */ 119 | void get(list&); 120 | 121 | /*! 122 | *\brief Returns next event time 123 | * Checks TPM time and returns the next 124 | * scheduled event time. 125 | */ 126 | uint64_t next() const; 127 | 128 | /*! 129 | * Returns the number of active events 130 | *\return the value of the event counter 131 | */ 132 | inline const uint64_t& getCounter() const { 133 | return counter; 134 | } 135 | 136 | /*! 137 | * Returns whether Kronos has been initialized 138 | *\return value of the initialized flag 139 | */ 140 | inline const bool& isInitialized() const { 141 | return initialized; 142 | } 143 | }; 144 | 145 | } /* namespace TrafficProfiles */ 146 | 147 | #endif /* __AMBA_TRAFFIC_PROFILE_KRONOS_HH__ */ 148 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.so 3 | *.d 4 | *.cmd 5 | *.ko 6 | *.mod 7 | *.mod.* 8 | modules.order 9 | Module.symvers 10 | -------------------------------------------------------------------------------- /linux/Kbuild: -------------------------------------------------------------------------------- 1 | obj-m := atp_buffer_manager.o atp_device.o 2 | ccflags-y += $(ATP_CFLAGS) 3 | -------------------------------------------------------------------------------- /linux/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | include Kbuild 3 | else 4 | 5 | SRC := $(shell pwd) 6 | ARCH ?= arm64 7 | CROSS_COMPILE ?= aarch64-none-linux-gnu- 8 | KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build 9 | 10 | ifeq ($(DEBUG), 1) 11 | ATP_CFLAGS := -g3 12 | endif 13 | 14 | .PHONY: default modules modules_install clean 15 | 16 | default: modules 17 | 18 | modules modules_install: 19 | $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) ATP_CFLAGS=$(ATP_CFLAGS) -C $(KERNEL_SRC) M=$(SRC) $@ 20 | 21 | clean: 22 | $(RM) *.a *.o *.ko *.mod *.mod.* .*.cmd modules.order Module.symvers 23 | endif 24 | -------------------------------------------------------------------------------- /linux/atp_buffer_manager.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #include "atp_buffer_manager.h" 10 | #include "atp_buffer_manager_user.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | static const struct file_operations file_ops = { 21 | .owner = THIS_MODULE, 22 | .unlocked_ioctl = atp_buffer_manager_ioctl 23 | }; 24 | 25 | static const struct dma_buf_ops buf_ops = { 26 | .cache_sgt_mapping = true, 27 | .attach = atp_buffer_manager_attach, 28 | .detach = atp_buffer_manager_detach, 29 | .map_dma_buf = atp_buffer_manager_map, 30 | .unmap_dma_buf = atp_buffer_manager_unmap, 31 | .mmap = atp_buffer_manager_mmap, 32 | .release = atp_buffer_manager_release 33 | }; 34 | 35 | static struct miscdevice buffer_manager = { 36 | .minor = MISC_DYNAMIC_MINOR, 37 | .name = "atpbuffer", 38 | .fops = &file_ops 39 | }; 40 | 41 | static long 42 | atp_buffer_manager_ioctl(struct file *file, unsigned int cmd, 43 | unsigned long arg) 44 | { 45 | struct dma_buf *buf; 46 | 47 | switch (cmd) { 48 | case ATP_GET_BUF: 49 | { 50 | struct atp_data_get_buf data; 51 | 52 | if (copy_from_user(&data, (void __user *) arg, sizeof(data))) 53 | return -EFAULT; 54 | data.size = PAGE_ALIGN(data.size); 55 | 56 | buf = atp_buffer_manager_export(data.size, data.contig); 57 | if (IS_ERR(buf)) 58 | return PTR_ERR(buf); 59 | 60 | data.fd = dma_buf_fd(buf, O_CLOEXEC); 61 | if (copy_to_user((void __user *) arg, &data, sizeof(data))) { 62 | atp_buffer_manager_release(buf); 63 | return -EFAULT; 64 | } 65 | 66 | break; 67 | } 68 | case ATP_PUT_BUF: 69 | { 70 | int data; 71 | struct list_head *pos, *n; 72 | struct dma_buf_attachment *att; 73 | 74 | if (copy_from_user(&data, (void __user *) arg, sizeof(data))) 75 | return -EFAULT; 76 | 77 | buf = dma_buf_get(data); 78 | if (IS_ERR(buf)) 79 | return PTR_ERR(buf); 80 | 81 | list_for_each_safe(pos, n, &buf->attachments) { 82 | att = list_entry(pos, struct dma_buf_attachment, node); 83 | list_del(pos); 84 | dma_buf_detach(buf, att); 85 | } 86 | 87 | dma_buf_put(buf); 88 | 89 | break; 90 | } 91 | } 92 | 93 | return 0; 94 | } 95 | 96 | static struct dma_buf * 97 | atp_buffer_manager_export(const size_t size, const bool contig) 98 | { 99 | struct atp_buffer_data *data; 100 | int i; 101 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 102 | struct dma_buf *buf; 103 | 104 | data = kzalloc(sizeof(*data), GFP_KERNEL); 105 | data->num_pages = size >> PAGE_SHIFT; 106 | data->pages = kcalloc(data->num_pages, sizeof(struct page *), 107 | GFP_KERNEL); 108 | data->contig = contig; 109 | 110 | if (data->contig) { 111 | void *kvaddr; 112 | 113 | kvaddr = alloc_pages_exact(size, GFP_KERNEL); 114 | if (!kvaddr) { 115 | buf = ERR_PTR(-ENOMEM); 116 | goto err; 117 | } 118 | for (i = 0; i < data->num_pages; ++i) { 119 | data->pages[i] = virt_to_page(kvaddr); 120 | kvaddr += PAGE_SIZE; 121 | } 122 | } else { 123 | if (!iommu_present(&platform_bus_type)) { 124 | buf = ERR_PTR(-ENODEV); 125 | goto err; 126 | } 127 | for (i = 0; i < data->num_pages; ++i) 128 | data->pages[i] = alloc_page(GFP_KERNEL); 129 | } 130 | 131 | exp_info.ops = &buf_ops; 132 | exp_info.size = size; 133 | exp_info.flags = O_RDWR; 134 | exp_info.priv = data; 135 | buf = dma_buf_export(&exp_info); 136 | if (IS_ERR(buf)) 137 | goto err; 138 | 139 | goto ok; 140 | err: 141 | kfree(data->pages); 142 | kfree(data); 143 | ok: 144 | return buf; 145 | } 146 | 147 | static int 148 | atp_buffer_manager_attach(struct dma_buf *buf, struct dma_buf_attachment *att) 149 | { 150 | struct sg_table *sgt; 151 | struct atp_buffer_data *data; 152 | int error; 153 | 154 | sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); 155 | if (!sgt) 156 | return -ENOMEM; 157 | 158 | data = buf->priv; 159 | error = sg_alloc_table_from_pages(sgt, data->pages, data->num_pages, 0, 160 | buf->size, GFP_KERNEL); 161 | if (error) 162 | goto err; 163 | att->priv = sgt; 164 | 165 | goto ok; 166 | err: 167 | kfree(sgt); 168 | ok: 169 | return error; 170 | } 171 | 172 | static void 173 | atp_buffer_manager_detach(struct dma_buf *buf, struct dma_buf_attachment *att) 174 | { 175 | struct sg_table *sgt; 176 | 177 | sgt = att->priv; 178 | sg_free_table(sgt); 179 | kfree(sgt); 180 | } 181 | 182 | static struct sg_table * 183 | atp_buffer_manager_map(struct dma_buf_attachment *att, 184 | enum dma_data_direction dir) 185 | { 186 | struct sg_table *sgt; 187 | 188 | sgt = att->priv; 189 | sgt->nents = dma_map_sg(att->dev, sgt->sgl, sgt->orig_nents, dir); 190 | if (!sgt->nents) 191 | return ERR_PTR(-EIO); 192 | 193 | return sgt; 194 | } 195 | 196 | static void 197 | atp_buffer_manager_unmap(struct dma_buf_attachment *att, struct sg_table *sgt, 198 | enum dma_data_direction dir) 199 | { 200 | dma_unmap_sg(att->dev, sgt->sgl, sgt->orig_nents, dir); 201 | } 202 | 203 | static int 204 | atp_buffer_manager_mmap(struct dma_buf *buf, struct vm_area_struct *vma) 205 | { 206 | struct atp_buffer_data *data; 207 | unsigned long uvaddr; 208 | int i, error; 209 | 210 | data = buf->priv; 211 | uvaddr = vma->vm_start; 212 | for (i = vma->vm_pgoff; i < data->num_pages; ++i) { 213 | if (uvaddr >= vma->vm_end) 214 | break; 215 | error = vm_insert_page(vma, uvaddr, data->pages[i]); 216 | if (error) 217 | return error; 218 | uvaddr += PAGE_SIZE; 219 | } 220 | 221 | return 0; 222 | } 223 | 224 | static void 225 | atp_buffer_manager_release(struct dma_buf *buf) 226 | { 227 | struct atp_buffer_data *data; 228 | int i; 229 | 230 | data = buf->priv; 231 | if (data->contig) { 232 | free_pages_exact(page_address(data->pages[0]), buf->size); 233 | } else { 234 | for (i = 0; i < data->num_pages; ++i) 235 | free_page((unsigned long) 236 | page_address(data->pages[i])); 237 | } 238 | kfree(data->pages); 239 | 240 | kfree(data); 241 | } 242 | 243 | module_misc_device(buffer_manager); 244 | 245 | MODULE_LICENSE("Dual BSD/GPL"); 246 | -------------------------------------------------------------------------------- /linux/atp_buffer_manager.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_BUFFER_MANAGER_H__ 10 | #define __ATP_BUFFER_MANAGER_H__ 11 | 12 | #include 13 | #include 14 | 15 | struct file; 16 | struct dma_buf; 17 | struct dma_buf_attachment; 18 | struct vm_area_struct; 19 | 20 | struct atp_buffer_data { 21 | /* Physical memory pages allocated for the buffer */ 22 | size_t num_pages; 23 | struct page **pages; 24 | /* Whether this buffer is physically contiguous in memory */ 25 | bool contig; 26 | }; 27 | 28 | /* 29 | * IOCTL system call handler 30 | * 31 | * @file: [in] data structure corresponding to the FD provided from user-space 32 | * @cmd: [in] IOCTL command code (see atp_buffer_manager_user.h) 33 | * @arg: [in/out] command argument / parameter 34 | * 35 | * Returns 0 on success, negative error code otherwise 36 | */ 37 | static long 38 | atp_buffer_manager_ioctl(struct file *file, unsigned int cmd, 39 | unsigned long arg); 40 | 41 | /* 42 | * Allocates and exports a shareable DMA buffer 43 | * 44 | * @size: [in] size of the buffer in bytes 45 | * @contig: [in] true if the buffer should be physically contiguous 46 | * 47 | * Returns pointer to the allocated buffer on success, ERR_PTR otherwise 48 | */ 49 | static struct dma_buf * 50 | atp_buffer_manager_export(const size_t size, const bool contig); 51 | 52 | /* 53 | * Callback triggered when a user attaches a device to a shareable DMA buffer 54 | * 55 | * @buf: [in] buffer being attached to 56 | * @att: [in] buffer attachment data 57 | * 58 | * Returns 0 on success, negative error code otherwise 59 | */ 60 | static int 61 | atp_buffer_manager_attach(struct dma_buf *buf, struct dma_buf_attachment *att); 62 | 63 | /* 64 | * Callback triggered when a user detaches a device from a shareable DMA buffer 65 | * 66 | * @buf: [in] buffer being detached from 67 | * @att: [in] buffer attachment data 68 | */ 69 | static void 70 | atp_buffer_manager_detach(struct dma_buf *buf, struct dma_buf_attachment *att); 71 | 72 | /* 73 | * Callback triggered when a user maps a shareable DMA buffer to a device 74 | * address space 75 | * 76 | * @att: [in] buffer attachment data 77 | * @dir: [in] mapping direction 78 | * 79 | * Returns pointer to the mapped SG table on success, ERR_PTR otherwise 80 | */ 81 | static struct sg_table * 82 | atp_buffer_manager_map(struct dma_buf_attachment *att, 83 | enum dma_data_direction dir); 84 | 85 | /* 86 | * Callback triggered when a user unmaps a shareable DMA buffer from a device 87 | * address space 88 | * 89 | * @att: [in] buffer attachment data 90 | * @sgt: [in] mapped SG table to unmap 91 | * @dir: [in] mapping direction 92 | */ 93 | static void 94 | atp_buffer_manager_unmap(struct dma_buf_attachment *att, struct sg_table *sgt, 95 | enum dma_data_direction dir); 96 | 97 | /* 98 | * Callback triggered when a user maps a shareable DMA buffer to its virtual 99 | * address space 100 | * 101 | * @buf: [in] buffer to be mapped 102 | * @vma: [in] virtual memory area where to map the buffer 103 | * 104 | * Returns 0 on success, negative error code otherwise 105 | */ 106 | static int 107 | atp_buffer_manager_mmap(struct dma_buf *buf, struct vm_area_struct *vma); 108 | 109 | /* 110 | * Callback triggered when the last reference to shareable DMA buffer is 111 | * released. Deallocates the buffer and associated data. 112 | * 113 | * @buf: [in] buffer to be deallocated 114 | */ 115 | static void 116 | atp_buffer_manager_release(struct dma_buf *buf); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /linux/atp_buffer_manager_user.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_BUFFER_MANAGER_USER_H__ 10 | #define __ATP_BUFFER_MANAGER_USER_H__ 11 | 12 | #ifdef __KERNEL__ 13 | #include 14 | #include 15 | #else 16 | #include 17 | #include 18 | #endif 19 | 20 | struct atp_data_get_buf { 21 | /* Buffer size in bytes */ 22 | size_t size; 23 | /* (Out) Resulting file descriptor idenitifying the buffer */ 24 | int fd; 25 | /* 26 | * Specifies the buffer as physically contiguous in memory. Intended to 27 | * allow access to the buffer from devices not behind an IOMMU. Can be 28 | * safely used for buffers up to 1 MiB in size; allocations from 1 MiB 29 | * to 4 MiB have a small chance of succeeding; allocations bigger than 30 | * 4 MiB will return always fail. 31 | */ 32 | bool contig; 33 | }; 34 | 35 | #define ATP_BUFFER_MANAGER_IOCTL_BASE 0xE2 36 | 37 | /* Allocate and retrieve the FD of a shareable DMA buffer */ 38 | #define ATP_GET_BUF \ 39 | _IOWR(ATP_BUFFER_MANAGER_IOCTL_BASE, 1, struct atp_data_get_buf) 40 | /* Deallocate a shareable DMA buffer */ 41 | #define ATP_PUT_BUF \ 42 | _IOW(ATP_BUFFER_MANAGER_IOCTL_BASE, 2, int) 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /linux/atp_device.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_DEVICE_H__ 10 | #define __ATP_DEVICE_H__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct dma_buf; 19 | struct platform_device; 20 | 21 | struct atp_device_data { 22 | /* ATP device ID, same as in .atp files */ 23 | const char *atp_id; 24 | /* Play stream requests */ 25 | struct list_head play_requests; 26 | uint32_t next_play_request_id; 27 | spinlock_t play_requests_lock; 28 | /* Allocated interrupt for the device */ 29 | int irq; 30 | /* Memory region for accessing the device MMIO registers */ 31 | void __iomem *mmio; 32 | spinlock_t mmio_lock; 33 | struct miscdevice mdev; 34 | }; 35 | 36 | /* See gem5/atp_device.hh for a description of MMIO registers */ 37 | enum atp_device_offset { 38 | STREAM_NAME_BASE = 0x00, 39 | STREAM_NAME_RANGE = 0x08, 40 | READ_BASE = 0x10, 41 | READ_RANGE = 0x18, 42 | WRITE_BASE = 0x20, 43 | WRITE_RANGE = 0x28, 44 | STREAM_ID = 0x30, 45 | TASK_ID = 0x38, 46 | IN_REQUEST_ID = 0x3c, 47 | OUT_REQUEST_ID = 0x40, 48 | CONTROL = 0x44, 49 | STATUS = 0x45 50 | }; 51 | 52 | struct atp_request_play_stream { 53 | /* Unique request ID */ 54 | uint32_t id; 55 | /* Buffer DMA read address and range */ 56 | dma_addr_t raddr; 57 | size_t rrange; 58 | /* Buffer DMA write address and range */ 59 | dma_addr_t waddr; 60 | size_t wrange; 61 | /* Unique ATP stream ID. Obtained via ATP_UNIQUE_STREAM */ 62 | uint64_t stream_id; 63 | /* Unique flow ID. Identifies the stream activity across the system */ 64 | uint32_t flow_id; 65 | wait_queue_head_t wait; 66 | bool completed; 67 | struct list_head node; 68 | }; 69 | 70 | struct atp_request_unique_stream { 71 | /* ATP stream name, same as in .atp files */ 72 | const char *stream_name; 73 | /* Stream base DMA address and range */ 74 | dma_addr_t stream_name_addr; 75 | size_t stream_name_range; 76 | }; 77 | 78 | /* 79 | * IOCTL system call handler 80 | * 81 | * @file: [in] data structure corresponding to the FD provided from user-space 82 | * @cmd: [in] IOCTL command code (see atp_buffer_manager_user.h) 83 | * @arg: [in/out] command argument / parameter 84 | * 85 | * Returns 0 on success, negative error code otherwise 86 | */ 87 | static long 88 | atp_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 89 | 90 | /* 91 | * Retrieves data for a particular device - buffer attachment 92 | * 93 | * @buf: [in] attached buffer 94 | * @dev: [in] attached device 95 | * 96 | * Returns pointer to the attachment data on success, ERR_PTR otherwise 97 | */ 98 | static struct dma_buf_attachment * 99 | atp_device_attachment_get(struct dma_buf *buf, struct device *dev); 100 | 101 | /* 102 | * Maps a shareable DMA buffer to a device address space 103 | * 104 | * @buf_fd: [in] buffer file descriptor 105 | * @dev: [in] attached device to receive the mapping 106 | * @dir: [in] mapping direction 107 | * @addr: [out] resulting mapping base address 108 | * @range: [out] resulting mapping range 109 | * 110 | * Returns 0 on success, negative error code otherwise 111 | */ 112 | static int 113 | atp_device_attachment_map(const int buf_fd, struct device *dev, 114 | const enum dma_data_direction dir, dma_addr_t *addr, 115 | size_t *range); 116 | 117 | /* 118 | * Allocates a request for a play stream call 119 | * 120 | * @dev_data: [in] device-specific data 121 | * @stream_id: [in] call-provided stream ID 122 | * @flow_id: [in] call-provided flow ID 123 | * 124 | * Returns pointer to allocated request 125 | */ 126 | static struct atp_request_play_stream * 127 | atp_device_request_get_play_stream(struct atp_device_data *dev_data, 128 | const uint64_t stream_id, 129 | const uint32_t flow_id); 130 | 131 | /* 132 | * Looks up a play stream call request in the device pending list 133 | * 134 | * @dev_data: [in] device-specific data 135 | * @req_id: [in] request ID used in the lookup 136 | * 137 | * Returns pointer to the pending request, ERR_PTR otherwise 138 | */ 139 | static struct atp_request_play_stream * 140 | atp_device_request_get_play_stream_by_id(struct atp_device_data *dev_data, 141 | const uint32_t req_id); 142 | 143 | /* 144 | * Deallocates a request for a play stream call 145 | * 146 | * @dev_data: [in] device-specific data 147 | * @req: [in] request to be deallocated 148 | */ 149 | static void 150 | atp_device_request_put_play_stream(struct atp_device_data *dev_data, 151 | struct atp_request_play_stream *req); 152 | 153 | /* 154 | * Allocates a request for a unique stream call 155 | * 156 | * @stream_name: [in] call-provided stream name 157 | * 158 | * Returns pointer to allocated request 159 | */ 160 | static struct atp_request_unique_stream * 161 | atp_device_request_get_unique_stream(const char __user *stream_name); 162 | 163 | /* 164 | * Deallocates a request for a unique stream call 165 | * 166 | * @req: [in] request to be deallocated 167 | */ 168 | static void 169 | atp_device_request_put_unique_stream(struct atp_request_unique_stream *req); 170 | 171 | /* 172 | * Programs a device MMIO registers to play a stream 173 | * 174 | * @dev_data: [in] device-specific data 175 | * @req: [in] request with specific programming parameters 176 | */ 177 | static void 178 | atp_device_mmio_play_stream(struct atp_device_data *dev_data, 179 | struct atp_request_play_stream *req); 180 | 181 | /* 182 | * Programs a device MMIO registers to instantiate a unique stream 183 | * 184 | * @dev_data: [in] device-specific data 185 | * @req: [in] request with specific programming parameters 186 | * @stream_id: [out] resulting unique stream ID 187 | */ 188 | static void 189 | atp_device_mmio_unique_stream(struct atp_device_data *dev_data, 190 | struct atp_request_unique_stream *req, 191 | uint64_t *stream_id); 192 | 193 | /* 194 | * Common ATP device interrupt service routine 195 | * 196 | * @irq: [in] device-specific interrupt received 197 | * @handle: [in] pointer to device-specific data 198 | * 199 | * Returns IRQ_HANDLED 200 | */ 201 | static irqreturn_t 202 | atp_device_isr(int irq, void *handle); 203 | 204 | /* 205 | * Callback triggered when a compatible ATP device is discovered 206 | * 207 | * @pdev: [in] discovered device 208 | * 209 | * Returns 0 on success, negative error code otherwise 210 | */ 211 | static int 212 | atp_device_probe(struct platform_device *pdev); 213 | 214 | /* 215 | * Callback triggered when a compatible ATP device is removed 216 | * 217 | * @pdev: [in] removed device 218 | * 219 | * Returns 0 220 | */ 221 | static int 222 | atp_device_remove(struct platform_device *pdev); 223 | 224 | #endif 225 | -------------------------------------------------------------------------------- /linux/atp_device_user.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_DEVICE_USER_H__ 10 | #define __ATP_DEVICE_USER_H__ 11 | 12 | struct atp_data_play_stream { 13 | /* Unique ID of the stream to play */ 14 | uint64_t atp_stream_id; 15 | /* Unique flow ID. Identifies the stream activity across the system */ 16 | uint32_t flow_id; 17 | /* 18 | * Read and write buffer file descriptors. At least one must be 19 | * provided 20 | */ 21 | int read_fd; 22 | int write_fd; 23 | }; 24 | 25 | struct atp_data_unique_stream { 26 | /* ATP stream name, same as in .atp files */ 27 | const char *atp_stream_name; 28 | /* (Out) Resulting unique stream ID */ 29 | uint64_t atp_stream_id; 30 | }; 31 | 32 | #define ATP_DEVICE_MAX_LEN_STREAM_NAME 256 33 | 34 | #define ATP_DEVICE_IOCTL_BASE 0xE1 35 | 36 | /* Attaches the device to an allocated shareable DMA buffer */ 37 | #define ATP_ATTACH_BUFFER \ 38 | _IOW(ATP_DEVICE_IOCTL_BASE, 1, int) 39 | /* Detaches the device from an allocated shareable DMA buffer */ 40 | #define ATP_DETACH_BUFFER \ 41 | _IOW(ATP_DEVICE_IOCTL_BASE, 2, int) 42 | /* Plays a unique stream in the ATP Engine */ 43 | #define ATP_PLAY_STREAM \ 44 | _IOW(ATP_DEVICE_IOCTL_BASE, 3, struct atp_data_play_stream) 45 | /* Instantiates a unique stream in the ATP Engine and retrieves its ID */ 46 | #define ATP_UNIQUE_STREAM \ 47 | _IOW(ATP_DEVICE_IOCTL_BASE, 4, struct atp_data_unique_stream) 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /linux/test/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard *.cc) 2 | obj := $(src:.cc=.o) 3 | dep := $(src:.cc=.d) 4 | out := test_atp 5 | 6 | CPPFLAGS := -I../uapi -MMD -MP 7 | CXXFLAGS := -std=c++11 -Wall -Wextra -Werror -pedantic 8 | LDFLAGS ?= -L../uapi 9 | LDLIBS := -latp -lcppunit 10 | ifeq ($(DEBUG), 1) 11 | CXXFLAGS += -O0 -g3 12 | else 13 | CXXFLAGS += -O3 14 | endif 15 | 16 | PREFIX := /usr/local 17 | 18 | .PHONY: all 19 | all: $(out).out 20 | $(out).out: $(obj) 21 | $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@ 22 | 23 | .PHONY: install 24 | install: all 25 | mkdir -p $(DESTDIR)$(PREFIX)/bin 26 | cp $(out).out $(DESTDIR)$(PREFIX)/bin 27 | 28 | .PHONY: clean 29 | clean: 30 | $(RM) $(obj) $(dep) $(out).out 31 | 32 | -include $(dep) 33 | -------------------------------------------------------------------------------- /linux/test/main.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "test_atp_buf.hh" 18 | #include "test_atp_dev.hh" 19 | 20 | int main(int argc, char *argv[]) { 21 | const bool run_all{ argc < 2 }; 22 | 23 | CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpBufGet); 24 | // Exclude IPC tests when running all tests 25 | if (!run_all) { CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpBufShare); } 26 | CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpBufCpuAccess); 27 | CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpDevAttach); 28 | CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpDevUniqueStr); 29 | CPPUNIT_TEST_SUITE_REGISTRATION(TestAtpDevPlayStr); 30 | 31 | CPPUNIT_NS::TestResult controller{ }; 32 | CPPUNIT_NS::TestResultCollector result{ }; 33 | CPPUNIT_NS::BriefTestProgressListener progress{ }; 34 | CPPUNIT_NS::TestRunner runner{ }; 35 | 36 | controller.addListener(&result); 37 | controller.addListener(&progress); 38 | 39 | auto *suites{ static_cast( 40 | CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest()) }; 41 | if (run_all) { 42 | runner.addTest(suites); 43 | } else { 44 | // Run subset of tests based on the passed regex 45 | const std::regex re{ argv[1] }; 46 | for (auto &suite : suites->getTests()) { 47 | for (auto i{ 0 }; i < suite->getChildTestCount(); ++i) { 48 | auto *test{ suite->getChildTestAt(i) }; 49 | if (std::regex_search(test->getName(), re)) 50 | runner.addTest(test); 51 | } 52 | } 53 | } 54 | 55 | runner.run(controller); 56 | 57 | CPPUNIT_NS::CompilerOutputter outputter{ &result, CPPUNIT_NS::stdCOut()} ; 58 | outputter.write(); 59 | 60 | return result.wasSuccessful() ? 0 : 1; 61 | } 62 | -------------------------------------------------------------------------------- /linux/test/test_atp_buf.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #include "test_atp_buf.hh" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | void TestAtpBufBase::setUp() { 18 | bm_fd = fd("/dev/atpbuffer"); 19 | } 20 | 21 | void TestAtpBufBase::tearDown() { 22 | close(bm_fd); 23 | } 24 | 25 | int TestAtpBufBase::fd(const std::string &name) { 26 | const int fd{ open(name.c_str(), O_RDWR) }; 27 | CPPUNIT_ASSERT_GREATEREQUAL(0, fd); 28 | return fd; 29 | } 30 | 31 | int TestAtpBufBase::get(const size_t size) { 32 | const auto buf_fd{ atp_buffer_get(bm_fd, size) }; 33 | CPPUNIT_ASSERT_GREATEREQUAL(0, buf_fd); 34 | return buf_fd; 35 | } 36 | 37 | void TestAtpBufBase::put(const int buf_fd) { 38 | CPPUNIT_ASSERT_EQUAL(0, atp_buffer_put(bm_fd, buf_fd)); 39 | } 40 | 41 | void TestAtpBufGet::testSinglePage() { 42 | put(get(getpagesize())); 43 | } 44 | 45 | void TestAtpBufGet::testMultiPage() { 46 | put(get(4 * getpagesize())); 47 | } 48 | 49 | void TestAtpBufGet::testB4M() { 50 | put(get(8388608)); 51 | } 52 | 53 | void TestAtpBufGet::testContig() { 54 | const auto buf_fd{ atp_buffer_get_contig(bm_fd, 4 * getpagesize()) }; 55 | CPPUNIT_ASSERT_GREATEREQUAL(0, buf_fd); 56 | put(buf_fd); 57 | } 58 | 59 | void TestAtpBufGet::testContigB4M() { 60 | CPPUNIT_ASSERT_LESS(0, atp_buffer_get_contig(bm_fd, 8388608)); 61 | } 62 | 63 | void TestAtpBufGet::testMultiBuf() { 64 | std::vector buf_fds{ }; 65 | buf_fds.reserve(4); 66 | for (size_t i{ 0 }; i < buf_fds.capacity(); ++i) 67 | buf_fds.emplace_back(get(4 * getpagesize())); 68 | for (auto &buf_fd : buf_fds) 69 | put(buf_fd); 70 | } 71 | 72 | void TestAtpBufShare::testSend() { 73 | const auto buf_fd{ get(4 * getpagesize()) }; 74 | CPPUNIT_ASSERT_EQUAL(0, atp_buffer_send("/tmp/fd_comm", buf_fd)); 75 | } 76 | 77 | void TestAtpBufShare::testRecv() { 78 | const auto buf_fd{ atp_buffer_receive("/tmp/fd_comm") }; 79 | CPPUNIT_ASSERT_GREATEREQUAL(0, buf_fd); 80 | put(buf_fd); 81 | } 82 | 83 | void *TestAtpBufCpuAccess::getCpu(const int buf_fd, const size_t size) { 84 | auto *buf{ atp_buffer_cpu_get(buf_fd, size) }; 85 | CPPUNIT_ASSERT(buf != nullptr); 86 | return buf; 87 | } 88 | 89 | void TestAtpBufCpuAccess::testSinglePage() { 90 | const auto buf_sz{ getpagesize() }; 91 | const auto buf_fd{ get(buf_sz) }; 92 | atp_buffer_cpu_put(getCpu(buf_fd, buf_sz), buf_sz); 93 | put(buf_fd); 94 | } 95 | 96 | void TestAtpBufCpuAccess::testMultiPage() { 97 | const auto buf_sz{ 4 * getpagesize() }; 98 | const auto buf_fd{ get(buf_sz) }; 99 | atp_buffer_cpu_put(getCpu(buf_fd, buf_sz), buf_sz); 100 | put(buf_fd); 101 | } 102 | 103 | void TestAtpBufCpuAccess::testAccess() { 104 | const auto buf_sz{ 2 * getpagesize() }; 105 | const auto buf_fd{ get(buf_sz) }; 106 | char *buf{ static_cast(getCpu(buf_fd, buf_sz)) }; 107 | CPPUNIT_ASSERT_EQUAL(0, atp_buffer_cpu_begin(buf_fd)); 108 | std::memset(buf, 'A', buf_sz); 109 | for (auto i{ 0 }; i < buf_sz; ++i) { 110 | CPPUNIT_ASSERT(*(buf + i) == 'A'); 111 | } 112 | CPPUNIT_ASSERT_EQUAL(0, atp_buffer_cpu_end(buf_fd)); 113 | atp_buffer_cpu_put(buf, buf_sz); 114 | put(buf_fd); 115 | } 116 | -------------------------------------------------------------------------------- /linux/test/test_atp_buf.hh: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __TEST_ATP_BUF_HH__ 10 | #define __TEST_ATP_BUF_HH__ 11 | 12 | #include 13 | 14 | //! Base class for test suites using the ATP buffer manager module 15 | class TestAtpBufBase : public CPPUNIT_NS::TestFixture { 16 | public: 17 | virtual void setUp() override; 18 | virtual void tearDown() override; 19 | protected: 20 | //! Buffer manager file descriptor 21 | int bm_fd; 22 | //! Helper. Returns a module file descriptor. Checks correctness. 23 | int fd(const std::string &name); 24 | //! Helper. Returns a buffer file descriptor. Checks correctness. 25 | int get(const size_t size); 26 | //! Helper. Releases a buffer. Checks correctness. 27 | void put(const int buf_fd); 28 | }; 29 | 30 | //! Test suite targeting "ATP_GET_BUF" and "ATP_PUT_BUF" APIs 31 | class TestAtpBufGet : public TestAtpBufBase { 32 | CPPUNIT_TEST_SUITE(TestAtpBufGet); 33 | CPPUNIT_TEST(testSinglePage); 34 | CPPUNIT_TEST(testMultiPage); 35 | CPPUNIT_TEST(testB4M); 36 | CPPUNIT_TEST(testContig); 37 | CPPUNIT_TEST(testContigB4M); 38 | CPPUNIT_TEST(testMultiBuf); 39 | CPPUNIT_TEST_SUITE_END(); 40 | protected: 41 | //! Tests single-page buffer allocation 42 | void testSinglePage(); 43 | //! Tests multi-page buffer allocation 44 | void testMultiPage(); 45 | //! Tests bigger than 4MiB (contiguous limit) buffer allocation 46 | void testB4M(); 47 | //! Tests contiguous buffer allocation 48 | void testContig(); 49 | //! Tests contiguous bigger than 4MiB buffer allocation 50 | void testContigB4M(); 51 | //! Tests multiple outstanding buffer allocations 52 | void testMultiBuf(); 53 | }; 54 | 55 | /*! 56 | * Test suite targeting "atp_buffer_send" and "atp_buffer_receive" APIs 57 | * Disabled by default when running all test suites 58 | * Sender and receiver should be executed in different Linux processes 59 | */ 60 | class TestAtpBufShare : public TestAtpBufBase { 61 | CPPUNIT_TEST_SUITE(TestAtpBufShare); 62 | CPPUNIT_TEST(testSend); 63 | CPPUNIT_TEST(testRecv); 64 | CPPUNIT_TEST_SUITE_END(); 65 | protected: 66 | //! Tests sending a buffer file descriptor over UNIX sockets 67 | void testSend(); 68 | //! Tests receiving a buffer file descriptor over UNIX sockets 69 | void testRecv(); 70 | }; 71 | 72 | //! Test suite targeting "atp_buffer_cpu_*" APIs 73 | class TestAtpBufCpuAccess : public TestAtpBufBase { 74 | CPPUNIT_TEST_SUITE(TestAtpBufCpuAccess); 75 | CPPUNIT_TEST(testSinglePage); 76 | CPPUNIT_TEST(testMultiPage); 77 | CPPUNIT_TEST(testAccess); 78 | CPPUNIT_TEST_SUITE_END(); 79 | protected: 80 | //! Tests single-page buffer CPU address space mapping 81 | void testSinglePage(); 82 | //! Tests multi-page buffer CPU address space mapping 83 | void testMultiPage(); 84 | //! Tests access to a buffer from CPU address space 85 | void testAccess(); 86 | //! Helper. Returns a CPU mapped buffer. Checks correcteness. 87 | void *getCpu(const int buf_fd, const size_t size); 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /linux/test/test_atp_dev.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #include "test_atp_dev.hh" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | void TestAtpDevBase::setUp() { 17 | TestAtpBufBase::setUp(); 18 | dev_fd = fd("/dev/atpSTREAM"); 19 | } 20 | 21 | void TestAtpDevBase::tearDown() { 22 | close(dev_fd); 23 | TestAtpBufBase::tearDown(); 24 | } 25 | 26 | uint64_t TestAtpDevBase::unique() { 27 | const char *str_name{ "ROOT" }; 28 | auto id{ std::numeric_limits::max() }; 29 | CPPUNIT_ASSERT_EQUAL(0, atp_device_unique_stream(dev_fd, str_name, &id)); 30 | CPPUNIT_ASSERT(id != std::numeric_limits::max()); 31 | return id; 32 | } 33 | 34 | void TestAtpDevAttach::testAttach() { 35 | const auto buf_fd{ get(4 * getpagesize()) }; 36 | CPPUNIT_ASSERT_EQUAL(0, atp_device_attach(dev_fd, buf_fd)); 37 | CPPUNIT_ASSERT_EQUAL(0, atp_device_detach(dev_fd, buf_fd)); 38 | put(buf_fd); 39 | } 40 | 41 | void TestAtpDevUniqueStr::testUniqueStr() { 42 | unique(); 43 | } 44 | 45 | void TestAtpDevPlayStr::setUp() { 46 | TestAtpDevBase::setUp(); 47 | // Size expected by ROOT stream 48 | buf_fd = get(3200); 49 | CPPUNIT_ASSERT_EQUAL(0, atp_device_attach(dev_fd, buf_fd)); 50 | str_id = unique(); 51 | } 52 | 53 | void TestAtpDevPlayStr::tearDown() { 54 | CPPUNIT_ASSERT_EQUAL(0, atp_device_detach(dev_fd, buf_fd)); 55 | put(buf_fd); 56 | TestAtpDevBase::tearDown(); 57 | } 58 | 59 | void TestAtpDevPlayStr::testPlayStr() { 60 | CPPUNIT_ASSERT_EQUAL(0, 61 | atp_device_play_stream(dev_fd, str_id, 1, buf_fd, -1)); 62 | } 63 | 64 | void TestAtpDevPlayStr::testMultiPlayStr() { 65 | CPPUNIT_ASSERT_EQUAL(0, 66 | atp_device_play_stream(dev_fd, str_id, 1, buf_fd, -1)); 67 | CPPUNIT_ASSERT_EQUAL(0, 68 | atp_device_play_stream(dev_fd, str_id, 1, buf_fd, -1)); 69 | } 70 | -------------------------------------------------------------------------------- /linux/test/test_atp_dev.hh: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __TEST_ATP_DEV_HH__ 10 | #define __TEST_ATP_DEV_HH__ 11 | 12 | #include 13 | 14 | #include "test_atp_buf.hh" 15 | 16 | // Base class for test suites using the ATP device module 17 | class TestAtpDevBase : public TestAtpBufBase { 18 | public: 19 | virtual void setUp() override; 20 | virtual void tearDown() override; 21 | protected: 22 | int dev_fd; 23 | uint64_t unique(void); 24 | }; 25 | 26 | //! Test suite targeting "ATP_ATTACH_BUFFER" and "ATP_DETACH_BUFFER" APIs 27 | class TestAtpDevAttach : public TestAtpDevBase { 28 | CPPUNIT_TEST_SUITE(TestAtpDevAttach); 29 | CPPUNIT_TEST(testAttach); 30 | CPPUNIT_TEST_SUITE_END(); 31 | protected: 32 | // Tests attaching an ATP device to a previously allocated buffer 33 | void testAttach(); 34 | }; 35 | 36 | //! Test suite targeting "ATP_UNIQUE_STREAM" API 37 | class TestAtpDevUniqueStr : public TestAtpDevBase { 38 | CPPUNIT_TEST_SUITE(TestAtpDevUniqueStr); 39 | CPPUNIT_TEST(testUniqueStr); 40 | CPPUNIT_TEST_SUITE_END(); 41 | protected: 42 | // Tests creating a unique stream identifier through ATP Engine 43 | void testUniqueStr(); 44 | }; 45 | 46 | //! Test suite targeting "ATP_PLAY_STREAM" API 47 | class TestAtpDevPlayStr : public TestAtpDevBase { 48 | CPPUNIT_TEST_SUITE(TestAtpDevPlayStr); 49 | CPPUNIT_TEST(testPlayStr); 50 | CPPUNIT_TEST(testMultiPlayStr); 51 | CPPUNIT_TEST_SUITE_END(); 52 | public: 53 | virtual void setUp() override; 54 | virtual void tearDown() override; 55 | protected: 56 | int buf_fd; 57 | uint64_t str_id; 58 | // Tests activating a stream through ATP Engine 59 | void testPlayStr(); 60 | /* 61 | * Tests multiple activations of a stream through ATP Engine 62 | * Verifies the request handling process in the kernel module 63 | */ 64 | void testMultiPlayStr(); 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /linux/uapi/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard *.c) 2 | obj := $(src:.c=.o) 3 | dep := $(src:.c=.d) 4 | out := libatp 5 | 6 | # Path to exported kernel user API header files 7 | # https://www.kernel.org/doc/html/latest/kbuild/headers_install.html 8 | KERNEL_HDR_PATH ?= /usr/include 9 | 10 | ARFLAGS := Ucrs 11 | CPPFLAGS := -I../../ -I$(KERNEL_HDR_PATH) -MMD -MP 12 | CFLAGS := -std=c11 -Wall -Wextra -Werror -pedantic 13 | ifeq ($(DEBUG), 1) 14 | CFLAGS += -O0 -g3 15 | else 16 | CFLAGS += -O3 17 | endif 18 | 19 | PREFIX := /usr/local 20 | 21 | .PHONY: all static 22 | all: $(out).so 23 | $(out).so: CFLAGS += -fPIC 24 | $(out).so: LDFLAGS += -shared 25 | $(out).so: $(obj) 26 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 27 | static: $(out).a($(obj)) 28 | 29 | .PHONY: install install_static install_common 30 | install: all install_common 31 | cp $(out).so $(DESTDIR)$(PREFIX)/lib 32 | install_static: static install_common 33 | cp $(out).a $(DESTDIR)$(PREFIX)/lib 34 | install_common: 35 | mkdir -p $(DESTDIR)$(PREFIX)/lib 36 | mkdir -p $(DESTDIR)$(PREFIX)/include 37 | cp atp.h $(DESTDIR)$(PREFIX)/include 38 | 39 | .PHONY: uninstall uninstall_static uninstall_common 40 | uninstall: uninstall_common 41 | $(RM) $(DESTDIR)$(PREFIX)/lib/$(out).so 42 | uninstall_static: 43 | $(RM) $(DESTDIR)$(PREFIX)/lib/$(out).a 44 | uninstall_common: 45 | $(RM) $(DESTDIR)$(PREFIX)/include/atp.h 46 | 47 | .PHONY: clean 48 | clean: 49 | $(RM) $(obj) $(dep) $(out).so $(out).a 50 | 51 | -include $(dep) 52 | -------------------------------------------------------------------------------- /linux/uapi/atp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 | 3 | /* 4 | * Copyright (c) 2019-2020 ARM Limited 5 | * All rights reserved 6 | * Authors: Adrian Herrera 7 | */ 8 | 9 | #ifndef __ATP_H__ 10 | #define __ATP_H__ 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /* ATP buffer manager declarations */ 21 | 22 | /* 23 | * Allocates and retrieves the FD of a shareable DMA buffer 24 | * 25 | * @fd: [in] buffer manager file descriptor 26 | * @size: [in] size of the buffer in bytes 27 | * 28 | * Returns buffer file descriptor on sucess, negative error code otherwise 29 | */ 30 | int 31 | atp_buffer_get(const int fd, const size_t size); 32 | int 33 | atp_buffer_get_contig(const int fd, const size_t size); 34 | 35 | /* 36 | * Deallocates a shareable DMA buffer 37 | * 38 | * @fd: [in] buffer manager file descriptor 39 | * @buf_fd: [in] file descriptor of the buffer to deallocate 40 | * 41 | * Returns 0 on sucess, negative error code otherwise 42 | */ 43 | int 44 | atp_buffer_put(const int fd, const int buf_fd); 45 | 46 | /* 47 | * Sends a buffer FD to another process 48 | * Uses ancillary data over UNIX domain sockets 49 | * 50 | * @fpath: [in] UNIX domain socket location 51 | * @buf_fd: [in] buffer file descriptor to send 52 | * 53 | * Returns 0 on sucess, negative error code otherwise 54 | */ 55 | int 56 | atp_buffer_send(const char *fpath, const int buf_fd); 57 | 58 | /* 59 | * Receives a buffer FD from another process 60 | * Uses ancillary data over UNIX domain sockets 61 | * 62 | * @fpath: [in] UNIX domain socket location 63 | * 64 | * Returns buffer file descriptor on sucess, negative error code otherwise 65 | */ 66 | int 67 | atp_buffer_receive(const char *fpath); 68 | 69 | /* 70 | * Maps a shareable DMA buffer to the caller process address space 71 | * Supports mapping the entire buffer or any sub-range 72 | * 73 | * @buf_fd: [in] file descriptor of the buffer to map 74 | * @size: [in] range of the buffer to map 75 | * 76 | * Returns pointer to mapped buffer, NULL otherwise 77 | */ 78 | void * 79 | atp_buffer_cpu_get(const int buf_fd, const size_t size); 80 | 81 | /* 82 | * Unmaps a shareable DMA buffer from the caller process address space 83 | * 84 | * @buffer: [in] buffer to unmap 85 | * @size: [in] range of the buffer to unmap 86 | */ 87 | void 88 | atp_buffer_cpu_put(void *buffer, const size_t size); 89 | 90 | /* 91 | * Synchronises the system for the beginning of a CPU access to a buffer 92 | * 93 | * @buf_fd: [in] file descriptor of the accessed buffer 94 | * 95 | * Returns 0 on success, negative error code otherwise 96 | */ 97 | int 98 | atp_buffer_cpu_begin(const int buf_fd); 99 | 100 | /* 101 | * Synchronises the system for the ending of a CPU access to a buffer 102 | * 103 | * @buf_fd: [in] file descriptor of the accessed buffer 104 | * 105 | * Returns 0 on success, negative error code otherwise 106 | */ 107 | int 108 | atp_buffer_cpu_end(const int buf_fd); 109 | 110 | /* 111 | * Associates a device to a shareable DMA buffer 112 | * Enables mapping and access from the device to the buffer 113 | * 114 | * @fd: [in] device file descriptor 115 | * @buf_fd: [in] buffer file descriptor 116 | * 117 | * Returns 0 on success, negative error code otherwise 118 | */ 119 | int 120 | atp_device_attach(const int fd, const int buf_fd); 121 | 122 | /* 123 | * Dissociates a device from a shareable DMA buffer 124 | * 125 | * @fd: [in] device file descriptor 126 | * @buf_fd: [in] buffer file descriptor 127 | * 128 | * Returns 0 on success, negative error code otherwise 129 | */ 130 | int 131 | atp_device_detach(const int fd, const int buf_fd); 132 | 133 | /* 134 | * Instructs ATP Engine to activate a stream of traffic profiles 135 | * Maps read and/or write buffers to device address space 136 | * This is a blocking call, puts caller to sleep until completion 137 | * Completion is signaled by an interrupt from the device 138 | * 139 | * @fd: [in] device file descriptor 140 | * @stream_id: [in] unique stream ID 141 | * @flow_id: [in] unique system flow ID 142 | * @read_fd: [in] read DMA buffer file descriptor 143 | * @write_fd: [in] write DMA buffer file descriptor 144 | * 145 | * Returns 0 on success, negative error code otherwise 146 | */ 147 | int 148 | atp_device_play_stream(const int fd, const uint64_t stream_id, 149 | const uint32_t flow_id, const int read_fd, 150 | const int write_fd); 151 | 152 | /* 153 | * Instructs ATP Engine to generate a unique, independet stream instance 154 | * The stream instance is associated to the device 155 | * 156 | * @fd: [in] device file descriptor 157 | * @stream_name: [in] stream name 158 | * @stream_id: [out] resulting unique stream ID 159 | * 160 | * Returns 0 on success, negative error code otherwise 161 | */ 162 | int 163 | atp_device_unique_stream(const int fd, const char *stream_name, 164 | uint64_t *stream_id); 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /logger.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 8, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | #include "logger.hh" 10 | #include 11 | 12 | namespace TrafficProfiles { 13 | 14 | Logger* Logger::instance = nullptr; 15 | 16 | const string Logger::RED = "\x1b[31m"; 17 | const string Logger::GREEN = "\x1b[32m"; 18 | const string Logger::YELLOW = "\x1b[33m"; 19 | const string Logger::BLUE = "\x1b[34m"; 20 | const string Logger::MAGENTA = "\x1b[35m"; 21 | const string Logger::CYAN = "\x1b[36m"; 22 | const string Logger::COLOR_RESET = "\x1b[0m"; 23 | 24 | 25 | Logger* Logger::get() { 26 | if (instance == nullptr) { 27 | #ifdef LOG_FILE 28 | // the global Logger entity, configured to log to file 29 | instance = new FileLogger(LOG_FILE, LOG_LEVEL); 30 | #else 31 | // the default global Logger entity, configured to log to standard output 32 | instance = new Logger(&cout, LOG_LEVEL); 33 | #endif 34 | } 35 | return instance; 36 | } 37 | 38 | FileLogger::FileLogger(const string& fileName, const Level lvl): 39 | Logger(&cout, LOG_LEVEL) { 40 | level = lvl; 41 | open(fileName); 42 | } 43 | 44 | FileLogger::~FileLogger() { 45 | if(out!=nullptr) { 46 | close(); 47 | delete out; 48 | } 49 | } 50 | 51 | void FileLogger::open(const string& fileName) 52 | { 53 | out = new ofstream(fileName.c_str(), ios_base::binary| ios_base::out); 54 | if( !dynamic_cast(out)->is_open() ) 55 | { 56 | throw(runtime_error("Logger: Unable to open file")); 57 | } 58 | } 59 | 60 | void FileLogger::close() 61 | { 62 | if(out && dynamic_cast(out)->is_open()) 63 | { 64 | dynamic_cast(out)->close(); 65 | } 66 | } 67 | 68 | 69 | } // end of namespace 70 | -------------------------------------------------------------------------------- /packet_tagger.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: 1 Mar 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #include "packet_tagger.hh" 11 | #include "logger.hh" 12 | 13 | namespace TrafficProfiles { 14 | 15 | // Packet metadata defaults set in header 16 | PacketTagger::PacketTagger(): currentId(0), low_id(0), high_id(0) {} 17 | 18 | PacketTagger::~PacketTagger() { 19 | } 20 | 21 | uint64_t 22 | PacketTagger::getId() { 23 | if (currentId high_id) { 28 | currentId = low_id; 29 | } 30 | 31 | LOG("PacketTagger::getId generated ID",currentId); 32 | // return and post-increment 33 | return currentId++; 34 | } 35 | 36 | uint64_t 37 | PacketTagger::getUid() { 38 | LOG("PacketTagger::getUid generated UID", currentUid); 39 | //return and post-increment 40 | return currentUid++; 41 | } 42 | 43 | void 44 | PacketTagger::tagGlobalPacket(Packet* pkt) { 45 | // global UID is always overwritten 46 | pkt->set_uid(getUid()); 47 | } 48 | 49 | void 50 | PacketTagger::tagPacket(Packet* pkt) { 51 | // set profile Packet flow_id if availalbe 52 | if (isValid(this->flow_id)) 53 | pkt->set_flow_id(flow_id); 54 | 55 | // set profile Packet iommu_id if availalbe 56 | if (isValid(this->iommu_id)) 57 | pkt->set_iommu_id(iommu_id); 58 | 59 | // set profile Packet stream_id if availalbe 60 | if (isValid(this->stream_id)) 61 | pkt->set_stream_id(stream_id); 62 | 63 | // check if profile has low and high ids to support tagging packets for Packet Desc 64 | if (isValid(this->low_id) && isValid(this->high_id)){ 65 | // set profile PacketID if not already set 66 | if (!pkt->has_id()) { 67 | pkt->set_id(getId()); 68 | } 69 | } 70 | } 71 | 72 | } /* namespace TrafficProfiles */ 73 | -------------------------------------------------------------------------------- /packet_tagger.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: 1 Mar 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef __AMBA_TRAFFIC_PROFILE_PACKET_TAGGER_HH__ 11 | #define __AMBA_TRAFFIC_PROFILE_PACKET_TAGGER_HH__ 12 | 13 | #include "proto/tp_packet.pb.h" 14 | #include "types.hh" 15 | 16 | namespace TrafficProfiles { 17 | 18 | /*! 19 | *\brief Implements the AMBA Traffic Profile Packets Tagger 20 | * 21 | * Tags ATP generated tagger with global configured fields 22 | * such as packet ID 23 | */ 24 | class PacketTagger { 25 | 26 | protected: 27 | //! current packet ID value 28 | uint64_t currentId; 29 | 30 | //! current packet Unique ID (UID) value 31 | uint64_t currentUid; 32 | 33 | /*! 34 | * Generates a new packet ID 35 | *\return a new packet ID 36 | */ 37 | uint64_t getId(); 38 | 39 | /*! 40 | * Generates a new packet UID 41 | *\return a new packet UID 42 | */ 43 | uint64_t getUid(); 44 | 45 | public: 46 | //! packet lowest ID value 47 | uint64_t low_id{ InvalidId() }; 48 | //! packet highest ID value 49 | uint64_t high_id{ InvalidId() }; 50 | //! flow_id value for profile packet tagging 51 | uint64_t flow_id{ InvalidId() }; 52 | //! iommu_id value for profile packet tagging 53 | uint32_t iommu_id{ InvalidId() }; 54 | //! stream_id value for profile packet tagging 55 | uint64_t stream_id{ InvalidId() }; 56 | 57 | 58 | //! default constructor 59 | PacketTagger(); 60 | //! default destructor 61 | virtual ~PacketTagger(); 62 | 63 | /*! 64 | * Reset PacketTagger currentID counter when reusing PacketTagger 65 | */ 66 | inline void resetCurrentId (){ this->currentId = 0; }; 67 | 68 | /*! 69 | * Tags a packet with profile 70 | * configured fields such as iommu_id or flow_id 71 | *\param pkt pointer to the packet to be tagged 72 | */ 73 | void tagPacket(Packet*); 74 | 75 | /*! 76 | * Tags a packet with globally 77 | * configured fields 78 | *\param pkt pointer to the packet to be tagged 79 | */ 80 | void tagGlobalPacket(Packet*); 81 | }; 82 | 83 | } /* namespace TrafficProfiles */ 84 | 85 | #endif /* __AMBA_TRAFFIC_PROFILE_PACKET_TAGGER_HH__ */ 86 | -------------------------------------------------------------------------------- /packet_tracer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2017 ARM Limited 5 | * All rights reserved 6 | * Author: Matteo Andreozzi 7 | */ 8 | 9 | #include 10 | #include "packet_tracer.hh" 11 | #include "logger.hh" 12 | #include "traffic_profile_manager.hh" 13 | #include "utilities.hh" 14 | 15 | namespace TrafficProfiles { 16 | 17 | const string PacketTracer::traceExt = ".trace"; 18 | 19 | 20 | PacketTracer::PacketTracer(TrafficProfileManager* t): tpm(t), enabled(false), 21 | timeUnit(Configuration::S),latencyUnit(Configuration::NS) { 22 | // load packet command names 23 | for (uint64_t i = 0; i < TrafficProfiles::Command_ARRAYSIZE; ++i) { 24 | traceName[i] = Command_Name(Command(i)); 25 | } 26 | // add additional trace names 27 | traceName[OT] = "OT"; 28 | traceName[LATENCY] = "LATENCY"; 29 | } 30 | 31 | PacketTracer::~PacketTracer() { 32 | // close all open descriptors 33 | for (auto&m : traces) { 34 | for (auto& os : m.second) { 35 | os.close(); 36 | } 37 | } 38 | } 39 | 40 | void PacketTracer::setOutDir(const string& dir) { 41 | outDir = Utilities::buildPath(dir); 42 | } 43 | 44 | array& PacketTracer::getTraceFiles(const uint64_t mId) { 45 | 46 | if (traces.find(mId)==traces.end()) { 47 | // create the output directory if it does not exist yet 48 | mkdir(outDir.c_str(), S_IRWXU|S_IRWXG); 49 | // calculate base trace name 50 | auto masterName = tpm->masterName(mId); 51 | // create packet types traces 52 | for (uint64_t t=0; t < TYPES; t++) { 53 | const string fullPath = Utilities::buildPath(outDir, 54 | masterName+"."+traceName[t]+traceExt); 55 | traces[mId][t].open(fullPath, ofstream::out); 56 | if (traces[mId][t].is_open()) 57 | { 58 | LOG("PacketTracer::getTraceFiles opened trace",fullPath); 59 | } else { 60 | ERROR("PacketTracer::getTraceFiles failed to open trace",fullPath); 61 | } 62 | } 63 | LOG("PacketTracer::getTraceFiles created traces for master", masterName); 64 | } 65 | 66 | return traces[mId]; 67 | } 68 | 69 | void PacketTracer::trace(const Packet* const pkt) { 70 | if (enabled) { 71 | 72 | // get numerical master ID 73 | const uint64_t mId = tpm->masterId(pkt->master_id()); 74 | // access/create trace files 75 | auto& masterTraces = getTraceFiles(mId); 76 | 77 | // load the time scale to report times in the configured time unit 78 | const double timeScale = 79 | tpm->toFrequency(tpm->getTimeResolution())/tpm->toFrequency(timeUnit); 80 | 81 | auto trace_prefix = 82 | [pkt, timeScale](std::ofstream &out) -> std::ofstream & { 83 | out << static_cast(pkt->time()) / timeScale << " " 84 | << " 0x" << std::hex << pkt->addr() << std::dec << " "; 85 | return out; 86 | }; 87 | 88 | // write the time trace point 89 | trace_prefix(masterTraces[pkt->cmd()]) << pkt->size() << std::endl; 90 | 91 | LOG("PacketTracer::trace tracing master", 92 | pkt->master_id(), "packet uid",pkt->uid(), 93 | "type", Command_Name(pkt->cmd()), "address", 94 | Utilities::toHex(pkt->addr()),"size", pkt->size()); 95 | 96 | // write a time/latency trace if the packet was awaited by the TPM 97 | double delay=tpm->getTime(), requestTime=tpm->getTime(); 98 | uint64_t destId = 0; 99 | // the packet was waited for 100 | if (tpm->getDestinationProfile(requestTime, destId, pkt)) { 101 | // compute latency in ATP time (current ATP time - requestTime) 102 | delay-=requestTime; 103 | 104 | // get the latency default scale factor 105 | const double latencyScale = tpm->toFrequency(latencyUnit); 106 | 107 | // compute the latency value using the latency time unit, then truncate to int 108 | const double latency = (int)((double)(delay)/ 109 | (tpm->toFrequency(tpm->getTimeResolution())/latencyScale)); 110 | 111 | LOG("PacketTracer::trace tracing master", pkt->master_id(), "packet uid", pkt->uid(), 112 | "request time", requestTime, "delay (", Configuration::TimeUnit_Name(tpm->getTimeResolution()) 113 | ,")", delay, "latency (",Configuration::TimeUnit_Name(latencyUnit),")",latency); 114 | 115 | trace_prefix(masterTraces[LATENCY]) << latency << std::endl; 116 | 117 | // acquire the current master OT count and trace it 118 | trace_prefix(masterTraces[OT]) << tpm->getOt(destId) << std::endl; 119 | } 120 | } 121 | } 122 | 123 | } /* namespace TrafficProfiles */ 124 | -------------------------------------------------------------------------------- /packet_tracer.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2017 ARM Limited 5 | * All rights reserved 6 | * Author: Matteo Andreozzi 7 | */ 8 | 9 | #ifndef __AMBA_TRAFFIC_PROFILE_PACKET_TRACER_HH__ 10 | #define __AMBA_TRAFFIC_PROFILE_PACKET_TRACER_HH__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "proto/tp_config.pb.h" 16 | #include "proto/tp_packet.pb.h" 17 | 18 | 19 | using namespace std; 20 | 21 | namespace TrafficProfiles { 22 | 23 | class TrafficProfileManager; 24 | 25 | /*! 26 | *\brief Implements the AMBA Traffic Profile Packets Tracer 27 | * 28 | * Traces ATP generated packets to files 29 | */ 30 | class PacketTracer { 31 | 32 | protected: 33 | //! additional traces types - extend the packet commands 34 | enum TraceType { 35 | OT = Command_ARRAYSIZE, 36 | LATENCY, 37 | TYPES 38 | }; 39 | 40 | //! Trace file extension 41 | static const string traceExt; 42 | 43 | //! Pointer to the TPM 44 | TrafficProfileManager* const tpm; 45 | 46 | //! Global enable flag 47 | bool enabled; 48 | 49 | //! all traces time unit 50 | Configuration::TimeUnit timeUnit; 51 | 52 | //! latency trace value time unit 53 | Configuration::TimeUnit latencyUnit; 54 | 55 | //! Trace types enum to name 56 | array traceName; 57 | 58 | //! Trace files output directory 59 | string outDir; 60 | 61 | //! Open files descriptors, per master id, one per packet command plus additional types 62 | map > traces; 63 | 64 | /*! 65 | * Returns trace file descriptors given a master id 66 | * if the traces do not exist, it creates them 67 | *\param mId master id 68 | *\return an array of ofstream, one per trace type 69 | */ 70 | array& getTraceFiles(const uint64_t); 71 | 72 | public: 73 | /*! 74 | * Constructor 75 | *\param t pointer to TPM 76 | */ 77 | PacketTracer(TrafficProfileManager*); 78 | 79 | //! default destructor 80 | virtual ~PacketTracer(); 81 | 82 | /*! 83 | * Traces a packet to file 84 | *\param pkt pointer to the packet to be traced 85 | */ 86 | void trace(const Packet* const); 87 | 88 | /*! 89 | * Set the output directory name 90 | *\param dir directory name 91 | */ 92 | void setOutDir(const string& dir); 93 | 94 | /*! 95 | * Sets all traces time unit 96 | *\param t time unit to set 97 | */ 98 | inline void setTimeUnit(const Configuration::TimeUnit t) {timeUnit=t;} 99 | 100 | /*! 101 | * Sets the latency time unit 102 | *\param l latency time unit to set 103 | */ 104 | inline void setLatencyUnit(const Configuration::TimeUnit l) {latencyUnit=l;} 105 | 106 | /*! 107 | * Enables the tracer 108 | */ 109 | inline void enable() {enabled=true;} 110 | }; 111 | 112 | } /* namespace TrafficProfiles */ 113 | 114 | #endif /* __AMBA_TRAFFIC_PROFILE_PACKET_TRACER_HH__ */ 115 | -------------------------------------------------------------------------------- /proto/SConscript: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | 3 | # SPDX-License-Identifier: BSD-3-Clause-Clear 4 | # 5 | # Copyright (c) 2012, 2021 ARM Limited 6 | # All rights reserved. 7 | # Authors: Matteo Andreozzi 8 | # Adrian Herrera 9 | 10 | Import('*') 11 | 12 | # Only build if we have protobuf support 13 | if env['CONF']['HAVE_PROTOBUF']: 14 | ProtoBuf('tp_config.proto') 15 | ProtoBuf('tp_packet.proto') 16 | ProtoBuf('tp_stats.proto') 17 | 18 | -------------------------------------------------------------------------------- /proto/tp_packet.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | // 3 | // Copyright (c) 2012-2013 ARM Limited 4 | // All rights reserved 5 | // Authors: Matteo Andreozzi 6 | syntax = "proto2"; 7 | // Put all the generated messages in a namespace 8 | package TrafficProfiles; 9 | 10 | enum Command { 11 | INVALID = 0; 12 | NONE = 1; 13 | READ_REQ = 2; 14 | WRITE_REQ = 3; 15 | READ_RESP = 4; 16 | WRITE_RESP= 5; 17 | } 18 | 19 | // packet data structure generated by the Traffic Profile Generator 20 | message Packet { 21 | required Command cmd = 1; 22 | required uint64 time = 2; 23 | required uint64 addr = 3; 24 | required uint64 size = 4; 25 | required string master_id = 5; 26 | optional uint64 id = 6; 27 | required uint64 uid = 7 [default = 0]; 28 | optional uint64 stream_id = 8; 29 | optional uint32 iommu_id = 9; 30 | optional uint64 flow_id = 10; 31 | } 32 | -------------------------------------------------------------------------------- /proto/tp_stats.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause-Clear 2 | // 3 | // Copyright (c) 2012-2013 ARM Limited 4 | // All rights reserved 5 | // Authors: Matteo Andreozzi 6 | syntax = "proto2"; 7 | // Put all the generated messages in a namespace 8 | package TrafficProfiles; 9 | 10 | // Google Protocol Buffer Object used to export statistics to the host 11 | // platform 12 | message StatObject { 13 | // time since when statistics started 14 | required uint64 start = 1; 15 | // last time statistics were recorded 16 | required uint64 time = 2; 17 | // total packet sent counter 18 | required uint64 sent = 3; 19 | // total packet received counter 20 | required uint64 received = 4; 21 | // how many data have been generated 22 | required uint64 dataSent = 5; 23 | // how many data have been received 24 | required uint64 dataReceived = 6; 25 | // average response latency 26 | required double latency = 7; 27 | // average response jitter 28 | required double jitter = 8; 29 | // send rate 30 | required double sendRate = 9; 31 | // receive rate 32 | required double receiveRate = 10; 33 | // FIFO buffer underruns 34 | required uint64 underruns = 11; 35 | // FIFO buffer overruns 36 | required uint64 overruns = 12; 37 | // Average outstanding transactions 38 | required uint64 ot = 13; 39 | // Average FIFO level 40 | required uint64 fifoLevel = 14; 41 | } 42 | -------------------------------------------------------------------------------- /random_generator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 2, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #include "random_generator.hh" 11 | 12 | #include "logger.hh" 13 | 14 | namespace TrafficProfiles { 15 | 16 | namespace Random { 17 | 18 | Generator::Generator(const uint64_t s): 19 | initialized(false), 20 | type(RandomDesc::UNIFORM), 21 | distribution(nullptr), 22 | seed(s) { 23 | mersenne.seed(seed); 24 | } 25 | 26 | Generator::~Generator() { 27 | delete distribution; 28 | } 29 | 30 | void Generator::init(const RandomDesc::Type t, 31 | const uint64_t base, const uint64_t range) { 32 | // clean previously allocated generators 33 | delete distribution; 34 | // set new type 35 | type = t; 36 | 37 | switch(type) 38 | { 39 | case RandomDesc::UNIFORM: { 40 | distribution = new Uniform(this, base, range); 41 | break; 42 | } 43 | case RandomDesc::NORMAL: { 44 | distribution = new Normal(this, base, range); 45 | break; 46 | } 47 | case RandomDesc::POISSON: { 48 | distribution = new Poisson(this, base, range); 49 | break; 50 | } 51 | case RandomDesc::WEIBULL: { 52 | distribution = new Weibull(this, base, range); 53 | break; 54 | } 55 | default: 56 | ERROR("Generator::init unknown random generator type", RandomDesc::Type_Name(type)); 57 | break; 58 | } 59 | LOG("Generator::init",RandomDesc::Type_Name(type),"generator initialised with base", 60 | base, "range", range); 61 | 62 | initialized = true; 63 | } 64 | 65 | void Generator::init(const RandomDesc& from) { 66 | 67 | // clean previously allocated generators 68 | delete distribution; 69 | 70 | type = from.type(); 71 | 72 | switch(type) 73 | { 74 | case RandomDesc::UNIFORM: { 75 | distribution = new Uniform(this, from); 76 | break; 77 | } 78 | case RandomDesc::NORMAL: { 79 | distribution = new Normal(this, from); 80 | break; 81 | } 82 | case RandomDesc::POISSON: { 83 | distribution = new Poisson(this, from); 84 | break; 85 | } 86 | case RandomDesc::WEIBULL: { 87 | distribution = new Weibull(this, from); 88 | break; 89 | } 90 | default: 91 | ERROR("Generator::init unknown random generator type", RandomDesc::Type_Name(type)); 92 | break; 93 | } 94 | LOG("Generator::init",RandomDesc::Type_Name(type),"generator initialised from descriptor"); 95 | 96 | initialized = true; 97 | } 98 | 99 | uint64_t Generator::get() { 100 | uint64_t ret = 0; 101 | if (initialized) { 102 | ret = distribution->get(); 103 | LOG("Generator::get generated",RandomDesc::Type_Name(type),"value", ret); 104 | } else { 105 | ERROR("RandomGenerator::get uninitialised"); 106 | } 107 | return ret; 108 | } 109 | 110 | Uniform::Uniform(Generator* const gen, const uint64_t base, const uint64_t range): 111 | Distribution(gen, base, range) { 112 | uint64_t min = base, max = base + range; 113 | uniform = new uniform_int_distribution(min,max); 114 | } 115 | 116 | Uniform::Uniform(Generator* const gen, const RandomDesc& from): 117 | Distribution(gen) { 118 | uint64_t min = from.uniform_desc().min(), max = from.uniform_desc().max(); 119 | uniform = new uniform_int_distribution(min,max); 120 | } 121 | 122 | uint64_t Uniform::get() { 123 | return (*uniform)(generator->mersenne); 124 | } 125 | 126 | Normal::Normal(Generator* const gen, const uint64_t base, const uint64_t range): 127 | Distribution(gen, base, range) { 128 | double dev = range/2, mean = base + dev; 129 | normal = new normal_distribution(mean,dev); 130 | } 131 | 132 | Normal::Normal(Generator* const gen, const RandomDesc& from): 133 | Distribution(gen) { 134 | double mean = from.normal_desc().mean(), dev = from.normal_desc().std_dev(); 135 | normal = new normal_distribution(mean,dev); 136 | } 137 | 138 | uint64_t Normal::get() { 139 | return (*normal)(generator->mersenne); 140 | } 141 | Poisson::Poisson(Generator* const gen, const uint64_t base, const uint64_t range): 142 | Distribution(gen, base, range) { 143 | double mean = base + range/2; 144 | poisson = new poisson_distribution(mean); 145 | } 146 | 147 | Poisson::Poisson(Generator* const gen, const RandomDesc& from): 148 | Distribution(gen) { 149 | double mean = from.poisson_desc().mean(); 150 | poisson = new poisson_distribution(mean); 151 | } 152 | 153 | uint64_t Poisson::get() { 154 | return (*poisson)(generator->mersenne); 155 | } 156 | 157 | Weibull::Weibull(Generator* const gen, const uint64_t base, const uint64_t range): 158 | Distribution(gen, base, range) { 159 | // todo should we work scale and shape out from GAMMA ? 160 | double scale = base + range/2, shape = 0; 161 | weibull = new weibull_distribution(shape, scale); 162 | } 163 | 164 | Weibull::Weibull(Generator* const gen, const RandomDesc& from): 165 | Distribution(gen) { 166 | double shape = from.weibull_desc().shape(), scale = from.weibull_desc().scale(); 167 | weibull = new weibull_distribution(shape,scale); 168 | } 169 | 170 | uint64_t Weibull::get() { 171 | return (*weibull)(generator->mersenne); 172 | } 173 | 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /stats.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 8, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #include "stats.hh" 11 | #include "utilities.hh" 12 | #include 13 | #include 14 | 15 | namespace TrafficProfiles { 16 | 17 | Stats::Stats(): 18 | started(false), startTime(numeric_limits::max()), 19 | timeScale(1), time(0), 20 | sent(0), received(0), dataSent(0), 21 | dataReceived(0), prevLatency(.0), jitter(.0), 22 | latency(.0), underruns(0), overruns(0), 23 | ot(0), otN(0), fifoLevel(0), 24 | fifoLevelN(0) { 25 | } 26 | 27 | Stats::~Stats() { 28 | } 29 | 30 | void Stats::setTime(const uint64_t t){ 31 | // going backwards in time is prevented 32 | if (t >= time) { 33 | time = t; 34 | } 35 | } 36 | 37 | void 38 | Stats::send (const uint64_t t, const uint64_t data, const uint64_t o) { 39 | // set start time if required 40 | start(t); 41 | // advance time if necessary 42 | setTime(t); 43 | // record event 44 | sent++; 45 | dataSent +=data; 46 | // update the OT count 47 | ot+=o; 48 | // update OT sample count only when increasing it 49 | otN++; 50 | } 51 | 52 | void 53 | Stats::receive (const uint64_t t,const uint64_t data, const double l) { 54 | // set start time if required 55 | start(t); 56 | // advance time if necessary 57 | setTime(t); 58 | // record event 59 | received++; 60 | dataReceived +=data; 61 | 62 | /* 63 | * Jitter is computer iteratively based on RFC 1889 January 1996 64 | * 65 | * https://datatracker.ietf.org/doc/rfc1889/?include_text=1 66 | * 67 | * On nth packet reception, 68 | * the latency variation is added to the current jitter 69 | * following the formula: 70 | * 71 | * J=J+(|D(n-1,n)|-J)/16 72 | * 73 | * This algorithm is the optimal first-order estimator 74 | * and the gain parameter 1/16 gives a good noise 75 | * reduction ratio while maintaining a 76 | * reasonable rate of convergence 77 | */ 78 | jitter += ((fabs(l-prevLatency) - jitter)/16); 79 | prevLatency = l; 80 | latency += l; 81 | } 82 | 83 | void 84 | Stats::fifoUpdate(const uint64_t l, const bool u, const bool o) { 85 | fifoLevel += l; 86 | fifoLevelN++; 87 | if (u) underruns++; 88 | if (o) overruns++; 89 | } 90 | 91 | const string 92 | Stats::dump() const { 93 | stringstream ss; 94 | ss << "start time: " << Utilities::toTimeString((double)startTime/(double)timeScale) 95 | << " finish time: " << Utilities::toTimeString(getTime()) 96 | << " sent: " << sent 97 | << " received: " << received 98 | << " data sent: " << Utilities::toByteString(dataSent) 99 | << " data received: " << Utilities::toByteString(dataReceived) 100 | << " avg response latency: " << Utilities::toTimeString(avgLatency()) 101 | << " avg response jitter: " << Utilities::toTimeString(avgJitter()) 102 | << " send rate:" << Utilities::toByteString(sendRate()) << "ps" 103 | << " receive rate: " << Utilities::toByteString(receiveRate()) << "ps" 104 | << " average OT: " << avgOt() 105 | << " average FIFO level: " << avgFifoLevel() 106 | << " FIFO underruns: " << underruns 107 | << " FIFO overruns: " << overruns; 108 | return ss.str(); 109 | } 110 | 111 | const StatObject* 112 | Stats::xport() const { 113 | StatObject* ret = new StatObject(); 114 | ret->set_start(getStartTime()); 115 | ret->set_time(getTime()); 116 | ret->set_sent(sent); 117 | ret->set_received(received); 118 | ret->set_datasent(dataSent); 119 | ret->set_datareceived(dataReceived); 120 | ret->set_latency(avgLatency()); 121 | ret->set_jitter(avgJitter()); 122 | ret->set_receiverate(receiveRate()); 123 | ret->set_sendrate(sendRate()); 124 | ret->set_underruns(underruns); 125 | ret->set_overruns(overruns); 126 | ret->set_ot(avgOt()); 127 | ret->set_fifolevel(avgFifoLevel()); 128 | return ret; 129 | } 130 | 131 | Stats Stats::operator+(const Stats& s) { 132 | Stats ret; 133 | // all stats objects should have the same time scale factor 134 | assert(this->timeScale == s.timeScale); 135 | ret.started = (s.started | this->started); 136 | ret.startTime = min(this->startTime, s.startTime); 137 | ret.timeScale = this->timeScale; 138 | ret.time = max(this->time, s.time); 139 | ret.sent = this->sent + s.sent; 140 | ret.received = this->received + s.received; 141 | ret.dataSent = this->dataSent + s.dataSent; 142 | ret.dataReceived = this->dataReceived + s.dataReceived; 143 | ret.latency = this->latency + s.latency; 144 | ret.jitter = this->jitter + s.jitter; 145 | ret.underruns = this->underruns + s.underruns; 146 | ret.overruns = this->overruns + s.overruns; 147 | ret.ot = this->ot + s.ot; 148 | ret.otN = this->otN + s.otN; 149 | ret.fifoLevel = this->fifoLevel + s.fifoLevel; 150 | ret.fifoLevelN = this->fifoLevelN + s.fifoLevelN; 151 | return ret; 152 | } 153 | 154 | Stats& Stats::operator+=(const Stats& s) { 155 | *this = *this + s; 156 | return *this; 157 | } 158 | 159 | } /* namespace TrafficProfiles */ 160 | -------------------------------------------------------------------------------- /stats.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 19, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef _AMBA_TRAFFIC_PROFILE_STATS_HH_ 11 | #define _AMBA_TRAFFIC_PROFILE_STATS_HH_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "proto/tp_stats.pb.h" 19 | 20 | using namespace std; 21 | 22 | namespace TrafficProfiles { 23 | /*! 24 | *\brief Statistics collection class 25 | * 26 | * This class provides methods and storage to collect and store statistics 27 | * at any level in the ATP hierarchy. It can also export recorded values 28 | * as Google Protocol Buffer objects 29 | */ 30 | class Stats { 31 | //! started flag : signals that the start time has been initialised 32 | bool started; 33 | 34 | public: 35 | //! Start time since when stats are computed 36 | uint64_t startTime; 37 | //! Time scale factor: used to export time in seconds 38 | uint64_t timeScale; 39 | //! last time statistics were recorded 40 | uint64_t time; 41 | //! total packet sent counter 42 | uint64_t sent; 43 | //! total packet received counter 44 | uint64_t received; 45 | //! how many data have been generated 46 | uint64_t dataSent; 47 | //! how many data have been received 48 | uint64_t dataReceived; 49 | //! previous latency - used to compute jitter 50 | double prevLatency; 51 | //! cumulative response jitter 52 | double jitter; 53 | //! cumulative response latency 54 | double latency; 55 | //! FIFO buffer underruns 56 | uint64_t underruns; 57 | //! FIFO buffer overruns 58 | uint64_t overruns; 59 | 60 | //! Cumulative OT (CurTxn) 61 | uint64_t ot; 62 | //! Number of OT measurements 63 | uint64_t otN; 64 | 65 | //! Cumulative FIFO level (CurLvl) 66 | uint64_t fifoLevel; 67 | 68 | //! Number of FIFO level measurements 69 | uint64_t fifoLevelN; 70 | 71 | //! Default Constructor 72 | Stats(); 73 | //! Default destructor 74 | virtual ~Stats(); 75 | /*! 76 | * records a send event 77 | *\param t the time the event occurred 78 | *\param data the amount of data sent 79 | *\param o outstanding transactions 80 | */ 81 | void send (const uint64_t, const uint64_t, const uint64_t=0); 82 | /*! 83 | * records a receive event 84 | *\param t the time the event occurred 85 | *\param data the amount of data received 86 | *\param l the latency measured for this data reception 87 | */ 88 | void receive (const uint64_t, const uint64_t, const double); 89 | 90 | /*! 91 | * records a FIFO update event 92 | *\param l the FIFO level 93 | *\param u whether the FIFO did underrun 94 | *\param o whether the FIFO did overrun 95 | */ 96 | void fifoUpdate(const uint64_t, const bool, const bool); 97 | 98 | //! resets all statistics counters 99 | inline void reset() {started=false, startTime=numeric_limits::max(), time=0, 100 | sent=0, received=0, dataSent=0, 101 | dataReceived=0, prevLatency=.0, jitter=.0, latency=.0, 102 | underruns=0, overruns=0, ot=0, otN=0, fifoLevel=0, 103 | fifoLevelN=0;} 104 | 105 | /*! 106 | * Starts the statistics from the given time, 107 | * if not already started 108 | *\param t start time 109 | */ 110 | inline void start(const uint64_t t) { if (!started) {started=true; startTime=t;}} 111 | 112 | /*! 113 | * Advances the time to a specific value 114 | * going backwards in time is prevented 115 | *\param t time to set 116 | */ 117 | void setTime(const uint64_t); 118 | 119 | /*! 120 | * Dumps statistics 121 | *\return a formatted string with all statistics 122 | */ 123 | const string dump() const; 124 | /*! 125 | * Method to compute and get the rate for sent data 126 | *\return the data rate 127 | */ 128 | inline double sendRate () const 129 | { return (time? (double)dataSent/((double)time - (double)startTime)*timeScale:0); } 130 | /*! 131 | * Method to compute and get the rate for received data 132 | *\return the data rate 133 | */ 134 | inline double receiveRate () const 135 | { return (time? (double)dataReceived/((double)time - (double)startTime)*timeScale:0);} 136 | /* 137 | * Method to compute and get the average response latency 138 | *\return the average response latency 139 | */ 140 | inline double avgLatency() const 141 | { return latency/(double)(timeScale * received); } 142 | 143 | /* 144 | * Method to compute and get the request to response jitter 145 | *\return the computed response jitter 146 | */ 147 | inline double avgJitter() const 148 | { return jitter/(double)(timeScale); } 149 | 150 | /* 151 | * Method to compute and get the average OT 152 | *\return the average OT count 153 | */ 154 | inline uint64_t avgOt() const { return otN ? ceil((double)ot/(double)otN) : 0;} 155 | 156 | /* 157 | * Method to compute and get the average FIFO level 158 | *\return the average FIFO level 159 | */ 160 | inline uint64_t avgFifoLevel() const {return fifoLevelN ? (fifoLevel/fifoLevelN) : 0;} 161 | 162 | /*! 163 | * Method to compute and return the stats finish time 164 | *\return the stats time in seconds 165 | */ 166 | inline double getTime() const {return (double)time/(double)timeScale;} 167 | 168 | /*! 169 | * Method to compute and return the stats start time 170 | *\return the stats time in seconds 171 | */ 172 | inline double getStartTime() const {return (double)startTime/(double)timeScale;} 173 | 174 | /*! 175 | * Exports statistics as Google Protocol Buffer object 176 | *\return a Google Protocol Buffer StatObject 177 | */ 178 | const StatObject* xport() const; 179 | 180 | /*! 181 | * Sum operator: merges two Stats objects 182 | *\param s the Stats object to add 183 | *\return the sum by value 184 | */ 185 | Stats operator+(const Stats&); 186 | 187 | /*! 188 | * Add operator: adds Stats objects 189 | * fields to this one 190 | *\param s the Stats object to add 191 | *\return this object by reference 192 | */ 193 | Stats& operator+=(const Stats&); 194 | }; 195 | 196 | } /* namespace TrafficProfiles */ 197 | 198 | #endif /* _AMBA_TRAFFIC_PROFILE_STATS_HH_ */ 199 | -------------------------------------------------------------------------------- /test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Sep 30, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | // standard library includes 10 | #include 11 | #include 12 | #include 13 | // cpp unit includes 14 | #include 15 | #include 16 | 17 | #include "test_atp.hh" 18 | 19 | // logger and tools 20 | #include "logger.hh" 21 | #include "utilities.hh" 22 | 23 | // interactive shell 24 | #include "shell.hh" 25 | 26 | using namespace TrafficProfiles; 27 | using namespace std; 28 | 29 | /* 30 | * Prints the command line options and exits 31 | */ 32 | void usage() { 33 | 34 | PRINT( "\n " 35 | "******** ATP ENGINE *******\n", 36 | "** by Matteo Andreozzi **\n", 37 | "*************************\n\n", 38 | "Usage: file1.atp file2.atp\n", 39 | "\t -v (--verbose) : enables debug logging\n", 40 | "\t -b (--bandwidth) : configures the memory bandwidth\n", 41 | "\t -l (--latency) : configures the memory latency\n", 42 | "\t -p (--profiles-as-masters): instantiates one ATP master per ATP FIFO\n", 43 | "\t -t (--trace) : enables tracing to the specified directory\n" 44 | "\t -i (--interactive): starts the Engine in interactive shell mode\n" 45 | "\t -? or -h (--help): Prints usage and exits\n\n", 46 | "No file arguments: runs self-tests\n"); 47 | } 48 | 49 | // instantiate test suite 50 | TestAtp test; 51 | 52 | void signalHandler( int signum ) { 53 | PRINT("Interrupt signal (",signum,") received"); 54 | 55 | // print statistics and exit 56 | 57 | test.dumpStats(); 58 | 59 | exit(signum); 60 | } 61 | 62 | int main(int argc, char* argv[]) { 63 | 64 | // enable colours 65 | Logger::get()->setColours(true); 66 | // register signal handler 67 | signal(SIGINT, signalHandler); 68 | 69 | // default parameters 70 | const string defaultBandwidth = "32GB/s"; 71 | const string defaultLatency = "80ns"; 72 | const string defaultTraceDir = "out"; 73 | // option flags and index counters 74 | int opt = 0, option_index = 0; 75 | int verbose_flag=0, trace_flag=0, 76 | interactive_flag=0, profiles_as_masters_flag=0; 77 | 78 | // long options vector 79 | option long_options[] = 80 | { 81 | {"interactive", no_argument, &interactive_flag, 1}, 82 | {"verbose", no_argument, &verbose_flag, 1}, 83 | {"help", no_argument, 0, '?'}, 84 | {"help", no_argument, 0, 'h'}, 85 | {"profiles-as-masters", no_argument, 0, 'p'}, 86 | {"latency", required_argument, 0, 'l'}, 87 | {"bandwidth", required_argument, 0, 'b'}, 88 | {"trace", optional_argument, &trace_flag, 1}, 89 | {0, 0, 0, 0} 90 | }; 91 | 92 | 93 | // set defaults 94 | string bandwidth(defaultBandwidth); 95 | string latency(defaultLatency); 96 | string traceDir(defaultTraceDir); 97 | 98 | // parse options 99 | while ((opt = getopt_long(argc,argv,":ivpb:l:t:?h", 100 | long_options, &option_index)) != EOF) { 101 | switch(opt) 102 | { 103 | case 0: { 104 | // long option set - nothing to do 105 | break; 106 | } 107 | case 'i': { 108 | interactive_flag=1; 109 | break; 110 | } 111 | 112 | case 'p':{ 113 | profiles_as_masters_flag=1; 114 | break; 115 | } 116 | 117 | case 'v': { 118 | verbose_flag = 1; 119 | break; 120 | } 121 | case 'b': { 122 | // assign value 123 | bandwidth = optarg; 124 | break; 125 | } 126 | case 'l': { 127 | latency = optarg; 128 | break; 129 | } 130 | case 't': { 131 | trace_flag = 1; 132 | if (optarg){ 133 | traceDir = optarg; 134 | } 135 | break; 136 | } 137 | case 'h': 138 | case '?': /* intentional fallthrough */ 139 | default: 140 | { 141 | // print usage and exit 142 | usage(); 143 | exit(0); 144 | } 145 | } 146 | } 147 | 148 | // handle flag 149 | if (verbose_flag) { 150 | // enable logging 151 | Logger::get()->setLevel(Logger::DEBUG_LEVEL); 152 | LOG("ATP Engine: Debug logging enabled from command line"); 153 | } 154 | 155 | // interactive mode bypasses self-tests and profiles loading 156 | 157 | if (interactive_flag) { 158 | Shell::get()->setTest(&test); 159 | Shell::get()->loop(); 160 | } else if (optind == argc) { 161 | // if no command line files are provided 162 | // run self-tests 163 | CppUnit::TextUi::TestRunner runner; 164 | LOG("ATP Engine: Creating Test Suites"); 165 | runner.addTest(TestAtp::suite()); 166 | LOG("ATP Engine: Running the unit tests"); 167 | runner.run(); 168 | } else { 169 | // handle trace flag 170 | if (trace_flag) { 171 | test.getTpm()->enableTracer(traceDir); 172 | } 173 | 174 | // handle profiles as masters flag 175 | if (profiles_as_masters_flag) { 176 | test.getTpm()->enableProfilesAsMasters(); 177 | } 178 | 179 | for (int i = optind; i < argc; ++i) 180 | { 181 | if (test.buildManager_fromFile(argv[i])) { 182 | LOG("ATP Engine: loading profiles from file", argv[i]); 183 | } else { 184 | ERROR("ATP Engine: unable to load file", argv[i]); 185 | } 186 | } 187 | 188 | // start the test 189 | test.testAgainstInternalSlave(bandwidth, latency); 190 | // cleanup 191 | test.tearDown(); 192 | } 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /test_atp.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2015 ARM Limited 5 | * All rights reserved 6 | * Created on: Oct 19, 2015 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef _AMBA_TRAFFIC_PROFILE_TEST_ATP_HH_ 11 | #define _AMBA_TRAFFIC_PROFILE_TEST_ATP_HH_ 12 | 13 | // std includes 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Unit test suit includes 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | // ATP includes 30 | 31 | #include "logger.hh" 32 | #include "traffic_profile_manager.hh" 33 | 34 | using namespace std; 35 | 36 | namespace TrafficProfiles { 37 | /*! 38 | *\brief Unit Tests class for ATP 39 | * 40 | * Implements Unit Test to validate the ATP implementation, 41 | */ 42 | class TestAtp : public CppUnit::TestFixture { 43 | 44 | private: 45 | //! pointer to ATP traffic profile manager 46 | TrafficProfileManager* tpm; 47 | //! Google Protocol Buffer ATP manager configuration objects 48 | Configuration* configuration; 49 | 50 | struct ProfileDescription { 51 | const string name; 52 | const Profile::Type type; 53 | const string *const master; 54 | const list *const waitFor; 55 | // iommu_id and flow_id have no default values in constructor as they 56 | // are optional fields 57 | uint64_t iommu_id; 58 | uint64_t flow_id; 59 | ProfileDescription(const string &n, const Profile::Type &t, 60 | const string *const m=nullptr, 61 | const list *const wf=nullptr) 62 | : name { n }, type { t }, master { m }, waitFor { wf } { } 63 | }; 64 | 65 | public: 66 | //! Default Constructor 67 | TestAtp(); 68 | //! Default Destructor 69 | virtual ~TestAtp(); 70 | 71 | //! Creates a CppUnit test suite 72 | static CppUnit::TestSuite* suite(); 73 | 74 | //! Unit Tests setup method 75 | void setUp(); 76 | 77 | //! Unit Tests tear down method 78 | void tearDown(); 79 | 80 | //! Dumps the TPM Stats 81 | void dumpStats(); 82 | 83 | //! returns a pointer to the stored TPM - creates it if needed 84 | inline TrafficProfileManager* getTpm() { 85 | if (nullptr == tpm) { tpm = new TrafficProfileManager(); } return tpm;} 86 | 87 | protected: 88 | 89 | /*! 90 | * Configures a Packet Configuration 91 | *\param t the Packet Configuration to be configured 92 | *\param cmd the Packet Command to be used for generating packets 93 | *\param wait the Packet Command related to responses waited for by this Packet Configuration 94 | *\return a pointer to the passed Packet Configuration 95 | */ 96 | PatternConfiguration* makePatternConfiguration(PatternConfiguration*, const Command, const Command = NONE); 97 | 98 | /*! 99 | * Builder for traffic profiles timing info 100 | *\param t the FifoConfiguration object to be filled 101 | *\param fullLevel the FIFO model maximum fill level 102 | *\param level indicates whether the FIFO starts full or empty 103 | *\param ot the maximum number of outstanding transactions for the associated Traffic Profile 104 | *\param total the total number of transaction the associated Traffic Profile will send 105 | *\param rate the FIFO model fill/depletion rate 106 | *\return a pointer to the FifoConfiguration 107 | */ 108 | FifoConfiguration* makeFifoConfiguration(FifoConfiguration* , const uint64_t, 109 | const FifoConfiguration::StartupLevel, const uint64_t, const uint64_t, const uint64_t); 110 | 111 | /*! 112 | * Creates a new Traffic Profile 113 | *\param p the Profile to be configured 114 | *\param desc description of the new Profile 115 | */ 116 | void 117 | makeProfile(Profile *p, const ProfileDescription &desc) const; 118 | 119 | public: 120 | 121 | //! Builds a TPM loading from file 122 | bool buildManager_fromFile(const string& ); 123 | 124 | /*! 125 | * Requests the TPM to send packets from masters 126 | * and routes them to an internal ATP Slave 127 | *\param rate memory bandwidth of the slave 128 | *\param latency request to response latency 129 | */ 130 | void testAgainstInternalSlave(const string&, const string&); 131 | 132 | 133 | //! UNIT TESTS 134 | 135 | //! tests the ATP FIFO model 136 | void testAtp_fifo(); 137 | 138 | //! tests the ATP Event 139 | void testAtp_event(); 140 | 141 | //! tests the ATP packet descriptor 142 | void testAtp_packetDesc(); 143 | 144 | //! tests the ATP packet tagger functionality 145 | void testAtp_packetTagger(); 146 | 147 | //! tests the statistics object 148 | void testAtp_stats(); 149 | 150 | //! tests the traffic profile object 151 | void testAtp_trafficProfile(); 152 | 153 | //! tests the ATP packet tagger creation logic 154 | void testAtp_packetTaggerCreation(); 155 | 156 | //! tests the traffic profile manager 157 | void testAtp_tpm(); 158 | 159 | //! tests the traffic profile delay 160 | void testAtp_trafficProfileDelay(); 161 | 162 | //! tests the unit conversion functions 163 | void testAtp_unitConversion(); 164 | 165 | //! tests the Kronos engine 166 | void testAtp_kronos(); 167 | 168 | //! tests the traffic profile slave 169 | void testAtp_trafficProfileSlave(); 170 | 171 | //! tests the Traffic Profile Manager routing functionality 172 | void testAtp_trafficProfileManagerRouting(); 173 | }; 174 | 175 | } // end of namespace 176 | 177 | #endif /* _AMBA_TRAFFIC_PROFILE_TEST_ATP_HH_ */ -------------------------------------------------------------------------------- /traffic_profile_checker.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 4 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #include "traffic_profile_checker.hh" 11 | #include "traffic_profile_manager.hh" 12 | #include "utilities.hh" 13 | 14 | namespace TrafficProfiles { 15 | 16 | TrafficProfileChecker::TrafficProfileChecker(TrafficProfileManager* manager, 17 | const uint64_t index, const Profile* p, const uint64_t clone_num) : 18 | TrafficProfileDescriptor(manager, index, p, clone_num) { 19 | 20 | if (p->has_fifo() && p->has_type()) { 21 | // Initialise the FIFO 22 | fifo.init(this, type, &p->fifo(), 23 | manager->isTrackerLatencyEnabled()); 24 | } else { 25 | ERROR("TrafficProfileChecker [", this->name, 26 | "] FIFO configuration not found"); 27 | } 28 | 29 | if (p->check_size() > 0) { 30 | for (int i = 0; i < p->check_size(); ++i) { 31 | string toCheck { p->check(i) }; 32 | if (clone_num) 33 | toCheck.append(Name::CloneSuffix) 34 | .append(to_string(clone_num - 1)); 35 | const uint64_t pid = tpm->getOrGeneratePid(toCheck); 36 | LOG("TrafficProfileChecker [", this->name, 37 | "] registering profile to check: id", pid); 38 | // register this checker to wait for termination of the checked 39 | // master - this will determine its lifetime 40 | waitEvent(Event::TERMINATION, pid, true); 41 | } 42 | } else { 43 | ERROR("TrafficProfileChecker [", this->name, 44 | "] ATP checker configured with no profile to check"); 45 | } 46 | 47 | role = CHECKER; 48 | // a checker is never "first activated", 49 | // it's activation starts with its watched profiles 50 | /* Not Needed 51 | if (getWaitedCount(Event::PROFILE)==0) { 52 | emitEvent(Event::ACTIVATION); 53 | }*/ 54 | } 55 | 56 | TrafficProfileChecker::~TrafficProfileChecker() { 57 | } 58 | 59 | void TrafficProfileChecker::reset() { 60 | // call the base class reset 61 | TrafficProfileDescriptor::reset(); 62 | LOG("TrafficProfileChecker [", this->name,"] " 63 | "reset requested"); 64 | // reset the FIFO 65 | fifo.reset(); 66 | } 67 | 68 | bool TrafficProfileChecker::send(bool& locked, Packet*& p, uint64_t& next) { 69 | // reset next transmission time 70 | next = 0; 71 | locked = false; 72 | bool ok = false; 73 | // get current time 74 | const uint64_t& t = tpm->getTime(); 75 | 76 | if (active(locked)) { 77 | bool underrun = false, overrun = false; 78 | uint64_t request_time = 0; 79 | 80 | if (nullptr == p) { 81 | ERROR("TrafficProfileChecker::send checker [", this->name, 82 | "] requested to record send with empty packet pointer"); 83 | } 84 | ot++; 85 | 86 | LOG("TrafficProfileChecker::send checker [", this->name, 87 | "] recorded address ", Utilities::toHex(p->addr()), "OT", ot); 88 | 89 | ok = fifo.send(underrun, overrun, next, request_time, t, p->size()); 90 | 91 | // update statistics 92 | stats.send(t, p->size(), ot); 93 | 94 | // updates FIFO stats 95 | stats.fifoUpdate(fifo.getLevel(),underrun, overrun); 96 | 97 | } else { 98 | LOG("TrafficProfileChecker::send [", this->name, "] is not active", 99 | locked ? "it is locked" : "it's terminated"); 100 | } 101 | return ok; 102 | } 103 | 104 | 105 | bool TrafficProfileChecker::receive( 106 | uint64_t& next, 107 | const Packet* packet, const double delay) { 108 | bool underrun=false, overrun=false, locked = false; 109 | // get current time 110 | const uint64_t& t = tpm->getTime(); 111 | next=0; 112 | // update OT count 113 | ot--; 114 | LOG("TrafficProfileChecker::receive checker [", this->name, 115 | "] recorded address ", 116 | Utilities::toHex(packet->addr()), "OT", ot); 117 | // this is a checker profile -> update the FIFO accordingly 118 | fifo.receive(underrun, overrun, t, packet->size()); 119 | 120 | stats.receive(t, packet->size(), delay); 121 | 122 | // updates FIFO stats 123 | stats.fifoUpdate(fifo.getLevel(),underrun, overrun); 124 | 125 | // check if the profile is still active (triggers termination event) 126 | if (!active(locked) && !locked) { 127 | LOG("TrafficProfileChecker::receive [", this->name, "] terminated"); 128 | } 129 | 130 | // a traffic profile checker should always accept requests 131 | return true; 132 | } 133 | 134 | bool TrafficProfileChecker::active(bool& l) { 135 | // avoid unused parameter warning 136 | (void) l; 137 | // a checker profile is active as long as its monitored profile is active 138 | bool isActive = waiting(); 139 | 140 | if (!isActive && !terminated) { 141 | // fire deactivation event 142 | emitEvent(Event::TERMINATION); 143 | 144 | LOG("TrafficProfileChecker::active [", name, 145 | "] firing deactivation event with id", id); 146 | 147 | terminated = true; 148 | } 149 | 150 | LOG("TrafficProfileChecker::active [", name, "]", 151 | (terminated ? 152 | "terminated" : (isActive ? "is active" : 153 | "is not active")), 154 | "OT",ot); 155 | 156 | return isActive; 157 | } 158 | 159 | bool TrafficProfileChecker::receiveEvent(const Event& e) { 160 | LOG("TrafficProfileChecker::receiveEvent [", this->name, "] Event", e); 161 | 162 | bool ok = false, fifoOk=false; 163 | // super class handle 164 | ok = EventManager::receiveEvent(e); 165 | // forward to FIFO 166 | // Fifo Handle 167 | fifoOk = fifo.receiveEvent(e); 168 | 169 | return ok || fifoOk; 170 | } 171 | 172 | } /* namespace TrafficProfiles */ 173 | -------------------------------------------------------------------------------- /traffic_profile_checker.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 4 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef __AMBA_TRAFFIC_PROFILE_CHECKER_HH__ 11 | #define __AMBA_TRAFFIC_PROFILE_CHECKER_HH__ 12 | 13 | #include "traffic_profile_desc.hh" 14 | #include "fifo.hh" 15 | 16 | namespace TrafficProfiles { 17 | 18 | /*! 19 | *\brief ATP Checker (Monitor) implementation 20 | * 21 | * An ATP Checker (or Monitor) is a TraffiProfile which 22 | * records in its ATP FIFO all requests and responses 23 | * which are generated or received by its monitored profile 24 | * 25 | * When its FIFO underruns or overruns, it means that the rate 26 | * at which requests/responses are recorded its not enough (READS) 27 | * or it does exceed (WRITES) the monitor FIFO configuration 28 | * 29 | */ 30 | class TrafficProfileChecker : public TrafficProfileDescriptor { 31 | 32 | protected: 33 | //! ATP FIFO 34 | Fifo fifo; 35 | 36 | public: 37 | 38 | /*! 39 | *\brief returns if the Traffic Profile is active 40 | * 41 | * if the Traffic Profile descriptor is not waiting for any events, 42 | * and hasn't sent toSend data yet, 43 | * then it's active. toSend == 0 means this profile doesn't have 44 | * a limit on the number of transactions to send 45 | * if the profile transitions from being active to inactive, 46 | * it fires an event to the TPM 47 | *\param l returns by reference if the Traffic Profile is locked on events 48 | *\return true if the Traffic Profile is active, false otherwise 49 | */ 50 | virtual bool active(bool&); 51 | 52 | /*! 53 | * Constructor 54 | *\param manager the parent Traffic Profile Manager 55 | *\param index the unique ID of this Traffic Profile 56 | *\param p a pointer to the configuration object for this Traffic Profile 57 | *\param clone_num (Optional) Stream Clone number (0=original) 58 | */ 59 | TrafficProfileChecker(TrafficProfileManager*, const uint64_t, 60 | const Profile*, const uint64_t=0); 61 | 62 | //! Default Destructor 63 | virtual ~TrafficProfileChecker(); 64 | 65 | /*! 66 | * 67 | * Signals the descriptor to send a packet 68 | *\param locked returns true if the profile descriptor is locked on waits 69 | *\param p packet to send 70 | *\param next time a packet will be available 71 | *\return true if the packet can be sent according to ot and FIFO limits, 72 | * false otherwise also returns next time a packet will be 73 | * available to be sent 74 | */ 75 | virtual bool send(bool&, Packet*&, uint64_t&); 76 | 77 | /*! 78 | * Signals the descriptor to receive a packet 79 | * returns true if the packet was expected. 80 | *\param next in case of rejection,a profile can return here next time a packet can be received 81 | *\param packet a pointer to the received ATP packet 82 | *\param delay measured request to response delay 83 | *\return true if the packet was accepted by the destination Packet Descriptor, false otherwise 84 | */ 85 | virtual bool receive(uint64_t&, const Packet*, const double); 86 | 87 | /*! 88 | * Activates this profile FIFO 89 | */ 90 | virtual inline void activateFifo() {fifo.activate();} 91 | 92 | 93 | /*! 94 | * Signals this Traffic Profile that an event has 95 | * occurred 96 | * it removes the event from the waiting list 97 | * in case of waited for event 98 | *\param e the event 99 | */ 100 | virtual bool receiveEvent(const Event&); 101 | 102 | /*! 103 | * Resets this profile 104 | */ 105 | virtual void reset(); 106 | }; 107 | 108 | } /* namespace TrafficProfiles */ 109 | 110 | #endif /* __AMBA_TRAFFIC_PROFILE_CHECKER_HH__ */ 111 | -------------------------------------------------------------------------------- /traffic_profile_delay.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * traffic_profile_delay.cc 5 | * 6 | * Created on: 9 Aug 2016 7 | * Author: matand03 8 | */ 9 | 10 | #include "traffic_profile_delay.hh" 11 | #include "traffic_profile_manager.hh" 12 | 13 | namespace TrafficProfiles { 14 | 15 | TrafficProfileDelay::TrafficProfileDelay(TrafficProfileManager* manager, 16 | const uint64_t index, const Profile* p, const uint64_t clone_num) : 17 | TrafficProfileDescriptor(manager, index, p, clone_num), 18 | delay(parseTime(p->delay().time())), 19 | startTime(0), 20 | time(0) { 21 | 22 | if (getWaitedCount(Event::PROFILE)==0) { 23 | // signal profile activation 24 | emitEvent(Event::ACTIVATION); 25 | } 26 | } 27 | 28 | TrafficProfileDelay::~TrafficProfileDelay() { 29 | } 30 | 31 | void TrafficProfileDelay::reset() { 32 | // base class reset 33 | TrafficProfileDescriptor::reset(); 34 | LOG("TrafficProfileDelay::reset", name, "reset requested"); 35 | startTime=0; 36 | time=0; 37 | if (getWaitedCount(Event::PROFILE) == 0) { 38 | emitEvent(Event::ACTIVATION); 39 | } 40 | } 41 | 42 | 43 | bool TrafficProfileDelay::receiveEvent(const Event& e) { 44 | bool ok = false; 45 | // super class handle 46 | ok = EventManager::receiveEvent(e); 47 | // signal profile first activation if not locked by other profiles 48 | if (getWaitedCount(Event::PROFILE) == 0) { 49 | emitEvent(Event::ACTIVATION); 50 | } 51 | return ok; 52 | } 53 | 54 | bool TrafficProfileDelay::send(bool& locked, Packet*& p, uint64_t& next) { 55 | // avoid unused parameter warning 56 | (void) p; 57 | // get current time 58 | const uint64_t& t = tpm->getTime(); 59 | // store current time 60 | time = t; 61 | // update the start time until this profile is started 62 | if (!started) { 63 | startTime = t; 64 | // record start time 65 | stats.start(t); 66 | } 67 | 68 | // check if active, this also triggers termination, eventually 69 | if (active(locked)) { 70 | 71 | LOG("TrafficProfileDelay::send [", name,"] time", t, 72 | "started at",startTime,"delay", delay); 73 | 74 | next = startTime+delay; 75 | } else { 76 | next = 0; 77 | } 78 | 79 | LOG("TrafficProfileDelay::send [", this->name, 80 | "] set next to ", next); 81 | 82 | // signal no transmission 83 | return false; 84 | } 85 | 86 | 87 | bool TrafficProfileDelay::active(bool& l) { 88 | bool isActive = true; 89 | l = (getWaitedCount(Event::PROFILE) > 0); 90 | 91 | // this profile will be activated 92 | if (!l && !started) { 93 | activate(); 94 | } 95 | // this profile is expired if it was started and the current time is 96 | // past or equal its expiration time 97 | const bool expired = (started && (time >= startTime + delay)); 98 | 99 | // a delay profile is active until its configured delay is expired 100 | isActive = !l && !expired; 101 | 102 | if (expired && !terminated) { 103 | // fire deactivation event 104 | emitEvent(Event::TERMINATION); 105 | 106 | LOG("TrafficProfileDelay::active [", name, 107 | "] firing deactivation event with id", id); 108 | 109 | terminated = true; 110 | // record termination time 111 | stats.setTime(time); 112 | } 113 | 114 | LOG("TrafficProfileDelay::active [", name, "]", 115 | (terminated ? "terminated" : 116 | (isActive ? "is active" : 117 | (l? "is locked": "is not active")))); 118 | 119 | return isActive; 120 | } 121 | 122 | 123 | bool TrafficProfileDelay::receive( 124 | uint64_t& next, 125 | const Packet* packet, const double delay) { 126 | // avoid unused parameter warnings 127 | (void) next; 128 | (void) packet; 129 | (void) delay; 130 | 131 | ERROR("TrafficProfileDelay::receive [", this->name, "] " 132 | "can't be called on a delay profile"); 133 | return false; 134 | } 135 | 136 | 137 | } /* namespace TrafficProfiles */ 138 | -------------------------------------------------------------------------------- /traffic_profile_delay.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 4 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef __AMBA_TRAFFIC_PROFILE_DELAY_HH__ 11 | #define __AMBA_TRAFFIC_PROFILE_DELAY_HH__ 12 | 13 | #include "traffic_profile_desc.hh" 14 | 15 | namespace TrafficProfiles { 16 | 17 | /*! 18 | *\brief Traffic Profile Delay implementation 19 | * 20 | * A Traffic Profile Delay implements a delay block, 21 | * it can be utilised to force a pause between two 22 | * traffic profiles. Its behaviour is to stay active 23 | * for the configured amount of time, sending no packets 24 | * and accepting no responses. At the of the configured 25 | * delay, it would terminate. 26 | */ 27 | class TrafficProfileDelay: public TrafficProfileDescriptor { 28 | 29 | protected: 30 | //! configured delay in ATP time units 31 | const uint64_t delay; 32 | 33 | //! field to record activation time 34 | uint64_t startTime; 35 | //! field to record current time 36 | uint64_t time; 37 | 38 | public: 39 | /*! 40 | * Constructor 41 | *\param manager the parent Traffic Profile Manager 42 | *\param index the unique ID of this Traffic Profile 43 | *\param p a pointer to the configuration object for this Traffic Profile 44 | *\param clone_num (Optional) Stream Clone number (0=original) 45 | */ 46 | TrafficProfileDelay(TrafficProfileManager*, const uint64_t, const Profile*, 47 | const uint64_t=0); 48 | 49 | //! Default destructor 50 | virtual ~TrafficProfileDelay(); 51 | 52 | /*! 53 | * Signals this Traffic Profile that an event has 54 | * occurred 55 | * it removes the event from the waiting list 56 | * in case of waited for event 57 | *\param e the event 58 | */ 59 | virtual bool receiveEvent(const Event&); 60 | 61 | /*! 62 | * 63 | *\brief returns if the Traffic Profile is active 64 | * 65 | * if the Traffic Profile descriptor is not waiting 66 | * for any events, and hasn't sent toSend data yet, 67 | * then it's active. toSend == 0 means this profile 68 | * doesn't have a limit on the number of transactions to send 69 | * if the profile transitions from being active to inactive, 70 | * it fires an event to the TPM 71 | *\param l returns by reference if the Traffic Profile is locked on events 72 | *\return true if the Traffic Profile is active, false otherwise 73 | */ 74 | virtual bool active(bool&); 75 | 76 | /*! 77 | * Signals the descriptor to send a packet 78 | *\param locked returns true if the profile descriptor is locked on waits 79 | *\param p packet to send 80 | *\param next time a packet will be available 81 | *\return true if the packet can be sent according to ot and FIFO limits, 82 | * false otherwise also returns next time a packet will be 83 | * available to be sent 84 | */ 85 | virtual bool send(bool&, Packet*&, uint64_t&); 86 | 87 | /*! 88 | * Signals the descriptor to receive a packet 89 | * returns true if the packet was expected. 90 | *\param next in case of rejection,a profile can return here next time a packet can be received 91 | *\param packet a pointer to the received ATP packet 92 | *\param delay measured request to response delay 93 | *\return true if the packet was accepted by the destination Packet Descriptor, false otherwise 94 | */ 95 | virtual bool receive(uint64_t&, const Packet*, const double); 96 | 97 | /*! 98 | * Resets this profile 99 | */ 100 | virtual void reset(); 101 | }; 102 | 103 | } /* namespace TrafficProfiles */ 104 | 105 | #endif /* __AMBA_TRAFFIC_PROFILE_DELAY_HH__ */ 106 | -------------------------------------------------------------------------------- /traffic_profile_master.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 4 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | 10 | #ifndef __AMBA_TRAFFIC_PROFILE_MASTER_HH_ 11 | #define __AMBA_TRAFFIC_PROFILE_MASTER_HH_ 12 | 13 | #include "traffic_profile_desc.hh" 14 | #include "fifo.hh" 15 | 16 | namespace TrafficProfiles { 17 | 18 | /*! 19 | *\brief Implements the AMBA Traffic Profile master profile 20 | * 21 | * Master Profile Descriptor: tracks the status of an active Profile in terms 22 | * of FIFO fill level, outstanding transactions 23 | */ 24 | class TrafficProfileMaster: public TrafficProfileDescriptor { 25 | 26 | protected: 27 | //! Configured total number of transactions to send 28 | uint64_t toSend; 29 | //! Configured time to stop 30 | uint64_t toStop; 31 | //! configured maximum number of outstanding transactions 32 | uint64_t maxOt; 33 | //! Total number of transactions sent so far 34 | uint64_t sent; 35 | //! AMBA Traffic Profiles FIFO model 36 | Fifo fifo; 37 | //! Buffer for pending Packet. If the FIFO is full, a packet could be pended here for later transmission 38 | Packet* pending; 39 | //! flag to signal checkers' FIFOs have been activated 40 | bool checkersFifoStarted; 41 | //! flag to signal the profile is halted - i.e. all operations suspended 42 | bool halted; 43 | //! AMBA TP Packet Descriptor 44 | PacketDesc packetDesc; 45 | 46 | public: 47 | 48 | /*! 49 | *\brief returns if the Traffic Profile is active 50 | * 51 | * if the Traffic Profile descriptor is not waiting for any events, 52 | * and hasn't sent toSend data yet, 53 | * then it's active. toSend == 0 means this profile doesn't have a 54 | * limit on the number of transactions to send 55 | * if the profile transitions from being active to inactive, 56 | * it fires an event to the TPM 57 | *\param l returns by reference if the Traffic Profile is locked on events 58 | *\return true if the Traffic Profile is active, false otherwise 59 | */ 60 | virtual bool active(bool&); 61 | 62 | /*! 63 | * Signals this Traffic Profile that an event has 64 | * occurred 65 | * it removes the event from the waiting list 66 | * in case of waited for event 67 | *\param e the event 68 | */ 69 | virtual bool receiveEvent(const Event&); 70 | 71 | /*! 72 | * Signals the descriptor to send a packet 73 | *\param locked returns true if the profile descriptor is locked on waits 74 | *\param p packet to send 75 | *\param next time a packet will be available 76 | *\return true if the packet can be sent according to ot and FIFO limits, 77 | * false otherwise also returns next time a packet will be 78 | * available to be sent 79 | */ 80 | virtual bool send(bool&, Packet*&, uint64_t&); 81 | 82 | /*! 83 | * Signals the descriptor to receive a packet 84 | * returns true if the packet was expected. 85 | *\param next in case of rejection,a profile can return here next time a packet can be received 86 | *\param packet a pointer to the received ATP packet 87 | *\param delay measured request to response delay 88 | *\return true if the packet was accepted by the destination Packet Descriptor, false otherwise 89 | */ 90 | virtual bool receive(uint64_t&, const Packet*, const double); 91 | 92 | /*! 93 | * Signals the TPM that a packet is waiting for a response related 94 | * to a specific address 95 | *\param time the time when this request was originated 96 | *\param uid the packet unique ID 97 | *\param address the address of the waited for response 98 | *\param size the size of the waited for response 99 | */ 100 | void wait(const uint64_t, const uint64_t, const uint64_t, const uint64_t); 101 | 102 | /*! 103 | * Signals the TPM that a response with the specified UID should 104 | * be discarded if received 105 | *\param uid the packet unique ID 106 | */ 107 | void discard(const uint64_t); 108 | 109 | /*! 110 | * Signals the descriptor that this Profile no longer waits for a response 111 | *\param uid the packet unique ID 112 | *\param address the address of the response which is no longer waited for 113 | *\param size the size of the response which is no longer waited for 114 | */ 115 | void signal(const uint64_t, const uint64_t, const uint64_t); 116 | 117 | /*! 118 | *\brief Triggers the profile descriptor autoRange 119 | * 120 | * The traffic profile descriptor is reconfigured 121 | * with a new address range (if no more restrictive 122 | * range was already set or if the force flag is set) 123 | * based on the configured number of packets and size. 124 | * If the descriptor is configured to generate 125 | * random packet sizes, the operation aborts 126 | * 127 | *\param force forces the range to be applied 128 | *\return the range applied 129 | */ 130 | inline uint64_t autoRange(const bool force = false) { 131 | return packetDesc.autoRange(toSend, force); 132 | } 133 | 134 | /*! 135 | * Reconfigures the packet descriptor with a new 136 | * base address and range 137 | */ 138 | inline void addressReconfigure(const uint64_t base, const uint64_t range) 139 | { 140 | packetDesc.addressReconfigure(base, range); 141 | } 142 | 143 | /*! Constructor 144 | *\param manager the parent Traffic Profile Manager 145 | *\param index the unique ID of this Traffic Profile 146 | *\param p a pointer to the configuration object for this Traffic Profile 147 | *\param clone_num (Optional) Stream Clone number (0=original) 148 | */ 149 | TrafficProfileMaster(TrafficProfileManager*, const uint64_t, 150 | const Profile*, const uint64_t=0); 151 | 152 | //! Default destructor 153 | virtual ~TrafficProfileMaster(); 154 | 155 | /*! 156 | * Returns the FIFO type 157 | *\return either READ or WRITE 158 | */ 159 | Profile::Type getFifoType() const { return fifo.getType();} 160 | 161 | /*! Returns the FIFO level */ 162 | uint64_t getFifoLevel() const { return fifo.getLevel(); } 163 | 164 | /*! 165 | * Resets this profile 166 | */ 167 | virtual void reset(); 168 | }; 169 | 170 | } /* namespace TrafficProfiles */ 171 | 172 | #endif /* __AMBA_TRAFFIC_PROFILE_MASTER_HH_ */ 173 | -------------------------------------------------------------------------------- /traffic_profile_slave.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 4 Aug 2016 7 | * Author: Matteo Andreozzi 8 | */ 9 | #ifndef __AMBA_TRAFFIC_PROFILE_SLAVE_HH__ 10 | #define __AMBA_TRAFFIC_PROFILE_SLAVE_HH__ 11 | 12 | #include "traffic_profile_desc.hh" 13 | #include "fifo.hh" 14 | #include 15 | 16 | using namespace std; 17 | 18 | namespace TrafficProfiles { 19 | 20 | /*! 21 | *\brief ATP Traffic Profile Slave (Memory) 22 | * 23 | * Implements an ATP Slave which receives requests from 24 | * and sends responses to its registered master Traffic 25 | * Profiles. When all masters are registered to at least 26 | * one ATP slave, ATP can be run in standalone mode. 27 | */ 28 | class TrafficProfileSlave : public TrafficProfileDescriptor { 29 | protected: 30 | //! type for response latency generation method 31 | enum Type { 32 | CONFIGURED = 0, RANDOM = 1 33 | }; 34 | 35 | //! Memory bandwidth pair multiplier and bytes per ATP time unit 36 | const pair bandwidth; 37 | //! Maximum outstanding transactions limit 38 | uint64_t maxOt; 39 | /*!\brief Width of the slave memory 40 | * transaction granularity to be taken into account 41 | * for OT calculation 42 | */ 43 | uint64_t width; 44 | 45 | //! methodology for generating response latencies 46 | Type latencyType; 47 | 48 | /*! 49 | * union which holds either the configured static 50 | * memory latency 51 | * or a RandomGenDesc object which is used to generate 52 | * random latency values 53 | */ 54 | union { 55 | struct { 56 | /*! 57 | * RandomGenDesc object used to generate 58 | * random latency values 59 | */ 60 | Random::Generator latency; 61 | /*! 62 | * Base unit to be used to generate 63 | * random latency values 64 | */ 65 | uint64_t latencyUnit; 66 | } random; 67 | /*! 68 | * Memory request to response static latency 69 | */ 70 | uint64_t staticLatency; 71 | }; 72 | 73 | /*! 74 | *\brief AMBA Traffic Profiles FIFO model 75 | * In slaves, the ATP FIFO is used as follows: 76 | * READ Type FIFO, FIFO size = width*MaxOT. 77 | * MaxOT = same as slave 78 | * On receive API call, FIFO is queried with send API, 79 | * data marked as "in-flight" represent requests 80 | * scheduled for processing 81 | * On send APU call FIFO, the slave looks up requests 82 | * which can be served, calls appropriate number of 83 | * receive API FIFO based on width, unlocks in-flight data 84 | * The FIFO rate ensures the slave bandwidth is adhered to. 85 | */ 86 | Fifo fifo; 87 | 88 | /*! 89 | * Data structure used to store responses to be sent 90 | */ 91 | list responses; 92 | public: 93 | /*! 94 | * Constructor 95 | *\param manager the parent Traffic Profile Manager 96 | *\param index the unique ID of this Traffic Profile 97 | *\param p a pointer to the configuration object for this Traffic Profile 98 | *\param clone_num (Optional) Stream Clone number (0=original) 99 | */ 100 | TrafficProfileSlave(TrafficProfileManager*, const uint64_t, const Profile*, 101 | const uint64_t=0); 102 | 103 | //! Default destructor 104 | virtual ~TrafficProfileSlave(); 105 | 106 | /*! 107 | *\brief returns if the Traffic Profile is active 108 | * 109 | * If the Traffic Profile descriptor is not waiting 110 | * for any events, and hasn't sent toSend data yet, 111 | * then it's active. toSend == 0 means this profile 112 | * doesn't have a limit on the number of transactions to send 113 | * if the profile transitions from being active to inactive, 114 | * it fires an event to the TPM 115 | *\param l returns by reference if the Traffic Profile 116 | * is locked on events 117 | *\return true if the Traffic Profile is active, false otherwise 118 | */ 119 | virtual bool active(bool&); 120 | 121 | /*! 122 | * Queries the slave for Responses 123 | *\param locked returns true if the slave cannot generate responses 124 | *\param p Response packet 125 | *\param next time a Response will be generated 126 | *\return true if the Response can be generated according to the slave OT 127 | * and rate/latency limits, false otherwise. 128 | * Also returns next time a Response will be 129 | * available to be generated 130 | */ 131 | virtual bool send(bool&, Packet*&, uint64_t&); 132 | 133 | /*! 134 | * Signals the slave to receive a Request 135 | * returns true if the Request can be accepted 136 | *\param next in case of rejection, return here next time this request 137 | * can be received 138 | *\param packet a pointer to the ATP packet - Request 139 | *\param delay latency accumulated by the request 140 | *\return true if the request is accepted, false otherwise 141 | */ 142 | virtual bool receive(uint64_t&, const Packet*, const double); 143 | 144 | /*! 145 | * Gets the slave configured bandwidth 146 | *\return constant reference to the bandwidth pair 147 | * (bytes, period in ATP time units) 148 | */ 149 | inline const pair& getBandwidth() const { 150 | return bandwidth; 151 | } 152 | 153 | /*! 154 | * Gets the slave configured latency 155 | *\return constant reference to the latency value in 156 | * ATP time units 157 | */ 158 | inline const uint64_t& getLatency() const {return staticLatency;} 159 | 160 | /*! 161 | * Gets the slave configured width 162 | *\return constant reference to the slave configured width in bytes 163 | */ 164 | inline const uint64_t& getWidth() const {return width;} 165 | 166 | /*! 167 | * Gets the slave configured max OT 168 | *\return constant reference to the slave configured max OT 169 | */ 170 | inline const uint64_t& getMaxOt() const {return maxOt;} 171 | 172 | /*! 173 | * Gets next response time if available or 0 174 | *\return next response time if available or 0 175 | */ 176 | virtual inline uint64_t nextResponseTime() const {return responses.empty()?0:responses.front()->time();} 177 | 178 | /*! getter method for this Traffic Profile master name 179 | *\return the Slave traffic profile name 180 | */ 181 | virtual inline const string& getMasterName() const {return name;} 182 | 183 | /*! 184 | * Resets this profile 185 | */ 186 | virtual void reset(); 187 | }; 188 | 189 | } /* namespace TrafficProfiles */ 190 | 191 | #endif /* __AMBA_TRAFFIC_PROFILE_SLAVE_HH__ */ 192 | -------------------------------------------------------------------------------- /types.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2020 ARM Limited 5 | * All rights reserved 6 | * Author: Adrian Herrera 7 | */ 8 | 9 | #ifndef __TYPES_HH__ 10 | #define __TYPES_HH__ 11 | 12 | #include 13 | #include 14 | 15 | namespace TrafficProfiles { 16 | 17 | template 18 | constexpr T InvalidId() { return std::numeric_limits::max(); } 19 | 20 | template 21 | constexpr bool isValid(const T id) { return id != InvalidId(); } 22 | 23 | } 24 | 25 | #endif /* __TYPES_HH__ */ 26 | -------------------------------------------------------------------------------- /utilities.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause-Clear 3 | * 4 | * Copyright (c) 2016 ARM Limited 5 | * All rights reserved 6 | * Created on: 9 Sep 2016 7 | * Author: matand03 8 | */ 9 | 10 | #include "utilities.hh" 11 | 12 | namespace Utilities { 13 | 14 | 15 | bool isNumber(const string& s) 16 | { 17 | return !s.empty() && find_if(s.begin(), 18 | s.end(), [](char c) { return !(isdigit(c) || (c=='.') || (c=='-')); }) == s.end(); 19 | } 20 | 21 | void trimLeft(string& s){ 22 | s.erase(s.begin(), find_if(s.begin(), s.end(), 23 | [](char c) { return !isspace(static_cast(c)); })); 24 | } 25 | 26 | string trimLeftCopy(string s){ 27 | trimLeft(s); 28 | return s; 29 | } 30 | 31 | void trimRight(string& s){ 32 | s.erase(find_if(s.rbegin(), s.rend(), 33 | [](char c) { return !isspace(static_cast(c)); }).base(), 34 | s.end()); 35 | } 36 | 37 | string trimRightCopy(string s){ 38 | trimRight(s); 39 | return s; 40 | } 41 | 42 | void trimOuter(string& s){ 43 | trimLeft(s); 44 | trimRight(s); 45 | }; 46 | 47 | string trimOuterCopy(string s){ 48 | trimOuter(s); 49 | return s; 50 | }; 51 | 52 | const string trim(const string& s){ 53 | string ret = s; 54 | // trim string 55 | ret.erase(remove_if(ret.begin(), ret.end(), 56 | [](char x){return std::isspace(x);}), 57 | ret.end()); 58 | 59 | return ret; 60 | } 61 | 62 | string extractHead(const string& s){ 63 | string ret { trimOuterCopy(s) }; 64 | return ret.substr(0, ret.find_first_of(' ')); 65 | } 66 | 67 | string extractTail(const string& s){ 68 | string ret { trimOuterCopy(s) }; 69 | const auto sep_pos = ret.find_first_of(' '); 70 | return (sep_pos == string::npos) ? string { } : 71 | ret.substr(ret.find_first_not_of(' ', sep_pos + 1)); 72 | } 73 | 74 | uint64_t nextPowerTwo(const uint64_t n){ 75 | uint64_t temp = n; 76 | uint64_t i = 0; 77 | while (temp >>= 1) 78 | { 79 | i++; 80 | } 81 | return (1<& units) { 93 | bool found=false; 94 | uint64_t ret = 0; 95 | size_t pos_ret = string::npos; 96 | for (auto& u:units) { 97 | // look for matches from position pos 98 | auto temp = s.find(u.first, pos); 99 | if (temp != string::npos) { 100 | ret = (ret == 0 ? u.second:ret*u.second); 101 | // store position of first unit specifier character 102 | if (!found || (temp