├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── Makefile ├── README.md ├── data-analysis ├── data-analysis.cpp ├── dataparser.cpp ├── dataparser.hpp └── getTopLinkUtil.sh ├── devtests ├── devtests.cpp └── devtests.hpp ├── preProcessData.sh ├── question2.sh ├── run.sh ├── run_analysis.sh ├── simulation ├── config.cpp ├── config.hpp ├── config_default.hpp ├── config_evaluation.hpp ├── config_profiling.hpp ├── config_test.hpp ├── config_validation.hpp ├── event.cpp ├── event.hpp ├── simulation.cpp └── simulation.hpp ├── syndb-sim.cpp ├── topology ├── fattree_topology.cpp ├── fattree_topology.hpp ├── host.cpp ├── host.hpp ├── link.cpp ├── link.hpp ├── switch.cpp ├── switch.hpp ├── switch_ft.cpp ├── switch_ft.hpp ├── syndb_ringbuffer.cpp ├── syndb_ringbuffer.hpp ├── topology.cpp └── topology.hpp ├── traffic-dist ├── fb_webserver_flowinterarrival_ns_cdf.csv ├── fb_webserver_packetsizedist_cdf.csv ├── flowinterarrival_cdf.png ├── packetinterarrival_cdf.png ├── packetinterarrival_ns_cdf.csv └── packetsizedist_cdf.png ├── traffic ├── incastGenerator.cpp ├── incastGenerator.hpp ├── packet.cpp ├── packet.hpp ├── randomGenCDF.cpp ├── randomGenCDF.hpp ├── trafficGenerator.cpp ├── trafficGenerator.hpp ├── trafficPattern.cpp ├── trafficPattern.hpp ├── traffictester.cpp ├── triggerGenerator.cpp └── triggerGenerator.hpp └── utils ├── logger.cpp ├── logger.hpp ├── memusage ├── pktdumper.cpp ├── pktdumper.hpp ├── types.hpp └── utils.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | syndb-sim 34 | syndb-sim-debug 35 | syndb-sim-prof 36 | syndb-analysis 37 | syndb-analysis-debug 38 | syndb-analysis-prof 39 | data-analysis-output/* 40 | data/* 41 | output.txt 42 | lineTopo.txt 43 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Debug", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [ 9 | "DEBUG" 10 | ], 11 | "compilerPath": "/usr/bin/gcc", 12 | "cStandard": "gnu11", 13 | "cppStandard": "gnu++11", 14 | "intelliSenseMode": "gcc-x64", 15 | "compilerArgs": [] 16 | }, 17 | { 18 | "name": "Release", 19 | "includePath": [ 20 | "${workspaceFolder}/**" 21 | ], 22 | "defines": [], 23 | "compilerPath": "/usr/bin/gcc", 24 | "cStandard": "gnu11", 25 | "cppStandard": "gnu++11", 26 | "intelliSenseMode": "linux-gcc-x64" 27 | } 28 | ], 29 | "version": 4 30 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "(gdb) Debug Analysis", 10 | "type": "cppdbg", 11 | "request": "launch", 12 | "program": "${workspaceFolder}/syndb-analysis-debug", 13 | "args": [], 14 | "stopAtEntry": false, 15 | "cwd": "${workspaceFolder}", 16 | "environment": [], 17 | "externalConsole": false, 18 | "MIMode": "gdb", 19 | "setupCommands": [ 20 | { 21 | "description": "Enable pretty-printing for gdb", 22 | "text": "-enable-pretty-printing", 23 | "ignoreFailures": true 24 | } 25 | ], 26 | "preLaunchTask": "Debug Build Analysis", 27 | "miDebuggerPath": "/usr/bin/gdb" 28 | }, 29 | { 30 | "name": "(gdb) Debug", 31 | "type": "cppdbg", 32 | "request": "launch", 33 | "program": "${workspaceFolder}/syndb-sim-debug", 34 | "args": [], 35 | "stopAtEntry": false, 36 | "cwd": "${workspaceFolder}", 37 | "environment": [{"name":"MALLOC_CHECK_", "value": "2"}], 38 | "externalConsole": false, 39 | "MIMode": "gdb", 40 | "setupCommands": [ 41 | { 42 | "description": "Enable pretty-printing for gdb", 43 | "text": "-enable-pretty-printing", 44 | "ignoreFailures": true 45 | } 46 | ], 47 | "preLaunchTask": "Debug Build", 48 | "miDebuggerPath": "/usr/bin/gdb" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.tcc": "cpp", 4 | "unordered_map": "cpp", 5 | "fstream": "cpp", 6 | "istream": "cpp", 7 | "ostream": "cpp", 8 | "sstream": "cpp", 9 | "numeric": "cpp", 10 | "cctype": "cpp", 11 | "clocale": "cpp", 12 | "cmath": "cpp", 13 | "cstdarg": "cpp", 14 | "cstddef": "cpp", 15 | "cstdio": "cpp", 16 | "cstdlib": "cpp", 17 | "cstring": "cpp", 18 | "ctime": "cpp", 19 | "cwchar": "cpp", 20 | "cwctype": "cpp", 21 | "array": "cpp", 22 | "atomic": "cpp", 23 | "bitset": "cpp", 24 | "chrono": "cpp", 25 | "codecvt": "cpp", 26 | "complex": "cpp", 27 | "condition_variable": "cpp", 28 | "cstdint": "cpp", 29 | "deque": "cpp", 30 | "list": "cpp", 31 | "vector": "cpp", 32 | "exception": "cpp", 33 | "algorithm": "cpp", 34 | "filesystem": "cpp", 35 | "functional": "cpp", 36 | "iterator": "cpp", 37 | "map": "cpp", 38 | "memory": "cpp", 39 | "memory_resource": "cpp", 40 | "optional": "cpp", 41 | "random": "cpp", 42 | "ratio": "cpp", 43 | "set": "cpp", 44 | "string": "cpp", 45 | "string_view": "cpp", 46 | "system_error": "cpp", 47 | "tuple": "cpp", 48 | "type_traits": "cpp", 49 | "utility": "cpp", 50 | "initializer_list": "cpp", 51 | "iomanip": "cpp", 52 | "iosfwd": "cpp", 53 | "iostream": "cpp", 54 | "limits": "cpp", 55 | "mutex": "cpp", 56 | "new": "cpp", 57 | "stdexcept": "cpp", 58 | "streambuf": "cpp", 59 | "thread": "cpp", 60 | "cfenv": "cpp", 61 | "cinttypes": "cpp", 62 | "typeindex": "cpp", 63 | "typeinfo": "cpp", 64 | "variant": "cpp", 65 | "bit": "cpp", 66 | "strstream": "cpp", 67 | "unordered_set": "cpp" 68 | }, 69 | "python.pythonPath": "/usr/bin/python3" 70 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Debug Build", 8 | "type": "shell", 9 | "command": "make BUILD=debug -j $(($(nproc)-1))", 10 | "problemMatcher": [], 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | } 15 | }, 16 | { 17 | "label": "Debug Build Analysis", 18 | "type": "shell", 19 | "command": "make BUILD=debug -j $(($(nproc)-1)) analysis", 20 | "problemMatcher": [], 21 | "group": "build" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifndef $(BUILD) 2 | BUILD := release 3 | endif 4 | 5 | ifndef $(CONFIG) 6 | CONFIG := default 7 | endif 8 | 9 | UNAME_S := $(shell uname -s) 10 | 11 | CURR_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 12 | BASE_BUILDDIR:=$(CURR_DIR)/build 13 | BUILDDIR=$(BASE_BUILDDIR)/$(BUILD) 14 | 15 | SOURCES = $(wildcard $(CURR_DIR)/*.cpp) \ 16 | $(wildcard $(CURR_DIR)/traffic/*.cpp) \ 17 | $(wildcard $(CURR_DIR)/topology/*.cpp) \ 18 | $(wildcard $(CURR_DIR)/utils/*.cpp) \ 19 | $(wildcard $(CURR_DIR)/simulation/*.cpp) \ 20 | $(wildcard $(CURR_DIR)/devtests/*.cpp) 21 | 22 | ANALYSIS_SOURCES = $(wildcard $(CURR_DIR)/data-analysis/*.cpp) 23 | 24 | OBJECTS = $(patsubst $(CURR_DIR)/%,$(BUILDDIR)/%,$(SOURCES:.cpp=.o)) 25 | DEPENDS = $(patsubst $(CURR_DIR)/%,$(BUILDDIR)/%,$(SOURCES:.cpp=.d)) 26 | 27 | ANALYSIS_OBJECTS = $(patsubst $(CURR_DIR)/%,$(BUILDDIR)/%,$(ANALYSIS_SOURCES:.cpp=.o)) 28 | ANALYSIS_DEPENDS = $(patsubst $(CURR_DIR)/%,$(BUILDDIR)/%,$(ANALYSIS_SOURCES:.cpp=.d)) 29 | 30 | RELEASE_BINARY := syndb-sim 31 | DEBUG_BINARY := syndb-sim-debug 32 | PROFILE_BINARY := syndb-sim-prof 33 | 34 | ANALYSIS_RELEASE_BINARY := syndb-analysis 35 | ANALYSIS_DEBUG_BINARY := syndb-analysis-debug 36 | ANALYSIS_PROFILE_BINARY := syndb-analysis-profile 37 | 38 | 39 | CXXFLAGS = -I$(CURR_DIR) \ 40 | -std=c++11 41 | 42 | LDLIBS = -lpthread \ 43 | -lfmt \ 44 | -lspdlog 45 | 46 | ifeq ($(BUILD), release) 47 | CXXFLAGS += -O3 48 | OUTPUT_BINARY := $(RELEASE_BINARY) 49 | ANALYSIS_BINARY := $(ANALYSIS_RELEASE_BINARY) 50 | endif 51 | 52 | ifeq ($(BUILD), debug) 53 | CXXFLAGS += -O0 -g3 -DDEBUG 54 | OUTPUT_BINARY := $(DEBUG_BINARY) 55 | ANALYSIS_BINARY := $(ANALYSIS_DEBUG_BINARY) 56 | endif 57 | 58 | ifeq ($(CONFIG), default) 59 | CXXFLAGS += -DCONFIG=0 60 | endif 61 | 62 | ifeq ($(CONFIG), validation) 63 | CXXFLAGS += -DCONFIG=1 64 | endif 65 | 66 | ifeq ($(CONFIG), evaluation) 67 | CXXFLAGS += -DCONFIG=2 68 | endif 69 | 70 | ifeq ($(CONFIG), profiling) 71 | CXXFLAGS += -pg -DCONFIG=3 72 | OUTPUT_BINARY := $(PROFILE_BINARY) 73 | ANALYSIS_BINARY := $(ANALYSIS_PROFILE_BINARY) 74 | endif 75 | 76 | ifeq ($(CONFIG), test) 77 | CXXFLAGS += -DCONFIG=4 78 | endif 79 | 80 | .PHONY: all clean cleaner 81 | 82 | all: $(OUTPUT_BINARY) 83 | 84 | analysis: $(ANALYSIS_BINARY) 85 | 86 | clean: 87 | @$(RM) -rf $(BUILDDIR) 88 | @$(RM) $(OUTPUT_BINARY) 89 | @$(RM) $(ANALYSIS_BINARY) 90 | 91 | cleaner: 92 | @$(RM) -rf $(BASE_BUILDDIR) 93 | @$(RM) $(RELEASE_BINARY) $(DEBUG_BINARY) $(PROFILE_BINARY) 94 | @$(RM) $(ANALYSIS_RELEASE_BINARY) $(ANALYSIS_DEBUG_BINARY) $(ANALYSIS_PROFILE_BINARY) 95 | 96 | 97 | # Linking the executable from the object files 98 | $(OUTPUT_BINARY): $(OBJECTS) 99 | $(CXX) $(CXXFLAGS) $^ -o $@ $(LDLIBS) 100 | 101 | $(ANALYSIS_BINARY): $(ANALYSIS_OBJECTS) 102 | $(CXX) $(CXXFLAGS) $^ -o $@ $(LDLIBS) 103 | 104 | -include $(DEPENDS) 105 | 106 | # -MMD -MP are related to generating the .d depends file 107 | $(BUILDDIR)/%.o: $(CURR_DIR)/%.cpp Makefile 108 | @mkdir -p $(@D) 109 | $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@ 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SyNDB Simulator 2 | 3 | This repository hosts the packet-level simulator used in the evaluation of the NSDI 2021 paper titled [Debugging Transient Faults in Data Centers using Synchronized Network-wide Packet Histories](https://www.usenix.org/conference/nsdi21/presentation/kannan). This packet-level simulator is used to evaluate the proposed system, **SyNDB**, on a large-scale data center network. 4 | 5 | ## Compile 6 | 7 | ### Install Dependencies 8 | 9 | The following *additional* C++ libraries are required: 10 | * [libfmt-6.1.2](https://github.com/fmtlib/fmt/releases/tag/6.1.2) 11 | * [libspdlog-1.8.2](https://github.com/gabime/spdlog/releases/tag/v1.8.2) 12 | 13 | The simulator has been tested with the above library versions. You can always use higher versions. However, to avoid any possibility of running into API breakage, we recommend you to stick to the above versions. Other than these, the simulator uses the standard `libpthread` library. 14 | 15 | Download the source code for the above dependencies. Build and install them as per respective instructions: 16 | * [Building and installing libfmt](https://fmt.dev/latest/usage.html#building-the-library) (build a shared library) 17 | * [Building and installing libspdlog](https://github.com/gabime/spdlog#install) 18 | 19 | ### Compilation 20 | 21 | **Step 1:** Git clone this repo to your local Linux machine: 22 | ``` 23 | git clone https://github.com/rajkiranjoshi/syndb-sim.git 24 | ``` 25 | 26 | **Step 2:** Compile the simulator source code: 27 | ``` 28 | # Inside the syndb-sim directory 29 | make 30 | ``` 31 | This will create the simulator binary `syndb-sim` in the same directory. 32 | 33 | ## Run 34 | ``` 35 | # Inside the syndb-sim directory 36 | ./syndb-sim 37 | ``` 38 | This will run the simulation as described in section 7.1.2 of the [paper](https://www.usenix.org/system/files/nsdi21-kannan.pdf). By default, the simulator binary will simulate a small k=4 fat tree network with 100G links for a total network run time of 10 milliseconds. See [Advanced Simulation](#advanced-simulation) to run simulation for other (large) configurations. 39 | 40 | The simulation will produce a bunch of output files in the "data" subdirectory. 41 | 42 | ## Analyze 43 | 44 | The simulation data is analyzed by a separate binary. 45 | 46 | ### Build the data analysis binary 47 | 48 | Update the `PREFIX_FILE_PATH` and `PREFIX_STRING_FOR_DATA_FILES` macros in the `data-analysis/dataparser.hpp` to point to the output data and its (time-based) prefix. Now build the data analysis binary: 49 | ``` 50 | # Inside the syndb-sim directory 51 | make analysis 52 | ``` 53 | This will produce the binary `syndb-analysis` in the same directory. 54 | 55 | Finally, copy `preProcessData.sh` to the data folder and run it to process the simulation data. 56 | 57 | ``` 58 | # Inside the syndb-sim directory 59 | cp ./preProcessData.sh ./path/to/data/file 60 | cd ./path/to/data/file 61 | ./preProcessData.sh 62 | ``` 63 | 64 | ### Analyze the simulation data 65 | ``` 66 | # Inside the syndb-sim directory 67 | ./syndb-analysis 68 | ``` 69 | This will run analysis on the data generated by the simulation. The analysis will print the following for each valid switch: 70 | * ingress time for the trigger packet 71 | * maximum number of common packets between the trigger switch and current switch 72 | * correlation for the captured *p-records* 73 | * common time window between the trigger switch but missing in the current switch window 74 | 75 | ## Advanced Simulation 76 | 77 | The [paper](https://www.usenix.org/system/files/nsdi21-kannan.pdf) uses this simulator for: (a) validation (section 7, Figure 6), and (b) large-scale evaluation (section 7.1.2). To build the simulation/analysis binary for these experiment configurations, build the simulation binary with the following commands, respectively: 78 | ``` 79 | ## For validation, inside the syndb-sim directory 80 | make CONFIG=validation 81 | # After simulation and updating macros in dataparser.hpp 82 | make CONFIG=validation analysis 83 | 84 | ## For evaluation, inside the syndb-sim directory 85 | make CONFIG=evaluation 86 | # After simulation and updating macros in dataparser.hpp 87 | make CONFIG=evaluation analysis 88 | ``` 89 | For the evaluation configuration, each simulation run requires ~4 GB of memory and produces 100's of GB of simulation data while requiring ~10 hours (depending on your CPU clock speed) to complete. Therefore, please ensure sufficient system requirements before running the simulator with the evaluation configuration. 90 | -------------------------------------------------------------------------------- /data-analysis/data-analysis.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define LOGGING 0 6 | #include "utils/logger.hpp" 7 | #include "data-analysis/dataparser.hpp" 8 | 9 | 10 | /** 11 | * Get the route for a given packet in fat-tree topology. 12 | * 13 | * @param source Host ID of the source 14 | * @param destination Host ID of the destination 15 | * @param fatTreeTopoK k value for the fat-tree topology 16 | * 17 | * @return route List of switch IDs in the route as a vector 18 | */ 19 | std::vector getRoute (host_id_t source, host_id_t destination, ft_scale_t fatTreeTopoK) { 20 | std::vector route; 21 | 22 | const uint64_t k = fatTreeTopoK; 23 | const uint64_t kBy2 = fatTreeTopoK / 2; 24 | const uint64_t kBy2WholeSquare = kBy2 * kBy2; 25 | 26 | host_id_t sourcePod = source / kBy2WholeSquare; 27 | host_id_t destinationPod = destination / kBy2WholeSquare; 28 | 29 | #ifdef DEBUG 30 | debug_print("Source Pod: {}", sourcePod); 31 | debug_print("Destination Pod: {}", destinationPod); 32 | #endif 33 | 34 | // get ToR switch ID for first hop 35 | host_id_t podLocalSourceHostID = source % kBy2WholeSquare; // between 0 to (kBy2WholeSquare - 1) 36 | switch_id_t podLocalSourceToRSwitchID = podLocalSourceHostID / kBy2; // between 0 to (k/2 - 1) 37 | switch_id_t sourceToRSwitchID = (sourcePod * k) + podLocalSourceToRSwitchID; 38 | host_id_t podLocalDestinationHostID = destination % kBy2WholeSquare; // between 0 to (kBy2WholeSquare - 1) 39 | switch_id_t podLocalDestinationToRSwitchID = podLocalDestinationHostID / kBy2; // between 0 to (k/2 - 1) 40 | switch_id_t destinationToRSwitchID = (destinationPod * k) + podLocalDestinationToRSwitchID; 41 | 42 | route.push_back(sourceToRSwitchID); 43 | 44 | #ifdef DEBUG 45 | debug_print("Pod Local Source ID: {}", podLocalSourceHostID); 46 | debug_print("Pod Local Source ToR Switch ID: {}", podLocalSourceToRSwitchID); 47 | debug_print("Source ToR Switch ID: s{}", sourceToRSwitchID); 48 | #endif 49 | 50 | if (destinationToRSwitchID == sourceToRSwitchID) { 51 | return route; 52 | } 53 | 54 | host_id_t rackLocalDestinationHostID = destination % kBy2; 55 | switch_id_t podLocalSourceAggregationSwitchID = (sourceToRSwitchID + rackLocalDestinationHostID) % kBy2; // between 0 to (k/2 - 1) 56 | switch_id_t sourceAggregationSwitchID = (sourcePod * k) + kBy2 + podLocalSourceAggregationSwitchID; 57 | 58 | route.push_back(sourceAggregationSwitchID); 59 | 60 | #ifdef DEBUG 61 | debug_print("Pod Local Source Aggregation Switch ID: {}", podLocalSourceAggregationSwitchID); 62 | debug_print("Source Aggregation Switch ID: s{}", sourceAggregationSwitchID); 63 | #endif 64 | 65 | if (destinationPod == sourcePod) { 66 | 67 | #ifdef DEBUG 68 | debug_print("Pod Local Destination ID: {}", podLocalDestinationHostID); 69 | debug_print("Pod Local Destination ToR Switch ID: {}", podLocalDestinationToRSwitchID); 70 | debug_print("Destination ToR Switch ID: s{}", destinationToRSwitchID); 71 | #endif 72 | route.push_back(destinationToRSwitchID); 73 | return route; 74 | } 75 | 76 | switch_id_t localCoreSwitchID = (podLocalSourceAggregationSwitchID + rackLocalDestinationHostID) % kBy2; 77 | switch_id_t coreSwitchID = (k*k) + (podLocalSourceAggregationSwitchID * kBy2) + localCoreSwitchID; 78 | 79 | route.push_back(coreSwitchID); 80 | 81 | #ifdef DEBUG 82 | debug_print("Local Core Switch ID: {}", localCoreSwitchID); 83 | debug_print("Core Switch ID: s{}", coreSwitchID); 84 | #endif 85 | 86 | switch_id_t podLocalDestinationAggergationSwitchID = podLocalSourceAggregationSwitchID; 87 | switch_id_t destinationAggregationSwitchID = (destinationPod * k) + kBy2 + podLocalDestinationAggergationSwitchID; 88 | 89 | route.push_back(destinationAggregationSwitchID); 90 | route.push_back(destinationToRSwitchID); 91 | 92 | #ifdef DEBUG 93 | debug_print("Pod Local Destination Aggregation Switch ID: {}", podLocalDestinationAggergationSwitchID); 94 | debug_print("Destination Aggregation Switch ID: s{}", destinationAggregationSwitchID); 95 | debug_print("Pod Local Destination ID: {}", podLocalDestinationHostID); 96 | debug_print("Pod Local Destination ToR Switch ID: {}", podLocalDestinationToRSwitchID); 97 | debug_print("Destination ToR Switch ID: s{}", destinationToRSwitchID); 98 | #endif 99 | 100 | return route; 101 | } 102 | 103 | 104 | 105 | /** 106 | * Get the list of accessible switches for a trigger switch. 107 | * 108 | * @param triggerSwitchID Switch ID for trigger switch 109 | * 110 | * @return validSwitches Set of switches which are accessible from the trigger switch 111 | * 112 | */ 113 | std::unordered_set getValidSwitches(switch_id_t triggerSwitchID, ft_scale_t fatTreeTopoK) { 114 | std::unordered_set validSwitches; 115 | 116 | const uint64_t k = fatTreeTopoK; 117 | const uint64_t kBy2 = fatTreeTopoK / 2; 118 | const uint64_t kSquare = k * k; 119 | const uint64_t kBy2WholeSquare = kBy2 * kBy2; 120 | 121 | if (triggerSwitchID < kSquare) { 122 | 123 | if (triggerSwitchID < kSquare) { 124 | if ((triggerSwitchID % k) < kBy2) { 125 | // ToR switch 126 | 127 | // add all ToR and Aggr switches in all the pods 128 | for (int i = 0; i < kSquare; i++) { 129 | validSwitches.insert(i); 130 | } 131 | 132 | for (int i = kSquare; i < (kSquare +kBy2WholeSquare); i++) { 133 | validSwitches.insert(i); 134 | } 135 | 136 | return validSwitches; 137 | } else { 138 | // Aggr switch 139 | switch_id_t podLocalAggregationSwitchID = (triggerSwitchID % k) - kBy2; 140 | switch_id_t indexForStartingCoreSwitchID = kSquare + (podLocalAggregationSwitchID * kBy2); 141 | 142 | // add all ToR switches 143 | for (int i = 0; i < kSquare; i++) { 144 | if (i % k < kBy2) { 145 | validSwitches.insert(i); 146 | } 147 | } 148 | 149 | // add connected Core switches 150 | for (int i = 0; i < kBy2; i++) { 151 | validSwitches.insert(indexForStartingCoreSwitchID + i); 152 | } 153 | 154 | // add connected Aggr switches 155 | for (int i = 0; i < k; i++) { 156 | validSwitches.insert((k * i) + kBy2 + podLocalAggregationSwitchID); 157 | } 158 | 159 | return validSwitches; 160 | } 161 | } 162 | } else { 163 | // Core switch 164 | switch_id_t localgroupCoreSwitchID = (triggerSwitchID - kSquare) / kBy2; 165 | 166 | // add all ToR and connected Aggr switches 167 | for (int i = 0; i < kSquare; i++) { 168 | if (i % k < kBy2) { 169 | validSwitches.insert(i); 170 | } 171 | else if (i % kBy2 == localgroupCoreSwitchID) { 172 | validSwitches.insert(i); 173 | } 174 | } 175 | 176 | return validSwitches; 177 | } 178 | 179 | return validSwitches; 180 | } 181 | 182 | 183 | int main(int argc, char *argv[]) { 184 | 185 | ndebug_print_yellow("Welcome to data analysis!"); 186 | 187 | int startTriggerID = 0, endTriggerID = 2; 188 | if (argc > 1) { 189 | startTriggerID = std::stoi(argv[1]); 190 | endTriggerID = std::stoi(argv[2]); 191 | } 192 | ndebug_print("Processing triggers from {} to {}.", startTriggerID, endTriggerID); 193 | 194 | Config syndbConfig; 195 | DataParser dataparser(PREFIX_FILE_PATH, PREFIX_STRING_FOR_DATA_FILES, syndbConfig.numSwitches); 196 | dataparser.getTriggerInfo(syndbConfig.numSwitches); 197 | 198 | auto iteratorForTrigger = dataparser.listOfTriggers.begin(); 199 | for (; iteratorForTrigger < dataparser.listOfTriggers.end(); iteratorForTrigger++) { 200 | 201 | switch_id_t triggerSwitchID = iteratorForTrigger->originSwitch; 202 | sim_time_t triggerTime = iteratorForTrigger->triggerTime; 203 | 204 | if (iteratorForTrigger->triggerId > endTriggerID || iteratorForTrigger->triggerId < startTriggerID) { 205 | continue; 206 | } 207 | 208 | ndebug_print_yellow("Trigger ID: {} Switch: {} Time: {}", iteratorForTrigger->triggerId, triggerSwitchID, triggerTime); 209 | 210 | // get p-record window for trigger switch 211 | std::map pRecordWindowForTriggerSwitch = dataparser.getWindowForSwitch(triggerSwitchID, triggerTime, syndbConfig.ringBufferSize, true); 212 | auto iteratorForpRecordWindowForTriggerSwitch = pRecordWindowForTriggerSwitch.begin(); 213 | 214 | std::unordered_set validSwitches; 215 | if (syndbConfig.topoType == TopologyType::FatTree) { 216 | validSwitches = getValidSwitches(triggerSwitchID, syndbConfig.fatTreeTopoK); 217 | } 218 | ndebug_print_yellow("-----------------------"); 219 | 220 | #ifdef DEBUG 221 | for (; iteratorForpRecordWindowForTriggerSwitch != pRecordWindowForTriggerSwitch.end(); iteratorForpRecordWindowForTriggerSwitch++) { 222 | debug_print("{}\t{}\t{}\t{}", iteratorForpRecordWindowForTriggerSwitch->first, 223 | iteratorForpRecordWindowForTriggerSwitch->second.switchIngressTime, 224 | iteratorForpRecordWindowForTriggerSwitch->second.srcHost, 225 | iteratorForpRecordWindowForTriggerSwitch->second.dstHost); 226 | } 227 | #endif 228 | 229 | for (int switchID = 0; switchID < syndbConfig.numSwitches; switchID++) { 230 | 231 | std::string prefixFilePath = PREFIX_FILE_PATH; 232 | std::string prefixStringForFileName = PREFIX_STRING_FOR_DATA_FILES; 233 | std::string pathForDataFolder = prefixFilePath + "/" + prefixStringForFileName + "/" + prefixStringForFileName; 234 | std::string fileName = pathForDataFolder + "_switch_" + std::to_string(switchID) + ".txt"; 235 | 236 | if (syndbConfig.topoType == TopologyType::FatTree) { 237 | auto isValidSwitch = validSwitches.find(switchID); 238 | if (isValidSwitch == validSwitches.end()) { 239 | continue; 240 | } 241 | } 242 | 243 | if (switchID == triggerSwitchID) { 244 | continue; 245 | } 246 | 247 | // ----- Get precord window for switch when it receives the trigger packet ----- 248 | sim_time_t timeForTriggerPacket = iteratorForTrigger->mapOfSwitchTriggerTime.find(switchID)->second; 249 | ndebug_print("\tSwitch: {}\t Trigger Packet Time: {}", switchID, timeForTriggerPacket); 250 | 251 | std::map pRecordWindowForCurrentSwitch = dataparser.getWindowForSwitch(switchID, timeForTriggerPacket, syndbConfig.ringBufferSize, false); 252 | 253 | // ----- For each packet in the trigger switch precord window find the packet in current switch ID ----- 254 | double numberOfExpectedPackets = 0.0, numberOfCommonPackets = 0.0; 255 | auto iteratorForpRecordWindowForTriggerSwitch = pRecordWindowForTriggerSwitch.begin(); 256 | auto iteratorForpRecordWindowForCurrentSwitch = pRecordWindowForCurrentSwitch.begin(); 257 | sim_time_t timeOfMostRecentCommonpRecord = 0, timeOfLeastRecentCommonpRecord = 0; 258 | pkt_id_t packetIDOfLeastRecentExpectedRecord, packetIDOfMostRecentCommonRecord; 259 | 260 | #ifdef DEBUG 261 | debug_print("-----------------------"); 262 | for (; iteratorForpRecordWindowForCurrentSwitch != pRecordWindowForCurrentSwitch.end(); iteratorForpRecordWindowForCurrentSwitch++) { 263 | debug_print("{}\t{}", iteratorForpRecordWindowForCurrentSwitch->first, 264 | iteratorForpRecordWindowForCurrentSwitch->second.switchIngressTime); 265 | } 266 | iteratorForpRecordWindowForCurrentSwitch = pRecordWindowForCurrentSwitch.begin(); 267 | #endif 268 | 269 | if (syndbConfig.topoType == TopologyType::FatTree) { 270 | for (; iteratorForpRecordWindowForTriggerSwitch != pRecordWindowForTriggerSwitch.end(); iteratorForpRecordWindowForTriggerSwitch++) { 271 | 272 | auto route = getRoute(iteratorForpRecordWindowForTriggerSwitch->second.srcHost, 273 | iteratorForpRecordWindowForTriggerSwitch->second.dstHost, 274 | syndbConfig.fatTreeTopoK); 275 | 276 | int indexOfTriggerSwitch = -1, indexOfCurrentSwitch = -1; 277 | for (int routeIteratorIndex = 0; routeIteratorIndex < route.size(); routeIteratorIndex++) { 278 | if (route[routeIteratorIndex] == triggerSwitchID) { 279 | indexOfTriggerSwitch = routeIteratorIndex; 280 | } else if (route[routeIteratorIndex] == switchID) { 281 | indexOfCurrentSwitch = routeIteratorIndex; 282 | } 283 | } 284 | 285 | if (indexOfCurrentSwitch != -1 && indexOfCurrentSwitch < indexOfTriggerSwitch) 286 | { 287 | numberOfExpectedPackets++; 288 | 289 | if (iteratorForpRecordWindowForCurrentSwitch == pRecordWindowForCurrentSwitch.end()) { 290 | continue; 291 | } 292 | 293 | if (iteratorForpRecordWindowForTriggerSwitch->first < iteratorForpRecordWindowForCurrentSwitch->first) { 294 | continue; 295 | } 296 | 297 | while (iteratorForpRecordWindowForTriggerSwitch->first > iteratorForpRecordWindowForCurrentSwitch->first && 298 | iteratorForpRecordWindowForCurrentSwitch != pRecordWindowForCurrentSwitch.end()) { 299 | ++iteratorForpRecordWindowForCurrentSwitch; 300 | } 301 | if (iteratorForpRecordWindowForTriggerSwitch->first == iteratorForpRecordWindowForCurrentSwitch->first) { 302 | numberOfCommonPackets++; 303 | 304 | if (iteratorForpRecordWindowForTriggerSwitch->second.switchIngressTime > timeOfMostRecentCommonpRecord) { 305 | timeOfMostRecentCommonpRecord = iteratorForpRecordWindowForTriggerSwitch->second.switchIngressTime; 306 | packetIDOfMostRecentCommonRecord = iteratorForpRecordWindowForTriggerSwitch->first; 307 | } 308 | 309 | if (iteratorForpRecordWindowForTriggerSwitch->second.switchIngressTime < timeOfLeastRecentCommonpRecord || timeOfLeastRecentCommonpRecord == 0) { 310 | timeOfLeastRecentCommonpRecord = iteratorForpRecordWindowForTriggerSwitch->second.switchIngressTime; 311 | } 312 | } 313 | } 314 | } 315 | 316 | // ----- Calculate correlation and time lost statistics ----- 317 | if (numberOfExpectedPackets != 0) { 318 | 319 | if (timeOfLeastRecentCommonpRecord > timeOfMostRecentCommonpRecord && numberOfCommonPackets == 0) { 320 | timeOfLeastRecentCommonpRecord = timeOfMostRecentCommonpRecord; 321 | } 322 | 323 | ndebug_print("\tSwitch ID: {}\t Expected Packets: {}\t Correlation: {}%\t Common History: {}ns", 324 | switchID, 325 | int(numberOfExpectedPackets), 326 | 100 * numberOfCommonPackets / numberOfExpectedPackets, 327 | timeOfMostRecentCommonpRecord - timeOfLeastRecentCommonpRecord); 328 | } 329 | } else if (syndbConfig.topoType == TopologyType::Line) { 330 | 331 | for (; iteratorForpRecordWindowForTriggerSwitch != pRecordWindowForTriggerSwitch.end(); iteratorForpRecordWindowForTriggerSwitch++) { 332 | auto isPacketInCurrentSwitchID = pRecordWindowForCurrentSwitch.find(iteratorForpRecordWindowForTriggerSwitch->first); 333 | if (isPacketInCurrentSwitchID != pRecordWindowForCurrentSwitch.end()) { 334 | numberOfCommonPackets++; 335 | 336 | if (isPacketInCurrentSwitchID->second.switchIngressTime > timeOfMostRecentCommonpRecord) { 337 | timeOfMostRecentCommonpRecord = isPacketInCurrentSwitchID->second.switchIngressTime; 338 | packetIDOfMostRecentCommonRecord = isPacketInCurrentSwitchID->first; 339 | } 340 | } 341 | } // loop iterating over all packets in trigger switch window 342 | 343 | 344 | float correlation = ((float)numberOfCommonPackets / (float)syndbConfig.ringBufferSize); 345 | ndebug_print("\tSwitch ID: {}\t Correlation: {}%\t ", 346 | switchID, 347 | correlation * 100); 348 | } 349 | 350 | 351 | } // loop iterating over all non-trigger switches 352 | 353 | } // loop iterating over all triggers 354 | 355 | return 0; 356 | } 357 | 358 | -------------------------------------------------------------------------------- /data-analysis/dataparser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "data-analysis/dataparser.hpp" 5 | 6 | #define LOGGING 0 7 | #include "utils/logger.hpp" 8 | 9 | 10 | /** 11 | * Execute a shell command passed to the function 12 | */ 13 | std::string DataParser::executeShellCommand(const char* command) { 14 | std::array buffer; 15 | std::string result; 16 | std::unique_ptr pipe(popen(command, "r"), pclose); 17 | if (!pipe) { 18 | throw std::runtime_error("popen() failed!"); 19 | } 20 | while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { 21 | result += buffer.data(); 22 | } 23 | return result; 24 | } 25 | 26 | /** 27 | * Create and open file pointers for all data files. 28 | */ 29 | DataParser::DataParser(std::string prefixFilePath, std::string prefixStringForFileName, switch_id_t numberOfSwitches) { 30 | 31 | std::string pathForDataFolder = prefixFilePath + "/" + prefixStringForFileName +"/" + prefixStringForFileName; 32 | ndebug_print_yellow("Reading files {}*.txt", pathForDataFolder); 33 | // open all file pointers in write/output mode 34 | for (int i = 0; i < numberOfSwitches; i++) { 35 | std::string fileName = pathForDataFolder + "_switch_" + std::to_string(i) + ".txt"; 36 | std::fstream file (fileName, std::fstream::in); 37 | this->switchFilePointers.push_back(std::move(file)); 38 | } 39 | 40 | this->triggerFilePointer.open(pathForDataFolder + "_trigger.txt", std::fstream::in); 41 | this->sourceDestinationFilePointer.open(pathForDataFolder + "_sourceDestination.txt", std::fstream::in); 42 | 43 | } 44 | 45 | 46 | DataParser::~DataParser() { 47 | // close all file pointers 48 | for (int i = 0; i < this->switchFilePointers.size(); i++) { 49 | this->switchFilePointers[i].close(); 50 | } 51 | 52 | this->triggerFilePointer.close(); 53 | this->sourceDestinationFilePointer.close(); 54 | 55 | } 56 | 57 | 58 | /** 59 | * Get the p-record window for a switch at a particular point of time. 60 | * 61 | * @param triggerTime Time the switch received/generated the trigger packet 62 | * @param windowSize Size of the p-record window 63 | * @param isTriggerSwitch Boolean to denote if the switch is trigger switch. 64 | * If the switch is trigger switch we get the host and destination 65 | * for each packet in its trigger window. 66 | * 67 | */ 68 | std::map DataParser::getWindowForSwitch(switch_id_t switchID, sim_time_t triggerTime, pkt_id_t windowSize, bool isTriggerSwitch) { 69 | 70 | std::map pRecordWindow; 71 | 72 | // get line number of last packet before triggerTime 73 | std::string prefixFilePath = PREFIX_FILE_PATH; 74 | std::string prefixStringForFileName = PREFIX_STRING_FOR_DATA_FILES; 75 | std::string pathForDataFolder = prefixFilePath + "/" + prefixStringForFileName + "/" + prefixStringForFileName; 76 | std::string fileName = pathForDataFolder + "_switch_" + std::to_string(switchID) + ".txt"; 77 | std::string prefixForCommandToGetLineNumber = "cat " + fileName + " | cut -f 1 |" + "grep -n -w -F "; 78 | std::string suffixForCommandToGetLineNumber = " | cut -d \":\" -f 1"; 79 | uint64_t startLineNumber = 0; 80 | uint64_t skipBytes = 0; 81 | 82 | while (triggerTime > 0) { 83 | 84 | std::string commandToGetLineNumber = prefixForCommandToGetLineNumber + std::to_string(triggerTime) + suffixForCommandToGetLineNumber; 85 | std::string lineNumber = this->executeShellCommand(commandToGetLineNumber.c_str()); 86 | 87 | if (lineNumber.size() != 0) { 88 | startLineNumber = std::stoll(lineNumber); 89 | break; 90 | } 91 | triggerTime--; 92 | } 93 | 94 | #ifdef DEBUG 95 | debug_print("Starting line number is: {}", startLineNumber); 96 | debug_print("Starting trigger time is: {}", triggerTime); 97 | #endif 98 | 99 | this->switchFilePointers[switchID].clear(); 100 | this->switchFilePointers[switchID].seekg(0); 101 | for (uint64_t currLineNumber = 0; currLineNumber < startLineNumber - 1; ++currLineNumber){ 102 | sim_time_t tempIngressTime; 103 | 104 | if (this->switchFilePointers[switchID].ignore(std::numeric_limits::max(), this->switchFilePointers[switchID].widen('\n'))){ 105 | // skip till the line before start of pRecord window 106 | } 107 | } 108 | 109 | pkt_id_t numberOfPacketsAddedTopRecordWindow = 0; 110 | pkt_id_t smallestPktID = 0, largestPktID = 0; 111 | 112 | while (numberOfPacketsAddedTopRecordWindow < windowSize && ! this->switchFilePointers[switchID].eof()) { 113 | PacketInfo currentPacket; 114 | this->switchFilePointers[switchID] >> currentPacket.switchIngressTime >> currentPacket.id; 115 | pRecordWindow.insert(std::pair(currentPacket.id, currentPacket)); 116 | 117 | if (smallestPktID == 0 || smallestPktID > currentPacket.id) { 118 | smallestPktID = currentPacket.id; 119 | } 120 | if (largestPktID < currentPacket.id) { 121 | largestPktID = currentPacket.id; 122 | } 123 | 124 | numberOfPacketsAddedTopRecordWindow++; 125 | } 126 | 127 | debug_print("pRecord Window Size for Switch ID {} : {}", switchID, numberOfPacketsAddedTopRecordWindow); 128 | 129 | #ifdef DEBUG 130 | auto it = pRecordWindow.begin(); 131 | debug_print("--- pRecord window for switch {} ---", switchID); 132 | while (it != pRecordWindow.end()) { 133 | debug_print("{}\t{}", it->first, it->second.switchIngressTime); 134 | it++; 135 | } 136 | #endif 137 | 138 | debug_print("SUCCESS: Obtained pRecord Window for {}.", switchID); 139 | 140 | if (isTriggerSwitch) { 141 | 142 | // triggerTime now contains the tstamp of the most recent packet before the trigger packet is received 143 | sim_time_t timeOfMostRecentpRecord = triggerTime; 144 | // the next line to read in the file contains the packet most recently removed from the pRecord window 145 | sim_time_t timeOfLeastRecentpRecord = 0; 146 | this->switchFilePointers[switchID] >> timeOfLeastRecentpRecord; 147 | sim_time_t historyRecordedInpRecordWindow = 0; 148 | if (timeOfLeastRecentpRecord < timeOfMostRecentpRecord) { 149 | historyRecordedInpRecordWindow = timeOfMostRecentpRecord - timeOfLeastRecentpRecord - 1; 150 | } else { 151 | historyRecordedInpRecordWindow = timeOfMostRecentpRecord - 1; 152 | } 153 | ndebug_print("Trigger Switch pRecord Window History {}ns", historyRecordedInpRecordWindow); 154 | ndebug_print("Smallest pkt ID: {}\t Largest pkt ID:{}", smallestPktID, largestPktID); 155 | 156 | // skip lines in sourceDestination file 157 | 158 | fileName = pathForDataFolder + "_sourceDestination.txt"; 159 | prefixForCommandToGetLineNumber = "LC_ALL=C grep -m 1 -b -w -F "; 160 | std::string commandToGetSkipBytes = prefixForCommandToGetLineNumber + std::to_string(smallestPktID) + " " + fileName +suffixForCommandToGetLineNumber; 161 | debug_print("{}", commandToGetSkipBytes); 162 | std::string skipBytesString = this->executeShellCommand(commandToGetSkipBytes.c_str()); 163 | skipBytes = std::stoll(skipBytesString); 164 | debug_print("Skip Bytes for sourceDestination file: {}", skipBytes); 165 | 166 | startLineNumber = smallestPktID - 1; // pkt ID starts from 0 167 | this->sourceDestinationFilePointer.clear(); 168 | this->sourceDestinationFilePointer.seekg(skipBytes); 169 | 170 | pkt_id_t packetId = 0; 171 | host_id_t source, destination; 172 | long numberOfCompletedpRecords = 0; 173 | auto pRecordIterator = pRecordWindow.begin(); 174 | while (packetId <= largestPktID) { 175 | this->sourceDestinationFilePointer >> packetId >> source >> destination; 176 | 177 | // auto positionInMap = pRecordWindow.find(packetId); 178 | if (pRecordIterator->first == packetId) { 179 | debug_print("{}", packetId); 180 | 181 | pRecordIterator->second.srcHost = source; 182 | pRecordIterator->second.dstHost = destination; 183 | numberOfCompletedpRecords++; 184 | 185 | pRecordIterator++; 186 | skipBytes = this->sourceDestinationFilePointer.tellg(); 187 | skipBytes += (pRecordIterator->first - packetId) * 21; 188 | this->sourceDestinationFilePointer.seekg(skipBytes); 189 | if (this->sourceDestinationFilePointer.ignore(std::numeric_limits::max(), this->sourceDestinationFilePointer.widen('\n'))){ 190 | // skip till the line before start of pRecord window 191 | } 192 | 193 | #ifdef DEBUG 194 | if (numberOfCompletedpRecords >= windowSize) { 195 | break; 196 | ndebug_print("Found source and destination for all packets in the precord window."); 197 | } 198 | #endif 199 | } else if (pRecordIterator->first < packetId) { 200 | skipBytes -= (packetId - pRecordIterator->first) * 21; 201 | this->sourceDestinationFilePointer.seekg(skipBytes); 202 | if (this->sourceDestinationFilePointer.ignore(std::numeric_limits::max(), this->sourceDestinationFilePointer.widen('\n'))){ 203 | // skip till the line before start of pRecord window 204 | } 205 | } 206 | } 207 | } 208 | 209 | return pRecordWindow; 210 | } 211 | 212 | 213 | /** 214 | * Get information regarding triggers from the trigger dump file. 215 | */ 216 | void DataParser::getTriggerInfo(switch_id_t numberOfSwitches) { 217 | ndebug_print("Reading Trigger File."); 218 | 219 | while (! this->triggerFilePointer.eof()) { 220 | TriggerInfo trigger; 221 | this->triggerFilePointer >> trigger.triggerId >> trigger.triggerTime >> trigger.originSwitch; 222 | if (this->triggerFilePointer.eof()) { 223 | break; 224 | } 225 | debug_print_yellow("Trigger ID: {}\t Switch: {}\t Time: {}", trigger.triggerId, trigger.triggerTime, trigger.originSwitch); 226 | 227 | for (int i = 0; i < numberOfSwitches-1; i++) { 228 | sim_time_t timeOfReceivingTriggerPacket; 229 | switch_id_t switchID; 230 | this->triggerFilePointer >> switchID >> timeOfReceivingTriggerPacket; 231 | debug_print("\t Switch: {}\t Time: {}", switchID, timeOfReceivingTriggerPacket); 232 | trigger.mapOfSwitchTriggerTime.insert(std::pair(switchID, timeOfReceivingTriggerPacket)); 233 | } 234 | this->listOfTriggers.push_back(trigger); 235 | } 236 | 237 | ndebug_print_yellow("Read {} triggers.", this->listOfTriggers.size()); 238 | } -------------------------------------------------------------------------------- /data-analysis/dataparser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DATAPARSER_H 2 | #define DATAPARSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils/types.hpp" 9 | 10 | #define PREFIX_STRING_FOR_DATA_FILES "dump" 11 | #define PREFIX_FILE_PATH "/home/user/syndb" 12 | 13 | 14 | struct PacketInfo { 15 | pkt_id_t id; 16 | host_id_t srcHost; 17 | host_id_t dstHost; 18 | 19 | sim_time_t switchIngressTime; 20 | }; 21 | 22 | struct TriggerInfo { 23 | int triggerId; 24 | 25 | switch_id_t originSwitch; 26 | sim_time_t triggerTime; 27 | std::unordered_map mapOfSwitchTriggerTime; 28 | }; 29 | 30 | 31 | struct DataParser { 32 | 33 | /* data */ 34 | std::string prefixStringForFileName; 35 | 36 | std::fstream triggerFilePointer, sourceDestinationFilePointer; 37 | std::vector switchFilePointers; 38 | 39 | std::vector listOfTriggers; 40 | 41 | ~DataParser(); 42 | DataParser() = default; 43 | DataParser(std::string prefixFilePath, std::string prefixStringForFileName, switch_id_t numberOfSwitches); 44 | 45 | std::string executeShellCommand(const char* command); 46 | void getTriggerInfo(switch_id_t numberOfSwitches); 47 | std::map getWindowForSwitch(switch_id_t switchID, sim_time_t triggerTime, pkt_id_t windowSize, bool isTriggerSwitch); 48 | float getCorrelationBetweenPrecordWindows(std::map precordWindowForTriggerSwitch, std::map precordWindowForCurrentSwitch); 49 | }; 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /data-analysis/getTopLinkUtil.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ];then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | sort -g -r $1 -o $1 9 | 10 | # get number of top links (lines) 11 | numLines=$(wc -l $1 | cut -d' ' -f1) 12 | topLines=$((($numLines * 5 + 50) / 100)) # +50 is for rounding 13 | 14 | # echo $topLines 15 | 16 | topLowest=$(head -n $topLines $1 | tail -n1) 17 | topHighest=$(head -n 1 $1) 18 | 19 | echo $topLowest - $topHighest 20 | 21 | -------------------------------------------------------------------------------- /devtests/devtests.cpp: -------------------------------------------------------------------------------- 1 | #include "simulation/simulation.hpp" 2 | #include "utils/logger.hpp" 3 | #include "devtests/devtests.hpp" 4 | 5 | #ifdef DEBUG 6 | 7 | void showFatTreeTopoRoutingTables(){ 8 | 9 | std::shared_ptr fattreetopo = std::dynamic_pointer_cast(syndbSim.topo); 10 | 11 | debug_print_yellow("\n------------- Routing Tables [Core Switches] -------------"); 12 | auto it = fattreetopo->coreSwitches.begin(); 13 | for(it; it != fattreetopo->coreSwitches.end(); it++){ 14 | std::shared_ptr coreSwitch = std::dynamic_pointer_cast(*it); 15 | 16 | debug_print("Core Switch {}:", coreSwitch->id); 17 | auto entry_it = coreSwitch->routingTable.begin(); 18 | for(entry_it; entry_it != coreSwitch->routingTable.end(); entry_it++){ 19 | debug_print("{} --> {}", entry_it->first, entry_it->second); 20 | } 21 | } 22 | 23 | debug_print_yellow("\n------------- Routing Tables [Aggr Switches] -------------"); 24 | for(int i = 0; i < fattreetopo->k; i++){ // iterate over all pods 25 | for(int j = 0; j < (fattreetopo->k/2); j++){ 26 | std::shared_ptr aggrSwitch = std::dynamic_pointer_cast(fattreetopo->pods[i]->aggrSwitches[j]); 27 | 28 | debug_print("Aggr Switch {}:", aggrSwitch->id); 29 | auto entry_it = aggrSwitch->routingTable.begin(); 30 | for(entry_it; entry_it != aggrSwitch->routingTable.end(); entry_it++){ 31 | debug_print("{} --> {}", entry_it->first, entry_it->second); 32 | } 33 | } 34 | } 35 | 36 | debug_print_yellow("\n------------- Routing Tables [ToR Switches] -------------"); 37 | for(int i = 0; i < fattreetopo->k; i++){ // iterate over all pods 38 | for(int j = 0; j < (fattreetopo->k/2); j++){ 39 | std::shared_ptr torSwitch = std::dynamic_pointer_cast(fattreetopo->pods[i]->torSwitches[j]); 40 | 41 | debug_print("ToR Switch {}:", torSwitch->id); 42 | auto entry_it = torSwitch->routingTable.begin(); 43 | for(entry_it; entry_it != torSwitch->routingTable.end(); entry_it++){ 44 | debug_print("{} --> {}", entry_it->first, entry_it->second); 45 | } 46 | } 47 | } 48 | 49 | } 50 | 51 | 52 | void showSimpleTopoRingBuffers(){ 53 | #if RING_BUFFER 54 | switch_p s0, s1, s2; 55 | 56 | s0 = syndbSim.topo->getSwitchById(0); 57 | s1 = syndbSim.topo->getSwitchById(1); 58 | s2 = syndbSim.topo->getSwitchById(2); 59 | 60 | debug_print_yellow("\nRing buffer for s0:"); 61 | s0->ringBuffer.printRingBuffer(); 62 | 63 | debug_print_yellow("\nRing buffer for s1:"); 64 | s1->ringBuffer.printRingBuffer(); 65 | 66 | debug_print_yellow("\nRing buffer for s2:"); 67 | s2->ringBuffer.printRingBuffer(); 68 | 69 | debug_print_yellow("\nActual Ring buffer for s0:"); 70 | s0->ringBuffer.printActualRingBuffer(5); 71 | 72 | debug_print_yellow("\nActual Ring buffer for s1:"); 73 | s1->ringBuffer.printActualRingBuffer(5); 74 | 75 | debug_print_yellow("\nActual Ring buffer for s2:"); 76 | s2->ringBuffer.printActualRingBuffer(5); 77 | #endif 78 | } 79 | 80 | void testRingBufferOps(){ 81 | #if RING_BUFFER 82 | switch_p s0 = syndbSim.topo->getSwitchById(0); 83 | 84 | for(int i=1; i <= 8; i++){ 85 | s0->ringBuffer.insertPrecord(i, i); 86 | } 87 | 88 | s0->ringBuffer.printActualRingBuffer(10); 89 | #endif 90 | } 91 | 92 | void addTriggerPkts(){ 93 | 94 | if(syndbConfig.topoType == TopologyType::Simple){ 95 | const sim_time_t increment = 3000; 96 | static sim_time_t nextSendTime = 0; 97 | 98 | Switch* srcSwitch = syndbSim.topo->getSwitchById(0); 99 | 100 | if(syndbSim.currTime >= nextSendTime){ 101 | 102 | srcSwitch->generateTrigger(); 103 | 104 | nextSendTime += increment; 105 | } 106 | } 107 | else if(syndbConfig.topoType == TopologyType::FatTree){ 108 | static bool generatedAlready = false; 109 | 110 | if(generatedAlready == false){ 111 | // Generate a single trigger on switchID 2 112 | syndbSim.topo->getSwitchById(9)->generateTrigger(); 113 | generatedAlready = true; 114 | } 115 | } 116 | 117 | } 118 | 119 | void checkRemainingQueuingAtLinks(){ 120 | // Checking queueing on all the links 121 | auto it1 = syndbSim.topo->torLinkVector.begin(); 122 | debug_print_yellow("nextPktSendTime on ToR links at time {}ns", syndbSim.currTime); 123 | for (it1; it1 != syndbSim.topo->torLinkVector.end(); it1++){ 124 | debug_print("Link ID {}: towards host: {} | towards tor: {}", (*it1)->id, (*it1)->next_idle_time_to_host, (*it1)->next_idle_time_to_tor); 125 | } 126 | 127 | auto it2 = syndbSim.topo->networkLinkVector.begin(); 128 | debug_print_yellow("nextPktSendTime on Network links at time {}ns", syndbSim.currTime); 129 | for (it2; it2 != syndbSim.topo->networkLinkVector.end(); it2++){ 130 | auto map = (*it2)->next_idle_time; 131 | 132 | auto it3 = map.begin(); 133 | switch_id_t sw1 = it3->first; 134 | sim_time_t dir1 = it3->second; 135 | it3++; 136 | switch_id_t sw2 = it3->first; 137 | sim_time_t dir2 = it3->second; 138 | ndebug_print("Link ID {} Normal: towards {}: {} | towards {}: {}", (*it2)->id, sw1, dir1, sw2, dir2); 139 | 140 | auto mapPriority = (*it2)->next_idle_time_priority; 141 | auto it4 = mapPriority.begin(); 142 | sw1 = it4->first; 143 | dir1 = it4->second; 144 | it4++; 145 | sw2 = it4->first; 146 | dir2 = it4->second; 147 | ndebug_print("Link ID {} Priority: towards {}: {} | towards {}: {}", (*it2)->id, sw1, dir1, sw2, dir2); 148 | } 149 | } 150 | 151 | 152 | 153 | void testSharedPtrDestruction(){ 154 | 155 | // Create and add packetEvents 156 | normalpkt_p p1, p2; 157 | p1 = normalpkt_p(new NormalPkt(1, 1500)); 158 | p2 = normalpkt_p(new NormalPkt(2, 1500)); 159 | 160 | pktevent_p newPktEvent1 = pktevent_p(new PktEvent()); 161 | pktevent_p newPktEvent2 = pktevent_p(new PktEvent()); 162 | 163 | newPktEvent1->pkt = p1; 164 | newPktEvent2->pkt = p2; 165 | 166 | syndbSim.NormalPktEventList.push_back(newPktEvent1); 167 | syndbSim.NormalPktEventList.push_back(newPktEvent2); 168 | 169 | std::list>::iterator> toDelete; 170 | 171 | auto it = syndbSim.NormalPktEventList.begin(); 172 | 173 | while(it != syndbSim.NormalPktEventList.end() ){ 174 | debug_print(fmt::format("Found pkt with id {} inside PktEvent", (*it)->pkt->id)); 175 | toDelete.push_back(it); 176 | 177 | it++; 178 | } 179 | 180 | debug_print(fmt::format("Deleting {} NormalPktEvents...", toDelete.size())); 181 | auto it2 = toDelete.begin(); 182 | 183 | while (it2 != toDelete.end()){ 184 | syndbSim.NormalPktEventList.erase(*it2); 185 | it2++; 186 | } 187 | } 188 | 189 | #endif // end of DEBUG 190 | -------------------------------------------------------------------------------- /devtests/devtests.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEVTESTS_H 2 | #define DEVTESTS_H 3 | 4 | #include "utils/types.hpp" 5 | #include "topology/fattree_topology.hpp" 6 | 7 | /* 8 | Iterates over all links (ToR and Network). 9 | For each link, shows next_idle_time in both directions. 10 | Independent of topology. But too many links give cumbersome output. 11 | */ 12 | void checkRemainingQueuingAtLinks(); 13 | 14 | 15 | 16 | /* 17 | Quick test for shared_ptr destruction. 18 | Independent of any topology. 19 | */ 20 | void testSharedPtrDestruction(); 21 | 22 | /* 23 | Periodically adds TriggerPkts to test their latency. 24 | Assumes SimpleTopology. 25 | */ 26 | void addTriggerPkts(); 27 | 28 | /* 29 | Test basic operations of the ring buffer in Isolation of the main simulation 30 | */ 31 | void testRingBufferOps(); 32 | 33 | /* 34 | Show the ring buffer states of the 3 switches in SimpleTopo 35 | */ 36 | void showSimpleTopoRingBuffers(); 37 | 38 | /* 39 | Prints routing tables of all switches of a FatTree topo 40 | */ 41 | void showFatTreeTopoRoutingTables(); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /preProcessData.sh: -------------------------------------------------------------------------------- 1 | filesInDir=$(ls ./dump*switch*.txt) 2 | 3 | for fileName in $filesInDir 4 | do 5 | echo "Sorting $fileName" 6 | sort -n -r -k1 $fileName -o $fileName 7 | done 8 | 9 | filesInDir=$(ls ./dump*sourceDestination.txt) 10 | for fileName in $filesInDir 11 | do 12 | echo "Sorting $fileName" 13 | sort -n -k1 $fileName -o $fileName 14 | done -------------------------------------------------------------------------------- /question2.sh: -------------------------------------------------------------------------------- 1 | line=$(cat temp.txt | cut -d$'\t' -f 2 | grep -n -w "1252" | cut -d ":" -f 1) 2 | line=$((line + 1000000)) 3 | sed -n "$line"p temp.txt 4 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ];then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | echo "Running expt: $1" 9 | 10 | ./syndb-sim 11 | 12 | curl -X POST -H "Content-Type: application/json" -d "{\"value1\":\"$1\"}" https://maker.ifttt.com/trigger/SyNDB-sim_completed/with/key/gB88SULNID5Te0obIzRqK-6a-6EO6tHSSBT5ulPEBbT 13 | 14 | echo "" 15 | -------------------------------------------------------------------------------- /run_analysis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -lt 4 ];then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | startTrigger=$1 9 | endTrigger=$2 10 | increment=$3 11 | server=$4 12 | 13 | echo "Running triggers from $startTrigger to $endTrigger with each run processing $increment triggers!!!" 14 | 15 | make cleaner 16 | make -j20 analysis 17 | 18 | while [ $startTrigger -lt $endTrigger ] 19 | do 20 | tempEndTrigger=$(($startTrigger + $increment - 1)) 21 | cp syndb-analysis syndb-analysis-$startTrigger-$server 22 | echo "screen -S $server-$startTrigger bash -c './syndb-analysis-$startTrigger-$server $startTrigger $tempEndTrigger 2>&1 | tee ./data-analysis-output/patronus/storage/dump_1_6_35/output_for_triggers_$startTrigger-$tempEndTrigger.txt'" 23 | read varname 24 | startTrigger=$(($tempEndTrigger + 1)) 25 | # echo "$startTrigger" 26 | done 27 | 28 | -------------------------------------------------------------------------------- /simulation/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.hpp" 2 | 3 | 4 | Config syndbConfig; 5 | -------------------------------------------------------------------------------- /simulation/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #define CONFIG_DEFAULT 0 5 | #define CONFIG_VALIDATION 1 6 | #define CONFIG_EVALUATION 2 7 | #define CONFIG_PROFILING 3 8 | #define CONFIG_TEST 4 9 | 10 | #ifndef CONFIG 11 | #define CONFIG CONFIG_DEFAULT 12 | #endif 13 | 14 | #if CONFIG == CONFIG_DEFAULT 15 | #include "simulation/config_default.hpp" 16 | #elif CONFIG == CONFIG_VALIDATION 17 | #include "simulation/config_validation.hpp" 18 | #elif CONFIG == CONFIG_EVALUATION 19 | #include "simulation/config_evaluation.hpp" 20 | #elif CONFIG == CONFIG_PROFILING 21 | #include "simulation/config_profiling.hpp" 22 | #elif CONFIG == CONFIG_TEST 23 | #include "simulation/config_test.hpp" 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /simulation/config_default.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils/types.hpp" 4 | 5 | #ifndef LOGGING 6 | #define LOGGING 1 7 | #endif 8 | #define HOP_DELAY_NOISE 1 9 | #define RING_BUFFER 0 10 | #define TRIGGERS_ENABLED 1 11 | #define INCASTS_ENABLED 1 12 | 13 | typedef struct Config 14 | { 15 | static const sim_time_t timeIncrementNs = 100; 16 | 17 | // IMPORTANT: update numHosts and numSwitches as per the topology 18 | 19 | /* FatTree Topo 100ms Expt Params */ 20 | static const ft_scale_t fatTreeTopoK = 4; // Fat Tree scale k 21 | const uint8_t ftMixedPatternPercentIntraRack = 75; 22 | const uint8_t targetBaseNetworkLoadPercent = 40; /* 30 -> 25%, 40 -> 31%, 50 -> 36% */ 23 | const float totalTimeMSecs = 10; 24 | const TopologyType topoType = TopologyType::FatTree; 25 | static const host_id_t numHosts = (fatTreeTopoK * fatTreeTopoK * fatTreeTopoK)/4; 26 | static const switch_id_t numSwitches = (fatTreeTopoK * fatTreeTopoK) + ((fatTreeTopoK * fatTreeTopoK)/4); 27 | const TrafficPatternType trafficPatternType = TrafficPatternType::FtMixed; 28 | const TrafficGenType trafficGenType = TrafficGenType::Distribution; 29 | const sim_time_t triggerInitialDelay = 5000000; // 5ms for k=4 fatTree topo 10ms run and 50K ring buffer 30 | static const uint numTriggersPerSwitchType = 1; 31 | const link_speed_gbps_t torLinkSpeedGbps = 100; 32 | const link_speed_gbps_t networkLinkSpeedGbps = 100; 33 | static const int numCoreSwitches = (fatTreeTopoK/2) * (fatTreeTopoK/2); 34 | 35 | 36 | /* Incast Related Params */ 37 | const uint8_t percentIncastTime = 10; 38 | const host_id_t incastFanInRatio = numHosts / 4; // 25% of the total hosts 39 | const host_id_t percentTargetIncastHosts = 30; 40 | 41 | // const load_t hostTrafficGenLoadPercent = 100; 42 | 43 | const sim_time_t switchHopDelayNs = 1000; 44 | const sim_time_t minSwitchHopDelayNs = 950; 45 | const sim_time_t maxSwitchHopDelayNs = 1050; 46 | 47 | // SyNDB specific config options 48 | static const pkt_id_t ringBufferSize = 50000; // 50K 49 | static const pkt_size_t triggerPktSize = 60; 50 | 51 | const std::string packetSizeDistFile = "traffic-dist/fb_webserver_packetsizedist_cdf.csv"; 52 | const std::string flowArrivalDistFile = "traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"; 53 | 54 | /* Other params NOT used, but needed for compilation. */ 55 | // LineTopo 10ms Expt Params 56 | const pkt_size_t fixedPktSizeForSimpleTrafficGen = 101; //1500; 57 | 58 | } Config; 59 | 60 | extern Config syndbConfig; 61 | 62 | -------------------------------------------------------------------------------- /simulation/config_evaluation.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils/types.hpp" 4 | 5 | #ifndef LOGGING 6 | #define LOGGING 1 7 | #endif 8 | #define HOP_DELAY_NOISE 1 9 | #define RING_BUFFER 0 10 | #define TRIGGERS_ENABLED 1 11 | #define INCASTS_ENABLED 1 12 | 13 | typedef struct Config 14 | { 15 | static const sim_time_t timeIncrementNs = 100; 16 | 17 | // IMPORTANT: update numHosts and numSwitches as per the topology 18 | 19 | /* FatTree Topo 100ms Expt Params */ 20 | static const ft_scale_t fatTreeTopoK = 24; // Fat Tree scale k 21 | const uint8_t ftMixedPatternPercentIntraRack = 75; 22 | const uint8_t targetBaseNetworkLoadPercent = 40; /* 30 -> 25%, 40 -> 31%, 50 -> 36% */ 23 | const float totalTimeMSecs = 100; 24 | const TopologyType topoType = TopologyType::FatTree; 25 | static const host_id_t numHosts = (fatTreeTopoK * fatTreeTopoK * fatTreeTopoK)/4; 26 | static const switch_id_t numSwitches = (fatTreeTopoK * fatTreeTopoK) + ((fatTreeTopoK * fatTreeTopoK)/4); 27 | const TrafficPatternType trafficPatternType = TrafficPatternType::FtMixed; 28 | const TrafficGenType trafficGenType = TrafficGenType::Distribution; 29 | const sim_time_t triggerInitialDelay = 15000000; // 15ms for k=24 fatTree topo 100ms run 30 | static const uint numTriggersPerSwitchType = 100; 31 | const link_speed_gbps_t torLinkSpeedGbps = 100; 32 | const link_speed_gbps_t networkLinkSpeedGbps = 100; 33 | static const int numCoreSwitches = (fatTreeTopoK/2) * (fatTreeTopoK/2); 34 | 35 | /* Incast Related Params */ 36 | const uint8_t percentIncastTime = 10; 37 | const host_id_t incastFanInRatio = numHosts / 4; // 25% of the total hosts 38 | const host_id_t percentTargetIncastHosts = 30; 39 | 40 | // const load_t hostTrafficGenLoadPercent = 100; 41 | 42 | const sim_time_t switchHopDelayNs = 1000; 43 | const sim_time_t minSwitchHopDelayNs = 950; 44 | const sim_time_t maxSwitchHopDelayNs = 1050; 45 | 46 | // SyNDB specific config options 47 | static const pkt_id_t ringBufferSize = 1000000; // 1M 48 | static const pkt_size_t triggerPktSize = 60; 49 | 50 | const std::string packetSizeDistFile = "traffic-dist/fb_webserver_packetsizedist_cdf.csv"; 51 | const std::string flowArrivalDistFile = "traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"; 52 | 53 | /* Other params NOT used, but needed for compilation. */ 54 | // LineTopo 10ms Expt Params 55 | const pkt_size_t fixedPktSizeForSimpleTrafficGen = 101; //1500; 56 | 57 | } Config; 58 | 59 | extern Config syndbConfig; 60 | 61 | -------------------------------------------------------------------------------- /simulation/config_profiling.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils/types.hpp" 4 | 5 | #ifndef LOGGING 6 | #define LOGGING 0 7 | #endif 8 | #define HOP_DELAY_NOISE 0 9 | #define RING_BUFFER 0 10 | #define TRIGGERS_ENABLED 0 11 | #define INCASTS_ENABLED 0 12 | 13 | typedef struct Config 14 | { 15 | static const sim_time_t timeIncrementNs = 100; 16 | const float totalTimeMSecs = 0.5; 17 | 18 | // IMPORTANT: update numHosts and numSwitches as per the topology 19 | 20 | /* FatTree Topo Params */ 21 | static const ft_scale_t fatTreeTopoK = 24; // Fat Tree scale k 22 | const TopologyType topoType = TopologyType::FatTree; 23 | static const host_id_t numHosts = (fatTreeTopoK * fatTreeTopoK * fatTreeTopoK)/4; 24 | static const switch_id_t numSwitches = (fatTreeTopoK * fatTreeTopoK) + ((fatTreeTopoK * fatTreeTopoK)/4); 25 | const TrafficPatternType trafficPatternType = TrafficPatternType::FtUniform; 26 | const uint8_t ftMixedPatternPercentIntraRack = 75; 27 | static const uint numTriggersPerSwitchType = 15; 28 | const sim_time_t triggerInitialDelay = 75000; // 75us for k=24 fatTree topo 0.5ms run 29 | const uint8_t targetBaseNetworkLoadPercent = 40; /* 30 -> 25%, 40 -> 31%, 50 -> 36% */ 30 | const TrafficGenType trafficGenType = TrafficGenType::Continuous; 31 | const pkt_size_t fixedPktSizeForSimpleTrafficGen = 1500; 32 | const link_speed_gbps_t torLinkSpeedGbps = 100; 33 | const link_speed_gbps_t networkLinkSpeedGbps = 100; 34 | static const int numCoreSwitches = (fatTreeTopoK/2) * (fatTreeTopoK/2); 35 | 36 | /* Incast Related Params */ 37 | const uint8_t percentIncastTime = 10; 38 | const host_id_t incastFanInRatio = ((fatTreeTopoK * fatTreeTopoK) * 3)/4; 39 | const host_id_t percentTargetIncastHosts = 30; 40 | 41 | const load_t hostTrafficGenLoadPercent = 100; 42 | 43 | const sim_time_t switchHopDelayNs = 1000; 44 | const sim_time_t minSwitchHopDelayNs = 950; 45 | const sim_time_t maxSwitchHopDelayNs = 1050; 46 | 47 | // SyNDB specific config options 48 | static const uint32_t ringBufferSize = 10; // large size for simulation "oracle" 49 | static const pkt_size_t triggerPktSize = 60; 50 | 51 | const std::string packetSizeDistFile = "traffic-dist/fb_webserver_packetsizedist_cdf.csv"; 52 | const std::string flowArrivalDistFile = "traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"; 53 | } Config; 54 | 55 | extern Config syndbConfig; 56 | -------------------------------------------------------------------------------- /simulation/config_test.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils/types.hpp" 4 | 5 | #ifndef LOGGING 6 | #define LOGGING 1 7 | #endif 8 | #define HOP_DELAY_NOISE 1 9 | #define RING_BUFFER 0 10 | #define TRIGGERS_ENABLED 1 11 | #define INCASTS_ENABLED 1 12 | 13 | typedef struct Config 14 | { 15 | static const sim_time_t timeIncrementNs = 100; 16 | 17 | // IMPORTANT: update numHosts and numSwitches as per the topology 18 | 19 | /* SimpleTopo Params */ 20 | const float totalTimeMSecs = 1000; 21 | const TopologyType topoType = TopologyType::Simple; 22 | static const switch_id_t numSwitches = 3; 23 | static const uint numHosts = 4; 24 | const TrafficPatternType trafficPatternType = TrafficPatternType::SimpleTopo; 25 | const TrafficGenType trafficGenType = TrafficGenType::Distribution; 26 | const sim_time_t triggerInitialDelay = 1500000; // 1.5ms for Line topo 10G runs 27 | static const uint numTriggersPerSwitchType = 100; 28 | const link_speed_gbps_t torLinkSpeedGbps = 100; 29 | const link_speed_gbps_t networkLinkSpeedGbps = 100; 30 | 31 | /* Incast Related Params */ 32 | const uint8_t percentIncastTime = 10; 33 | const host_id_t incastFanInRatio = numHosts / 4; // 25% of the total hosts 34 | const host_id_t percentTargetIncastHosts = 30; 35 | 36 | // const load_t hostTrafficGenLoadPercent = 100; 37 | 38 | const sim_time_t switchHopDelayNs = 1000; 39 | const sim_time_t minSwitchHopDelayNs = 950; 40 | const sim_time_t maxSwitchHopDelayNs = 1050; 41 | 42 | // SyNDB specific config options 43 | static const uint32_t ringBufferSize = 10; // large size for simulation "oracle" 44 | static const pkt_size_t triggerPktSize = 60; 45 | 46 | const std::string packetSizeDistFile = "traffic-dist/fb_webserver_packetsizedist_cdf.csv"; 47 | const std::string flowArrivalDistFile = "traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"; 48 | 49 | 50 | 51 | /* Other params NOT used but needed for compilation */ 52 | // LineTopo 10ms Expt Params 53 | const pkt_size_t fixedPktSizeForSimpleTrafficGen = 101; //1500; 54 | // FatTree Topo 100ms Expt Params 55 | static const ft_scale_t fatTreeTopoK = 4; // Fat Tree scale k 56 | const uint8_t ftMixedPatternPercentIntraRack = 75; 57 | const uint8_t targetBaseNetworkLoadPercent = 40; /* 30 -> 25%, 40 -> 31%, 50 -> 36% */ 58 | static const int numCoreSwitches = (fatTreeTopoK/2) * (fatTreeTopoK/2); 59 | 60 | 61 | } Config; 62 | 63 | extern Config syndbConfig; 64 | 65 | -------------------------------------------------------------------------------- /simulation/config_validation.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils/types.hpp" 4 | 5 | #ifndef LOGGING 6 | #define LOGGING 1 7 | #endif 8 | #define HOP_DELAY_NOISE 1 9 | #define RING_BUFFER 0 10 | #define TRIGGERS_ENABLED 1 11 | #define INCASTS_ENABLED 0 12 | 13 | typedef struct Config 14 | { 15 | static const sim_time_t timeIncrementNs = 100; 16 | 17 | // IMPORTANT: update numHosts and numSwitches as per the topology 18 | 19 | /* LineTopo 10ms Expt Params */ 20 | const pkt_size_t fixedPktSizeForSimpleTrafficGen = 101; //1500; 21 | const float totalTimeMSecs = 10; 22 | const TopologyType topoType = TopologyType::Line; 23 | static const switch_id_t numSwitches = 5; 24 | static const uint numHosts = 2; 25 | const TrafficPatternType trafficPatternType = TrafficPatternType::SimpleTopo; 26 | const sim_time_t triggerInitialDelay = 1500000; // 1.5ms for Line topo 10ms run with 10k ring buffer 27 | static const uint numTriggersPerSwitchType = 100; 28 | const link_speed_gbps_t torLinkSpeedGbps = 10; 29 | const link_speed_gbps_t networkLinkSpeedGbps = 10; 30 | const TrafficGenType trafficGenType = TrafficGenType::Continuous; 31 | 32 | /* Incast Related Params */ 33 | const uint8_t percentIncastTime = 10; 34 | const host_id_t incastFanInRatio = numHosts / 4; // 25% of the total hosts 35 | const host_id_t percentTargetIncastHosts = 30; 36 | 37 | // const load_t hostTrafficGenLoadPercent = 100; 38 | 39 | const sim_time_t switchHopDelayNs = 500; 40 | const sim_time_t minSwitchHopDelayNs = 450; 41 | const sim_time_t maxSwitchHopDelayNs = 550; 42 | 43 | // SyNDB specific config options 44 | static const pkt_id_t ringBufferSize = 10000; // 10K 45 | static const pkt_size_t triggerPktSize = 60; 46 | 47 | const std::string packetSizeDistFile = "traffic-dist/fb_webserver_packetsizedist_cdf.csv"; 48 | const std::string flowArrivalDistFile = "traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"; 49 | 50 | /* Other params NOT used, but needed for compilation. */ 51 | // FatTree Topo 100ms Expt Params 52 | static const ft_scale_t fatTreeTopoK = 24; // Fat Tree scale k 53 | const uint8_t ftMixedPatternPercentIntraRack = 75; 54 | const uint8_t targetBaseNetworkLoadPercent = 40; /* 30 -> 25%, 40 -> 31%, 50 -> 36% */ 55 | static const int numCoreSwitches = (fatTreeTopoK/2) * (fatTreeTopoK/2); 56 | 57 | } Config; 58 | 59 | extern Config syndbConfig; 60 | 61 | -------------------------------------------------------------------------------- /simulation/event.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "simulation/event.hpp" 3 | #include "simulation/simulation.hpp" 4 | #include "utils/utils.hpp" 5 | #include "utils/logger.hpp" 6 | 7 | template 8 | PktEvent::PktEvent(){ 9 | // debug_print(fmt::format("New empty PktEvent constructed!")); 10 | } 11 | 12 | template<> 13 | PktEvent::~PktEvent(){ 14 | /* if(this->pkt != NULL) 15 | debug_print(fmt::format("Normal Pkt Event with packet id {} destructed!", this->pkt->id)); 16 | else 17 | debug_print(fmt::format("Normal Pkt Event (empty) destructed!")); */ 18 | } 19 | 20 | template<> 21 | PktEvent::~PktEvent(){ 22 | // debug_print(fmt::format("Trigger Pkt Event with trigger id {} destructed!", this->pkt->triggerId)); 23 | } 24 | 25 | 26 | HostPktEvent::HostPktEvent(Host* host, normalpkt_p &pkt){ 27 | this->host = host; 28 | this->pkt = pkt; 29 | } 30 | 31 | /* 32 | To avoid linking error for the template's methods, 33 | instantiating the template class with the two possible types 34 | */ 35 | 36 | template class PktEvent; 37 | template class PktEvent; 38 | -------------------------------------------------------------------------------- /simulation/event.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_H 2 | #define EVENT_H 3 | 4 | #include "traffic/packet.hpp" 5 | #include "topology/host.hpp" 6 | #include "topology/switch.hpp" 7 | 8 | template 9 | struct PktEvent 10 | { 11 | T pkt; // could be normalpkt_p or triggerpkt_p 12 | sim_time_t pktForwardTime; 13 | Switch* currSwitch; 14 | Switch* nextSwitch; // NULL if next hop is dstHost 15 | 16 | PktEvent(); 17 | ~PktEvent(); 18 | }; 19 | 20 | 21 | // Following is called an "alias template". 22 | // It is used for typedef equivalent of template structs/classes 23 | template 24 | using pktevent_p = std::shared_ptr>; 25 | 26 | struct HostPktEvent 27 | { 28 | Host* host; 29 | normalpkt_p pkt; 30 | 31 | HostPktEvent(Host* host, normalpkt_p &pkt); 32 | }; 33 | 34 | typedef std::shared_ptr hostpktevent_p; 35 | 36 | 37 | 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /simulation/simulation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "simulation/config.hpp" 5 | #include "simulation/simulation.hpp" 6 | #include "utils/logger.hpp" 7 | #include "utils/utils.hpp" 8 | #include "utils/pktdumper.hpp" 9 | #include "topology/fattree_topology.hpp" 10 | 11 | 12 | Simulation syndbSim; 13 | 14 | Simulation::Simulation(){ 15 | 16 | this->startTime = time(NULL); 17 | this->currTime = 0; 18 | this->timeIncrement = syndbConfig.timeIncrementNs; 19 | this->totalTime = (sim_time_t)(syndbConfig.totalTimeMSecs * (float)1000000); 20 | 21 | if(syndbConfig.topoType == TopologyType::Simple){ 22 | this->topo = std::shared_ptr(new SimpleTopology()); 23 | } 24 | else if (syndbConfig.topoType == TopologyType::FatTree){ 25 | this->topo = std::shared_ptr(new FattreeTopology(syndbConfig.fatTreeTopoK)); 26 | } 27 | else if (syndbConfig.topoType == TopologyType::Line){ 28 | this->topo = std::shared_ptr(new LineTopology()); 29 | } 30 | 31 | this->nextPktId = 0; 32 | this->nextTriggerPktId = 0; 33 | this->totalPktsDelivered = 0; 34 | 35 | #if LOGGING 36 | this->pktDumper = std::unique_ptr(new PktDumper()); 37 | #endif 38 | 39 | } 40 | 41 | 42 | pktevent_p Simulation::getNewNormalPktEvent(){ 43 | 44 | pktevent_p newNormalPktEvent; 45 | 46 | if(this->freeNormalPktEvents.size() > 0){ 47 | newNormalPktEvent = std::move(*this->freeNormalPktEvents.begin()); // retrieve 48 | this->freeNormalPktEvents.pop_front(); // remove 49 | } 50 | else{ 51 | newNormalPktEvent = std::make_shared>(); 52 | } 53 | 54 | return std::move(newNormalPktEvent); 55 | } 56 | 57 | normalpkt_p Simulation::getNewNormalPkt(pkt_id_t pktId, pkt_size_t pktSize){ 58 | normalpkt_p newNormalPkt; 59 | 60 | if(this->freeNormalPkts.size() > 0){ 61 | newNormalPkt = *this->freeNormalPkts.begin(); // retrieve 62 | this->freeNormalPkts.pop_front(); // remove 63 | 64 | newNormalPkt->id = pktId; 65 | newNormalPkt->size = pktSize; 66 | newNormalPkt->switchINTInfoList.clear(); 67 | } 68 | else{ 69 | newNormalPkt = new NormalPkt(pktId, pktSize); 70 | } 71 | 72 | return newNormalPkt; 73 | } 74 | 75 | void Simulation::initTriggerGen(){ 76 | switch(syndbConfig.topoType){ 77 | case TopologyType::Simple: 78 | this->triggerGen = std::shared_ptr(new TriggerGeneratorSimpleTopo()); 79 | break; 80 | case TopologyType::FatTree: 81 | this->triggerGen = std::shared_ptr(new TriggerGeneratorFatTreeTopo()); 82 | break; 83 | case TopologyType::Line: 84 | this->triggerGen = std::shared_ptr(new TriggerGeneratorLineTopo()); 85 | break; 86 | } 87 | } 88 | 89 | void Simulation::initIncastGen(){ 90 | this->incastGen = std::shared_ptr(new IncastGenerator()); 91 | } 92 | 93 | void Simulation::initHosts(){ 94 | 95 | for (auto it = this->topo->hostIDMap.begin(); it != this->topo->hostIDMap.end(); it++) 96 | { 97 | Host* h = it->second.get(); 98 | 99 | if(h->trafficGenDisabled) 100 | continue; 101 | 102 | if(syndbConfig.trafficPatternType == TrafficPatternType::FtMixed){ 103 | std::dynamic_pointer_cast(h->trafficPattern)->initTopoInfo(); 104 | } 105 | 106 | h->generateNextPkt(); 107 | 108 | } 109 | 110 | ndebug_print(fmt::format("Initialized {} hosts", this->topo->hostIDMap.size())); 111 | 112 | } 113 | 114 | void Simulation::generateHostPktEvents(){ 115 | 116 | // HostPktEventList MUST be empty 117 | assert((this->HostPktEventList.size() == 0) && "HostPktEventList is NOT empty!"); 118 | 119 | for(auto it = this->topo->hostIDMap.begin(); it != this->topo->hostIDMap.end(); it++){ 120 | Host* host = it->second.get(); 121 | 122 | // Just for debug case when trafficGen is disabled 123 | if (host->trafficGenDisabled) 124 | continue; 125 | 126 | while(host->nextPktTime <= syndbSim.currTime + syndbSim.timeIncrement){ 127 | // Use the next scheduled packet on the host to create hostPktEvent 128 | // hostpktevent_p hostPktEvent = hostpktevent_p(new HostPktEvent(host, host->nextPkt)); 129 | 130 | // Insert the hostPktEvent into the map (sorted list) 131 | this->HostPktEventList.insert(std::pair(host->nextPktTime, HostPktEvent(host, host->nextPkt))); 132 | 133 | // Generate next scheduled packet on the host 134 | host->generateNextPkt(); 135 | } 136 | 137 | } 138 | 139 | } 140 | 141 | void Simulation::processHostPktEvents(){ 142 | 143 | normalpkt_p nextPkt; 144 | sim_time_t nextPktTime; 145 | Host* host; 146 | 147 | auto it = this->HostPktEventList.begin(); 148 | 149 | while (it != this->HostPktEventList.end() ) 150 | { 151 | nextPktTime = it->first; 152 | host = it->second.host; 153 | nextPkt = it->second.pkt; 154 | 155 | if(this->currTime < nextPktTime){ 156 | std::string msg = fmt::format("Currtime: {}ns. HostPktEventList has pkt with nextPktTime {}ns", this->currTime, nextPktTime); 157 | throw std::logic_error(msg); 158 | } 159 | 160 | host->sendPkt(nextPkt, nextPktTime); 161 | 162 | it = this->HostPktEventList.erase(it); // erase and increment iterator 163 | 164 | } 165 | } 166 | 167 | 168 | 169 | void Simulation::processTriggerPktEvents(){ 170 | 171 | routeScheduleInfo rsinfo; 172 | 173 | // List of iterators that we would delete in the end 174 | std::list>::iterator> toDelete; 175 | 176 | toDelete.clear(); // Making sure that the list is empty 177 | 178 | auto it = this->TriggerPktEventList.begin(); 179 | 180 | while (it != this->TriggerPktEventList.end()) 181 | { 182 | pktevent_p event = *it; 183 | 184 | if(this->currTime >= event->pktForwardTime){ 185 | 186 | // Pass the pkt to the next switch to handle 187 | event->nextSwitch->receiveTriggerPkt(event->pkt, event->pktForwardTime); // can parallelize switch's processing? 188 | 189 | // Handling the case that the next hop is the pkt's dstSwitch 190 | if(event->nextSwitch->id == event->pkt->dstSwitchId){ 191 | // The pkt requires no more network event processing 192 | // Add the event's iterator to the toDelete list 193 | toDelete.push_front(it); 194 | } 195 | else // forward the event's packet 196 | { 197 | // Call routing on the next switch 198 | syndb_status_t status = event->nextSwitch->routeScheduleTriggerPkt(event->pkt, event->pktForwardTime, rsinfo); 199 | 200 | if(status != syndb_status_t::success){ 201 | std::string msg = fmt::format("Simulator failed to route trigger pkt of trigger event {}", event->pkt->triggerId); 202 | throw std::logic_error(msg); 203 | } 204 | 205 | // event->doForwarding(rinfo); 206 | 207 | event->currSwitch = event->nextSwitch; 208 | event->nextSwitch = rsinfo.nextSwitch; 209 | event->pktForwardTime = rsinfo.pktNextForwardTime; 210 | 211 | } 212 | } 213 | 214 | it++; // iterating over TriggerPktEventList 215 | } 216 | 217 | // Now delete the enlisted TriggerPktEvents 218 | 219 | // debug_print(fmt::format("Deleting {} TriggerPktEvents...", toDelete.size())); 220 | auto it2 = toDelete.begin(); 221 | 222 | while (it2 != toDelete.end()){ 223 | TriggerPktEventList.erase(*it2); 224 | 225 | it2++; 226 | } 227 | 228 | 229 | } 230 | 231 | 232 | void Simulation::processNormalPktEvents(){ 233 | 234 | routeScheduleInfo rsinfo; 235 | 236 | // List of iterators that we would delete in the end 237 | std::list>::iterator> toDelete; 238 | 239 | toDelete.clear(); // Making sure that the list is empty 240 | 241 | auto it = this->NormalPktEventList.begin(); 242 | 243 | while (it != this->NormalPktEventList.end()) 244 | { 245 | PktEvent* event = (*it).get(); 246 | 247 | if(this->currTime >= event->pktForwardTime){ 248 | 249 | 250 | // Handling the case that the next hop is the dst Host 251 | if(event->nextSwitch == NULL){ 252 | // Mark the event for deletion 253 | toDelete.push_back(it); 254 | 255 | // Add end time INT data to the packet 256 | event->pkt->endTime = event->pktForwardTime; 257 | 258 | // Dump the pkt with INT data to the disk 259 | #if LOGGING 260 | syndbSim.pktDumper->dumpPacket(event->pkt); 261 | #endif 262 | this->totalPktsDelivered += 1; 263 | 264 | #ifdef DEBUG 265 | /* debug_print_yellow("\nPkt ID {} dump:", event->pkt->id); 266 | debug_print("h{} --> h{}: {} ns (Start: {} ns | End: {} ns)", event->pkt->srcHost, event->pkt->dstHost, event->pkt->endTime - event->pkt->startTime, event->pkt->startTime, event->pkt->endTime); 267 | auto it1 = event->pkt->switchINTInfoList.begin(); 268 | for(it1; it1 != event->pkt->switchINTInfoList.end(); it1++){ 269 | debug_print("Rx on s{} at {} ns", it1->swId, it1->rxTime); 270 | } */ 271 | #endif 272 | } 273 | // Handling the case that the next hop is a switch (intermediate or dstTor) 274 | else{ 275 | 276 | // Pass the pkt to the next switch to handle 277 | event->nextSwitch->receiveNormalPkt(event->pkt, event->pktForwardTime); // thread-safe 278 | 279 | // Call routing on the next switch 280 | syndb_status_t status = event->nextSwitch->routeScheduleNormalPkt(event->pkt, event->pktForwardTime, rsinfo); 281 | 282 | 283 | /* Update the event */ 284 | event->currSwitch = event->nextSwitch; 285 | event->nextSwitch = rsinfo.nextSwitch; // will be NULL if next hop is a host 286 | event->pktForwardTime = rsinfo.pktNextForwardTime; 287 | 288 | } 289 | 290 | } // end of the if(this->currTime >= event->pktForwardTime) 291 | 292 | it++; // iterating over NormalPktEventList 293 | } 294 | 295 | // Now delete the enlisted NormalPktEvents 296 | 297 | // debug_print(fmt::format("Deleting {} NormalPktEvents...", toDelete.size())); 298 | auto it2 = toDelete.begin(); 299 | 300 | while (it2 != toDelete.end()){ 301 | this->freeNormalPkts.push_back((**it2)->pkt); // this makes pkt inside the event as NULL 302 | //TODO: other members of the PktEvent? 303 | this->freeNormalPktEvents.push_back(std::move(**it2)); 304 | NormalPktEventList.erase(*it2); 305 | it2++; 306 | } 307 | 308 | 309 | } 310 | 311 | 312 | void Simulation::flushRemainingNormalPkts(){ 313 | 314 | auto it = this->NormalPktEventList.begin(); 315 | 316 | for(it; it != this->NormalPktEventList.end(); it++){ 317 | pktevent_p event = *it; 318 | 319 | // Dump the pkt with INT data to the disk 320 | #if LOGGING 321 | syndbSim.pktDumper->dumpPacket(event->pkt); 322 | #endif 323 | 324 | 325 | #ifdef DEBUG 326 | /* debug_print_yellow("\nPkt ID {} dump:", event->pkt->id); 327 | debug_print("h{} --> h{}: N/A ns (Start: {} ns | End: {} ns)", event->pkt->srcHost, event->pkt->dstHost, event->pkt->startTime, event->pkt->endTime); 328 | auto it1 = event->pkt->switchINTInfoList.begin(); 329 | for(it1; it1 != event->pkt->switchINTInfoList.end(); it1++){ 330 | debug_print("Rx on s{} at {} ns", it1->swId, it1->rxTime); 331 | } */ 332 | #endif 333 | } 334 | 335 | } 336 | 337 | void Simulation::logTriggerInfoMap(){ 338 | sim_time_t triggerOriginTime, rxTime; 339 | trigger_id_t triggerId; 340 | switch_id_t originSwitch, rxSwitch; 341 | 342 | auto it1 = syndbSim.TriggerInfoMap.begin(); 343 | 344 | debug_print_yellow("\nTrigger pkt latencies between switches"); 345 | for(it1; it1 != syndbSim.TriggerInfoMap.end(); it1++){ 346 | 347 | triggerId = it1->first; 348 | originSwitch = it1->second.originSwitch; 349 | SwitchType switchType = syndbSim.topo->getSwitchTypeById(originSwitch); 350 | 351 | #if LOGGING 352 | syndbSim.pktDumper->dumpTriggerInfo(triggerId, it1->second, switchType); 353 | #else 354 | /* Below code is only for debugging. TODO: comment out later. */ 355 | 356 | /* 357 | triggerOriginTime = it1->second.triggerOrigTime; 358 | 359 | ndebug_print_yellow("Trigger ID {} (origin switch: {} {})", triggerId, originSwitch, switchTypeToString(switchType)); 360 | auto it2 = it1->second.rxSwitchTimes.begin(); 361 | 362 | for(it2; it2 != it1->second.rxSwitchTimes.end(); it2++){ 363 | rxSwitch = it2->first; 364 | rxTime = it2->second; 365 | 366 | ndebug_print("{} --> {}: {}ns", originSwitch, rxSwitch, rxTime - triggerOriginTime); 367 | } // end of iterating over rxSwitchTimes 368 | */ 369 | #endif 370 | 371 | 372 | } // end of iterating over TriggerPktLatencyMap 373 | } 374 | 375 | void Simulation::showLinkUtilizations(){ 376 | 377 | double util_to_tor, util_to_host; 378 | double util1, util2; 379 | double percent_util1, percent_util2; 380 | double percent_util_to_tor, percent_util_to_host; 381 | double torLinksPercentUtilSum = 0; 382 | double networkLinksPercentUtilSum = 0; 383 | link_id_t numTorLinks = 0; 384 | link_id_t numNetworkLinks = 0; 385 | 386 | // For dumping individual link utilization 387 | std::string torLinkUtilsFileName = ""; 388 | std::string networkLinkUtilsFileName = ""; 389 | #if LOGGING 390 | torLinkUtilsFileName = fmt::format("./data/{}torLinksUtil.txt", this->pktDumper->prefixStringForFileName); 391 | networkLinkUtilsFileName = fmt::format("./data/{}networkLinksUtil.txt", this->pktDumper->prefixStringForFileName); 392 | #else 393 | torLinkUtilsFileName = "./data/torLinksUtil.txt"; 394 | networkLinkUtilsFileName = "./data/networkLinksUtil.txt"; 395 | #endif 396 | 397 | std::ofstream torLinkUtilsFile(torLinkUtilsFileName); 398 | std::ofstream networkLinkUtilsFile(networkLinkUtilsFileName); 399 | 400 | debug_print_yellow("Utilization on ToR links:"); 401 | for(auto it = syndbSim.topo->torLinkVector.begin(); it != syndbSim.topo->torLinkVector.end(); it++){ 402 | 403 | util_to_tor = (double)((*it)->byte_count_to_tor * 8) / syndbSim.totalTime; 404 | util_to_host = (double)((*it)->byte_count_to_host * 8) / syndbSim.totalTime; 405 | 406 | percent_util_to_tor = (util_to_tor / syndbConfig.torLinkSpeedGbps) * 100.0; 407 | percent_util_to_host = (util_to_host / syndbConfig.torLinkSpeedGbps) * 100.0; 408 | 409 | debug_print("Link ID {}: towards host: {} | towards tor: {}", (*it)->id, percent_util_to_host, percent_util_to_tor); 410 | 411 | torLinksPercentUtilSum += percent_util_to_tor; 412 | torLinksPercentUtilSum += percent_util_to_host; 413 | numTorLinks += 2; 414 | 415 | // Dumping individual link utilization 416 | torLinkUtilsFile << percent_util_to_tor << std::endl; 417 | torLinkUtilsFile << percent_util_to_host << std::endl; 418 | } 419 | 420 | debug_print_yellow("Utilization on Network links:"); 421 | for(auto it = syndbSim.topo->networkLinkVector.begin(); it != syndbSim.topo->networkLinkVector.end(); it++){ 422 | 423 | auto map = (*it)->byte_count; 424 | auto it_byte_count = map.begin(); 425 | 426 | switch_id_t sw1 = it_byte_count->first; 427 | byte_count_t byteCount1 = it_byte_count->second; 428 | it_byte_count++; 429 | switch_id_t sw2 = it_byte_count->first; 430 | byte_count_t byteCount2 = it_byte_count->second; 431 | 432 | util1 = (double)(byteCount1 * 8) / syndbSim.totalTime; 433 | util2 = (double)(byteCount2 * 8) / syndbSim.totalTime; 434 | 435 | percent_util1 = (util1 / syndbConfig.networkLinkSpeedGbps) * 100.0; 436 | percent_util2 = (util2 / syndbConfig.networkLinkSpeedGbps) * 100.0; 437 | 438 | debug_print("Link ID {}: towards sw{}: {} | towards sw{}: {}", (*it)->id, sw1, percent_util1, sw2, percent_util2); 439 | 440 | networkLinksPercentUtilSum += percent_util1; 441 | networkLinksPercentUtilSum += percent_util2; 442 | numNetworkLinks += 2; 443 | 444 | // Dumping individual link utilization 445 | networkLinkUtilsFile << percent_util1 << std::endl; 446 | networkLinkUtilsFile << percent_util2 << std::endl; 447 | } 448 | 449 | // Closing individual link utilization files 450 | torLinkUtilsFile.close(); 451 | networkLinkUtilsFile.close(); 452 | 453 | ndebug_print_yellow("##### Network load summary #####"); 454 | ndebug_print("ToR Links: {}", torLinksPercentUtilSum / numTorLinks); 455 | ndebug_print("Network Links: {}", networkLinksPercentUtilSum / numNetworkLinks); 456 | 457 | } 458 | 459 | void Simulation::printSimulationStats(){ 460 | syndbSim.showLinkUtilizations(); 461 | ndebug_print_yellow("##### Total Pkts Summary #####"); 462 | ndebug_print("Generated: {} | Delivered: {}", this->nextPktId, this->totalPktsDelivered); 463 | } 464 | 465 | 466 | void Simulation::printSimulationSetup(){ 467 | 468 | ndebug_print_yellow("######## Simulation Setup ########"); 469 | ndebug_print("TrafficPattern type is {}", trafficPatternTypeToString(syndbConfig.trafficPatternType)); 470 | if(syndbConfig.trafficPatternType == TrafficPatternType::FtMixed){ 471 | ndebug_print("IntraRack: {}% | InterRack: {}%", syndbConfig.ftMixedPatternPercentIntraRack, 100 - syndbConfig.ftMixedPatternPercentIntraRack); 472 | } 473 | ndebug_print("TrafficDistribution type is {}", trafficGenTypeToString(syndbConfig.trafficGenType)); 474 | ndebug_print("Trigger initial delay is {}ns", syndbConfig.triggerInitialDelay); 475 | #if LOGGING 476 | ndebug_print("Logging is enabled!"); 477 | #else 478 | ndebug_print("Logging is disabled!"); 479 | #endif 480 | 481 | #if HOP_DELAY_NOISE 482 | ndebug_print("HopDelayNoise is enabled!"); 483 | #else 484 | ndebug_print("HopDelayNoise is disabled!"); 485 | #endif 486 | 487 | #if TRIGGERS_ENABLED 488 | ndebug_print("Triggers are enabled!"); 489 | #else 490 | ndebug_print("Triggers are disabled!"); 491 | #endif 492 | 493 | #if INCASTS_ENABLED 494 | ndebug_print("Incasts are enabled!"); 495 | #else 496 | ndebug_print("Incasts are disabled!"); 497 | #endif 498 | 499 | ndebug_print("Time increment is {}ns", syndbSim.timeIncrement); 500 | ndebug_print("Running simulation for {}ns ...\n",syndbSim.totalTime); 501 | } 502 | 503 | void Simulation::cleanUp(){ 504 | 505 | ndebug_print_yellow("Flushing remaining normal pkts"); 506 | this->flushRemainingNormalPkts(); 507 | ndebug_print_yellow("Flushing trigger pkts info"); 508 | this->logTriggerInfoMap(); 509 | 510 | /* Free NormalPkts from everywhere */ 511 | // 1. From the Hosts. Implemented in the destructor ~Host(). Should be freed there. 512 | // 2. From the HostPktEventList. Do NOT free in the destructor of HostPktEvent. It is destroyed in runtime. 513 | for(auto it=this->HostPktEventList.begin(); it != this->HostPktEventList.end(); it++){ 514 | if(it->second.pkt != NULL) 515 | delete it->second.pkt; 516 | } 517 | // 3. From the NormalPktEvents only. NOT the freeNormalPktEvents! 518 | for(auto it=this->NormalPktEventList.begin(); it != this->NormalPktEventList.end(); it++){ 519 | if((*it)->pkt != NULL) 520 | delete (*it)->pkt; 521 | } 522 | // 4. From the freeNormalPkts list. These are pkts from the freeNormalPktEvents 523 | ndebug_print_yellow("Cleaning up freeNormalPkts ..."); 524 | for(auto it=this->freeNormalPkts.begin(); it != this->freeNormalPkts.end(); it++){ 525 | if(*it != NULL) 526 | delete *it; 527 | } 528 | 529 | this->printSimulationStats(); 530 | 531 | this->endTime = time(NULL); 532 | ndebug_print_yellow("\nSimulation run took {} seconds.", this->endTime - this->startTime); 533 | 534 | } 535 | -------------------------------------------------------------------------------- /simulation/simulation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIMULATION_H 2 | #define SIMULATION_H 3 | 4 | #include 5 | #include 6 | #include "topology/topology.hpp" 7 | #include "simulation/event.hpp" 8 | #include "utils/pktdumper.hpp" 9 | #include "traffic/triggerGenerator.hpp" 10 | #include "traffic/incastGenerator.hpp" 11 | 12 | typedef struct Simulation 13 | { 14 | std::shared_ptr topo; 15 | 16 | // time-related. All units are nanoseconds 17 | sim_time_t currTime; 18 | sim_time_t timeIncrement; 19 | sim_time_t totalTime; 20 | 21 | // packets-related 22 | pkt_id_t nextPktId; 23 | pkt_id_t nextTriggerPktId; 24 | pkt_id_t totalPktsDelivered; 25 | 26 | std::multimap HostPktEventList; 27 | std::list> NormalPktEventList; 28 | std::list> freeNormalPktEvents; // to reuse shared_ptrs 29 | std::list> TriggerPktEventList; 30 | std::list freeNormalPkts; 31 | 32 | // For tracking and logging triggerInfo 33 | std::map TriggerInfoMap; 34 | 35 | 36 | std::shared_ptr triggerGen; 37 | std::shared_ptr incastGen; 38 | 39 | std::unique_ptr pktDumper; 40 | 41 | time_t startTime, endTime; 42 | 43 | Simulation(); // default constructor 44 | 45 | // needs to be thread-safe when parallelizing 46 | inline pkt_id_t getNextPktId() { return this->nextPktId++; }; 47 | inline pkt_id_t getNextTriggerPktId() { return this->nextTriggerPktId++; }; 48 | inline void buildTopo(){ this->topo->buildTopo(); }; 49 | pktevent_p getNewNormalPktEvent(); 50 | normalpkt_p getNewNormalPkt(pkt_id_t pktId, pkt_size_t pktSize); 51 | void initTriggerGen(); 52 | void initIncastGen(); 53 | void initHosts(); 54 | void generateHostPktEvents(); 55 | void processHostPktEvents(); 56 | void processTriggerPktEvents(); 57 | void processNormalPktEvents(); 58 | void flushRemainingNormalPkts(); 59 | void logTriggerInfoMap(); 60 | void showLinkUtilizations(); 61 | 62 | void printSimulationSetup(); 63 | void printSimulationStats(); 64 | void cleanUp(); 65 | 66 | } Simulation; 67 | 68 | extern Simulation syndbSim; 69 | 70 | 71 | #endif -------------------------------------------------------------------------------- /syndb-sim.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "utils/logger.hpp" 6 | #include "simulation/config.hpp" 7 | #include "simulation/simulation.hpp" 8 | #include "devtests/devtests.hpp" 9 | 10 | void signalHandler(int signum){ 11 | ndebug_print_yellow("\nCaught signal {}", signum); 12 | 13 | syndbSim.cleanUp(); 14 | 15 | exit(signum); 16 | } 17 | 18 | int main(){ 19 | 20 | signal(SIGINT, signalHandler); 21 | signal(SIGTERM, signalHandler); 22 | 23 | syndbSim = Simulation(); 24 | 25 | // Init Step 0: Open files for logging 26 | #if LOGGING 27 | syndbSim.pktDumper->openFiles(syndbConfig.numSwitches, syndbConfig.numHosts); 28 | #endif 29 | syndbSim.printSimulationSetup(); 30 | 31 | // Init Step 1: Build the topology 32 | syndbSim.buildTopo(); 33 | 34 | // Init Step 2: Init the triggerGen schedule 35 | #if TRIGGERS_ENABLED 36 | syndbSim.initTriggerGen(); 37 | syndbSim.triggerGen->printTriggerSchedule(); 38 | #endif 39 | #if INCASTS_ENABLED 40 | syndbSim.initIncastGen(); 41 | syndbSim.incastGen->printIncastSchedule(); 42 | #endif 43 | 44 | // Init Step 3: Initialize the hosts 45 | syndbSim.initHosts(); 46 | 47 | 48 | // Main simulation loop: at time = 0; all event lists are empty. Only step 4 does some work. 49 | for ( ; syndbSim.currTime <= syndbSim.totalTime; syndbSim.currTime += syndbSim.timeIncrement) 50 | { 51 | debug_print_yellow("######## Simulation Time: {} ########", syndbSim.currTime); 52 | if(syndbSim.currTime % 100000 == 0) 53 | ndebug_print_yellow("######## Simulation Time: {} ########", syndbSim.currTime); 54 | 55 | // Step 1: Process all hostPktEvents 56 | syndbSim.processHostPktEvents(); 57 | 58 | // Step 2: Generate (as per schedule) and process triggerPktEvents 59 | #if TRIGGERS_ENABLED 60 | syndbSim.triggerGen->generateTrigger(); 61 | syndbSim.processTriggerPktEvents(); 62 | #endif 63 | 64 | // Step 3: Process all normalPktEvents 65 | syndbSim.processNormalPktEvents(); 66 | 67 | // Step 4: Generate (rather modify) (as per schedule) incast pkts on certain hosts 68 | #if INCASTS_ENABLED 69 | syndbSim.incastGen->generateIncast(); // these pkts would be picked-up first in step 5 70 | #endif 71 | 72 | // Step 5: Generate hostPktEvents for the next timeIncrement slot 73 | syndbSim.generateHostPktEvents(); 74 | 75 | } // end of main simulation loop 76 | 77 | syndbSim.cleanUp(); 78 | 79 | 80 | #ifdef DEBUG 81 | checkRemainingQueuingAtLinks(); 82 | // testNormalPktLatencies(0, 1); 83 | // testRingBufferOps(); 84 | // showSimpleTopoRingBuffers(); 85 | // showFatTreeTopoRoutingTables(); 86 | #endif 87 | 88 | 89 | return 0; 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /topology/fattree_topology.cpp: -------------------------------------------------------------------------------- 1 | #include "topology/fattree_topology.hpp" 2 | #include "utils/logger.hpp" 3 | 4 | void Pod::buildPod(){ 5 | 6 | 7 | // Construct the racks 8 | auto tor_it = this->torSwitches.begin(); 9 | for(tor_it; tor_it != this->torSwitches.end(); tor_it++){ 10 | 11 | // create the ToR switch 12 | *tor_it = parentTopo.createNewSwitch(SwitchType::FtTor); 13 | 14 | // Update podId for the ToR switch 15 | std::dynamic_pointer_cast(*tor_it)->podId = this->id; 16 | 17 | // create and add k/2 hosts to the ToR switch 18 | for(int i=0; i < (syndbConfig.fatTreeTopoK / 2); i++){ 19 | host_p h = parentTopo.createNewHost(); 20 | parentTopo.addHostToTor(h, *tor_it); 21 | } 22 | 23 | } // end of tor_it loop 24 | 25 | // Initialize the Aggr switches 26 | // racklocal_host_id_t localHostId = 0; 27 | auto aggr_it = this->aggrSwitches.begin(); 28 | for(aggr_it; aggr_it != this->aggrSwitches.end(); aggr_it++){ 29 | *aggr_it = parentTopo.createNewSwitch(SwitchType::FtAggr); 30 | std::dynamic_pointer_cast(*aggr_it)->podId = this->id; 31 | 32 | // connect the Aggr switch to the ToR switches 33 | auto tor_it = this->torSwitches.begin(); 34 | for(tor_it; tor_it != this->torSwitches.end(); tor_it++){ 35 | // Adds links, updates neighborSwitch tables on both the switches 36 | parentTopo.connectSwitchToSwitch(*tor_it, *aggr_it); 37 | } 38 | } 39 | 40 | 41 | // Populate routing tables for the ToR switches 42 | ft_scale_t ftscaleK = syndbConfig.fatTreeTopoK; 43 | uint aggrSwitchIdx; 44 | 45 | for(int z=0; z < this->torSwitches.size(); z++){ // loops over ToR switches 46 | std::shared_ptr tor = std::dynamic_pointer_cast(this->torSwitches[z]); 47 | 48 | // Fills routing table of tor for all possible racklocal host IDs 49 | for(int rlocalHostId=0; rlocalHostId < ftscaleK/2; rlocalHostId++){ 50 | aggrSwitchIdx = (rlocalHostId + z) % (ftscaleK/2); 51 | tor->routingTable[rlocalHostId] = this->aggrSwitches[aggrSwitchIdx]->id; 52 | } 53 | } 54 | 55 | } 56 | 57 | void FattreeTopology::buildTopo(){ 58 | 59 | // Instantiate and build the pods 60 | for(int i=0; i < this->k; i++){ 61 | this->pods[i] = pod_p(new Pod(this->getNextPodId(),*this)); 62 | this->pods[i]->buildPod(); 63 | } 64 | 65 | // Create all Core switches 66 | for(int i=0; i < this->numCoreSwitches; i++){ 67 | this->coreSwitches[i] = this->createNewSwitch(SwitchType::FtCore); 68 | } 69 | 70 | // Connect Core switches to the pods. Update routing on only the Core switches 71 | /* 72 | For each core switch, compute the stride number it belongs to. 73 | Then for each pod, index the aggrSwitch array with the stride number 74 | to get the connected aggr switch. 75 | */ 76 | for(uint coreSwitchIdx=0; coreSwitchIdx < this->numCoreSwitches; coreSwitchIdx++){ 77 | // compute the stride for the core switch 78 | uint stride = coreSwitchIdx / (this->k/2); 79 | uint strideLocalCoreSwitchIdx = coreSwitchIdx % (this->k/2); 80 | switch_p coreSwitch = this->coreSwitches[coreSwitchIdx]; 81 | 82 | for(pod_id_t podIdx=0; podIdx < this->k; podIdx++){ 83 | switch_p aggrSwitch = this->pods[podIdx]->aggrSwitches[stride]; 84 | 85 | // Add links, update neighborSwitch tables on both the switches 86 | this->connectSwitchToSwitch(coreSwitch, aggrSwitch); 87 | // Update routing table on the Core Switch 88 | std::dynamic_pointer_cast(coreSwitch)->routingTable[podIdx] = aggrSwitch->id; 89 | 90 | // Add the core switch to AggrSwitch's coreSwitchesList 91 | std::dynamic_pointer_cast(aggrSwitch)->coreSwitchesList.push_back(coreSwitch->id); 92 | 93 | } 94 | 95 | } // end of for loop on all core switches 96 | 97 | 98 | // Update routing on all Aggr switches (across all pods) 99 | ft_scale_t ftscaleK = syndbConfig.fatTreeTopoK; 100 | uint coreSwitchIdx; 101 | for(int i=0; i < this->pods.size(); i++){ // loops over all pods 102 | pod_p pod = this->pods[i]; 103 | 104 | for(int z=0; z < pod->aggrSwitches.size(); z++){ // loops over aggr switches in the pod 105 | std::shared_ptr aggrSwitch = std::dynamic_pointer_cast(pod->aggrSwitches[z]); 106 | 107 | // Fill entries in the routing table of the aggrSwitch 108 | for(int rlocalHostId=0; rlocalHostId < ftscaleK/2; rlocalHostId++){ 109 | coreSwitchIdx = (rlocalHostId + z) % (ftscaleK/2); 110 | aggrSwitch->routingTable[rlocalHostId] = aggrSwitch->coreSwitchesList[coreSwitchIdx]; 111 | } // end of routing table entries 112 | } // end of aggrSwitches in the pod 113 | } // end of loop over all pods 114 | 115 | ndebug_print_yellow("Built FatTree Topo (k={})", this->k); 116 | ndebug_print("Total Hosts: {}", this->hostIDMap.size()); 117 | ndebug_print("Total Switches: {} (Core: {}, Agg: {}, ToR: {})", this->switchIDMap.size(), this->coreSwitches.size(), this->pods.size() * this->pods[0]->aggrSwitches.size(), this->pods.size() * this->pods[0]->torSwitches.size()); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /topology/fattree_topology.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FATTREE_TOPOLOGY_H 2 | #define FATTREE_TOPOLOGY_H 3 | 4 | #include 5 | #include "simulation/config.hpp" 6 | #include "topology/topology.hpp" 7 | 8 | struct Pod; 9 | typedef std::shared_ptr pod_p; 10 | 11 | struct FattreeTopology : Topology 12 | { 13 | ft_scale_t k; 14 | uint numCoreSwitches; 15 | pod_id_t nextPodId = 0; 16 | std::array pods; 17 | std::array coreSwitches; 18 | 19 | // Override the virtual function of the abstract Topology class 20 | void buildTopo(); 21 | inline FattreeTopology(ft_scale_t k):Topology(){ 22 | this->k = k; 23 | this->numCoreSwitches = syndbConfig.numCoreSwitches; 24 | } 25 | inline pod_id_t getNextPodId(){ return this->nextPodId++;} 26 | }; 27 | 28 | struct Pod 29 | { 30 | pod_id_t id; 31 | FattreeTopology &parentTopo; 32 | 33 | std::array aggrSwitches; 34 | std::array torSwitches; 35 | 36 | Pod(pod_id_t id, FattreeTopology &parent) : parentTopo(parent){ 37 | this->id = id; 38 | }; 39 | 40 | void buildPod(); 41 | 42 | private: 43 | void connectToRtoAggr(switch_p tor, switch_p aggr); 44 | }; 45 | 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /topology/host.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "topology/host.hpp" 5 | #include "simulation/config.hpp" 6 | #include "simulation/simulation.hpp" 7 | #include "utils/utils.hpp" 8 | #include "utils/logger.hpp" 9 | 10 | Host::Host(host_id_t id, bool disableTrafficGen){ 11 | this->torLink = NULL; 12 | this->torSwitch = NULL; 13 | this->nextPkt = NULL; 14 | this->nextPktTime = 0; 15 | this->prevPktTime = 0; 16 | 17 | this->id = id; 18 | this->trafficGenDisabled = disableTrafficGen; 19 | 20 | if(syndbConfig.trafficGenType == TrafficGenType::Continuous){ 21 | this->trafficGen = std::shared_ptr(new SimpleTrafficGenerator()); 22 | } 23 | else if (syndbConfig.trafficGenType == TrafficGenType::Distribution) 24 | { 25 | this->trafficGen = std::shared_ptr(new DcTrafficGenerator()); 26 | this->trafficGen->loadTrafficDistribution(syndbConfig.packetSizeDistFile, syndbConfig.flowArrivalDistFile); 27 | } 28 | 29 | switch(syndbConfig.trafficPatternType){ 30 | case TrafficPatternType::SimpleTopo: 31 | this->trafficPattern = std::shared_ptr(new SimpleTopoTrafficPattern(this->id)); 32 | break; 33 | case TrafficPatternType::AlltoAll: 34 | this->trafficPattern = std::shared_ptr(new AlltoAllTrafficPattern(this->id)); 35 | break; 36 | case TrafficPatternType::FtUniform: 37 | this->trafficPattern = std::shared_ptr(new FtUniformTrafficPattern(this->id)); 38 | break; 39 | case TrafficPatternType::FtMixed: 40 | this->trafficPattern = std::shared_ptr(new FtMixedTrafficPattern(this->id)); 41 | break; 42 | default: 43 | std::string msg = fmt::format("Host constructor failed. No way to initialize the specified traffic pattern: {}", syndbConfig.trafficPatternType); 44 | throw std::logic_error(msg); 45 | break; 46 | } 47 | } 48 | 49 | void Host::generateNextPkt(){ 50 | 51 | // Get the pktsize + delay from the trafficGen 52 | this->trafficGen->getNextPacket(this->nextPktInfo); 53 | 54 | // Construct a pkt 55 | this->nextPkt = syndbSim.getNewNormalPkt(syndbSim.getNextPktId(), this->nextPktInfo.size); 56 | this->nextPkt->srcHost = this->id; 57 | this->nextPkt->size = this->nextPktInfo.size; 58 | // Get the dstHost from the TrafficPattern 59 | this->nextPkt->dstHost = this->trafficPattern->applyTrafficPattern(); 60 | this->prevPktTime = this->nextPktTime; // save curr next time to prev 61 | 62 | sim_time_t pktGenSendTime = this->nextPktTime + this->nextPktInfo.sendDelay; 63 | sim_time_t nextPktSerializeStart = std::max(pktGenSendTime, this->torLink->next_idle_time_to_tor); 64 | // this->nextPktTime is the last pkt serialize end time 65 | this->nextPktTime = nextPktSerializeStart + getSerializationDelay(this->nextPkt->size, syndbConfig.torLinkSpeedGbps);; 66 | this->torLink->next_idle_time_to_tor = this->nextPktTime; 67 | 68 | // Update the byte count 69 | this->torLink->byte_count_to_tor += this->nextPkt->size + 24; // +24 to account for on-wire PHY bits 70 | 71 | // Add appropriate INT data to the packet 72 | this->nextPkt->startTime = nextPktSerializeStart; 73 | 74 | 75 | } 76 | 77 | void Host::sendPkt(normalpkt_p &nextPkt, sim_time_t nextPktTime){ 78 | 79 | routeScheduleInfo rsinfo; 80 | 81 | if(this->trafficGenDisabled) 82 | return; 83 | else if (nextPkt->dstHost == this->id){ // loopback pkt 84 | return; 85 | } 86 | 87 | // For quick testing of AlltoAll traffic pattern 88 | // ndebug_print("sendPkt(): {} --> {}", this->id, nextPkt->dstHost); 89 | 90 | // Step 1: Pass the pkt to ToR for its own processing 91 | this->torSwitch->receiveNormalPkt(nextPkt, nextPktTime); // can parallelize switch's processing? 92 | 93 | // Step 2: Call the routing + scheduling on the ToR switch to get rsinfo 94 | syndb_status_t s = this->torSwitch->routeScheduleNormalPkt(nextPkt, nextPktTime, rsinfo); 95 | 96 | if(s != syndb_status_t::success){ 97 | std::string msg = fmt::format("Host {} failed to send Pkt to host {} since routing on the ToR failed!", this->id, nextPkt->dstHost); 98 | throw std::logic_error(msg); 99 | } 100 | 101 | // Create, fill and add a new normal pkt event 102 | // pktevent_p newPktEvent = pktevent_p(new PktEvent()); 103 | pktevent_p newPktEvent = syndbSim.getNewNormalPktEvent(); 104 | newPktEvent->pkt = nextPkt; 105 | newPktEvent->pktForwardTime = rsinfo.pktNextForwardTime; 106 | newPktEvent->currSwitch = this->torSwitch; 107 | newPktEvent->nextSwitch = rsinfo.nextSwitch; 108 | 109 | syndbSim.NormalPktEventList.push_front(newPktEvent); 110 | 111 | } 112 | 113 | Host::~Host(){ 114 | if(this->nextPkt != NULL) 115 | delete this->nextPkt; 116 | } 117 | -------------------------------------------------------------------------------- /topology/host.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HOST_H 2 | #define HOST_H 3 | 4 | #include 5 | #include "utils/types.hpp" 6 | #include "topology/link.hpp" 7 | #include "topology/switch.hpp" 8 | #include "traffic/trafficGenerator.hpp" 9 | #include "traffic/trafficPattern.hpp" 10 | 11 | /* Host struct */ 12 | typedef struct Host 13 | { 14 | host_id_t id; 15 | host_tor_link_p torLink; 16 | Switch* torSwitch; 17 | 18 | packetInfo nextPktInfo; 19 | normalpkt_p nextPkt; 20 | sim_time_t nextPktTime; 21 | sim_time_t prevPktTime; 22 | 23 | std::shared_ptr trafficGen; 24 | std::shared_ptr trafficPattern; 25 | bool trafficGenDisabled; 26 | 27 | Host(host_id_t id, bool disableTrafficGen = false); 28 | ~Host(); 29 | 30 | void generateNextPkt(); 31 | void sendPkt(normalpkt_p &nextPkt, sim_time_t nextPktTime); 32 | 33 | } Host; 34 | 35 | typedef std::shared_ptr host_p; 36 | 37 | 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /topology/link.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | Link::Link(link_id_t id, link_speed_gbps_t speed) { 5 | this->id = id; 6 | this->speed = speed; 7 | } 8 | 9 | 10 | NetworkLink::NetworkLink(link_id_t id, link_speed_gbps_t speed, switch_id_t sw1, switch_id_t sw2) : Link::Link(id, speed){ 11 | 12 | this->next_idle_time[sw1] = 0; 13 | this->next_idle_time[sw2] = 0; 14 | this->next_idle_time_priority[sw1] = 0; 15 | this->next_idle_time_priority[sw2] = 0; 16 | this->byte_count[sw1] = 0; 17 | this->byte_count[sw2] = 0; 18 | } 19 | 20 | 21 | HostTorLink::HostTorLink(link_id_t id, link_speed_gbps_t speed) : Link::Link(id, speed){ 22 | this->next_idle_time_to_tor = 0; 23 | this->next_idle_time_to_host = 0; 24 | this->byte_count_to_tor = 0; 25 | this->byte_count_to_host = 0; 26 | } 27 | -------------------------------------------------------------------------------- /topology/link.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LINK_H 2 | #define LINK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "utils/types.hpp" 8 | 9 | /* Link struct */ 10 | typedef struct Link 11 | { 12 | link_id_t id; 13 | link_speed_gbps_t speed; 14 | 15 | Link() = default; 16 | Link(link_id_t id, link_speed_gbps_t speed); 17 | } Link; 18 | 19 | /* NetworkLink struct */ 20 | typedef struct NetworkLink : Link 21 | { 22 | std::unordered_map next_idle_time; 23 | std::unordered_map next_idle_time_priority; 24 | std::unordered_map byte_count; 25 | 26 | NetworkLink(link_id_t id, link_speed_gbps_t speed, switch_id_t sw1, switch_id_t sw2); 27 | 28 | } NetworkLink; 29 | 30 | typedef struct HostTorLink : Link 31 | { 32 | sim_time_t next_idle_time_to_tor; 33 | sim_time_t next_idle_time_to_host; 34 | byte_count_t byte_count_to_tor; 35 | byte_count_t byte_count_to_host; 36 | 37 | HostTorLink(link_id_t id, link_speed_gbps_t speed); 38 | } HostTorLink; 39 | 40 | /* Shared pointer to a Link struct object */ 41 | typedef std::shared_ptr network_link_p; 42 | typedef std::shared_ptr host_tor_link_p; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /topology/switch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "topology/switch.hpp" 6 | #include "utils/logger.hpp" 7 | #include "utils/utils.hpp" 8 | #include "simulation/simulation.hpp" 9 | #include "simulation/config.hpp" 10 | #include "utils/types.hpp" 11 | 12 | 13 | Switch::Switch(switch_id_t id){ 14 | this->id = id; 15 | this->hop_delay = syndbConfig.switchHopDelayNs; 16 | 17 | #if HOP_DELAY_NOISE 18 | this->hop_delay_variation = syndbConfig.maxSwitchHopDelayNs - syndbConfig.minSwitchHopDelayNs; 19 | uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 20 | this->randHopDelay = std::default_random_engine(seed); 21 | #endif 22 | } 23 | 24 | sim_time_t Switch::getRandomHopDelay(){ 25 | uint_fast32_t randval = this->randHopDelay() % this->hop_delay_variation; 26 | 27 | return syndbConfig.minSwitchHopDelayNs + randval; 28 | } 29 | 30 | 31 | syndb_status_t Switch::intraRackRouteNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo){ 32 | 33 | // intra-rack routing 34 | // Figure-out the link + queue and call schedulePkt() --> updates the q_next_idle_time 35 | // nextSwitch is NULL (since host) 36 | // Update the rsinfo struct 37 | 38 | HostTorLink* hostTorLink; 39 | 40 | auto search = this->neighborHostTable.find(pkt->dstHost); 41 | if(search != this->neighborHostTable.end()){ 42 | 43 | hostTorLink = search->second; 44 | this->schedulePkt(pkt->size, pktArrivalTime, hostTorLink->speed, hostTorLink->next_idle_time_to_host, hostTorLink->byte_count_to_host); 45 | 46 | rsinfo.nextSwitch = NULL; // next hop is a host 47 | rsinfo.pktNextForwardTime = hostTorLink->next_idle_time_to_host; 48 | 49 | return syndb_status_t::success; 50 | } 51 | else 52 | { // this should never happen 53 | std::string msg = fmt::format("ToR switch {} doesn't have entry for neighbor host {} in neighborHostTable", this->id, pkt->dstHost); 54 | throw std::logic_error(msg); 55 | } 56 | 57 | } 58 | 59 | syndb_status_t Switch::scheduleToNextHopSwitch(const pkt_size_t pktsize, const sim_time_t pktArrivalTime, Switch* nextHopSwitch, routeScheduleInfo &rsinfo, PacketType ptype){ 60 | 61 | NetworkLink* nextLink; 62 | 63 | auto search = this->neighborSwitchTable.find(nextHopSwitch->id); 64 | if(search != this->neighborSwitchTable.end()){ 65 | nextLink = search->second; 66 | 67 | // Choose different queues on the nextLink based on the packet type 68 | if(ptype == PacketType::NormalPkt){ 69 | // Schedule on the normal queue 70 | schedulePkt(pktsize, pktArrivalTime, nextLink->speed, nextLink->next_idle_time[nextHopSwitch->id], nextLink->byte_count[nextHopSwitch->id]); 71 | rsinfo.pktNextForwardTime = nextLink->next_idle_time[nextHopSwitch->id]; 72 | } 73 | else if (ptype == PacketType::TriggerPkt){ 74 | // Schedule on the priority queue 75 | schedulePkt(pktsize, pktArrivalTime, nextLink->speed, nextLink->next_idle_time_priority[nextHopSwitch->id], nextLink->byte_count[nextHopSwitch->id]); 76 | rsinfo.pktNextForwardTime = nextLink->next_idle_time_priority[nextHopSwitch->id]; 77 | } 78 | 79 | rsinfo.nextSwitch = nextHopSwitch; 80 | 81 | 82 | return syndb_status_t::success; 83 | } 84 | else 85 | { // this should never happen 86 | std::string msg = fmt::format("Switch {} has no link to next hop switch {}", this->id, nextHopSwitch->id); 87 | throw std::logic_error(msg); 88 | } 89 | 90 | } 91 | 92 | 93 | void Switch::schedulePkt(const pkt_size_t pktsize, const sim_time_t pktArrivalTime, const link_speed_gbps_t linkSpeed, sim_time_t &qNextIdleTime, byte_count_t &byteCount){ 94 | 95 | sim_time_t pktSendTime, timeAfterSwitchHop, pktNextSerializeStartTime, hopDelay; 96 | 97 | #if HOP_DELAY_NOISE 98 | hopDelay = this->getRandomHopDelay(); 99 | #else 100 | hopDelay = this->hop_delay; 101 | #endif 102 | 103 | // *earliest* time when we can start serialization on the link 104 | timeAfterSwitchHop = pktArrivalTime + hopDelay; 105 | 106 | // *actual* time when we can start serialization assuming FIFO queuing on the next link 107 | pktNextSerializeStartTime = std::max(timeAfterSwitchHop, qNextIdleTime); 108 | 109 | // Time when serialization would end and pkt can be forwarded to next hop 110 | pktSendTime = pktNextSerializeStartTime + getSerializationDelay(pktsize, linkSpeed); 111 | 112 | // Schedule the packet on the link 113 | qNextIdleTime = pktSendTime; 114 | 115 | // Update the byte_count 116 | byteCount += pktsize + 24; // +24 for on-wire PHY bits 117 | 118 | } 119 | 120 | 121 | void Switch::receiveNormalPkt(normalpkt_p pkt, sim_time_t rxTime){ 122 | #if RING_BUFFER 123 | this->ringBuffer.insertPrecord(pkt->id, rxTime); 124 | #endif 125 | 126 | // *this->swPktArrivalFile << rxTime << std::endl; 127 | 128 | // Prepare and insert switch INT into the packet 129 | switchINTInfo newInfo; 130 | newInfo.swId = this->id; 131 | newInfo.rxTime = rxTime; 132 | 133 | pkt->switchINTInfoList.push_back(newInfo); 134 | 135 | } 136 | 137 | 138 | void Switch::receiveTriggerPkt(triggerpkt_p pkt, sim_time_t rxTime){ 139 | 140 | switch_id_t dstSwitchId; 141 | 142 | if(pkt->dstSwitchId != this->id){ 143 | std::string msg = "Multi-hop trigger pkt received. This should NEVER happen!"; 144 | throw std::logic_error(msg); 145 | } 146 | 147 | // debug_print_yellow("\n[Switch {}] Received trigger pkt {} from switch {} at time {}", this->id, pkt->triggerId, pkt->srcSwitchId, rxTime); 148 | 149 | /* This has to be the destination. All trigger pkts are single-hop */ 150 | 151 | // Check if this trigger pkt has been received in the past 152 | bool triggerSeenBefore = this->triggerHistory.find(pkt->triggerId) != this->triggerHistory.end(); 153 | 154 | if(triggerSeenBefore){ // already broadcast forwarded before 155 | // debug_print("Trigger ID seen before. Ignoring now.."); 156 | return; // do nothing 157 | } 158 | 159 | /* Trigger ID is being seen for the first time */ 160 | 161 | // Add triggerId to the history 162 | this->triggerHistory.insert(pkt->triggerId); 163 | 164 | // Logging the triggerInfo 165 | syndbSim.TriggerInfoMap[pkt->triggerId].rxSwitchTimes[this->id] = rxTime; 166 | 167 | // Flush the current RingBuffer 168 | #if RING_BUFFER 169 | this->snapshotRingBuffer(rxTime); 170 | #endif 171 | 172 | // Broadcast forward to neighbors with source pruning 173 | switch_id_t srcSwitch = pkt->srcSwitchId; 174 | 175 | auto it2 = this->neighborSwitchTable.begin(); 176 | for(it2; it2 != this->neighborSwitchTable.end(); it2++){ 177 | 178 | if(it2->first == srcSwitch) 179 | continue; // source pruning 180 | 181 | dstSwitchId = it2->first; 182 | // debug_print("Fowarding to neighbor switch {}", dstSwitchId); 183 | this->createSendTriggerPkt(dstSwitchId, pkt->triggerId, pkt->triggerOriginSwId, pkt->triggerTime, rxTime); 184 | 185 | } 186 | 187 | } 188 | 189 | void Switch::generateTrigger(){ 190 | trigger_id_t newTriggerId; 191 | syndb_status_t status; 192 | switch_id_t dstSwitchId; 193 | routeScheduleInfo rsinfo; 194 | 195 | newTriggerId = syndbSim.getNextTriggerPktId(); 196 | 197 | this->triggerHistory.insert(newTriggerId); // this switch has already seen this triggerPkt 198 | 199 | // debug_print_yellow("Generating Trigger {} on switch {} at time {}:", newTriggerId, this->id, syndbSim.currTime); 200 | 201 | // Create and add TriggerInfo to TriggerInfoMap 202 | triggerInfo newTriggerInfo; 203 | newTriggerInfo.originSwitch = this->id; 204 | newTriggerInfo.triggerOrigTime = syndbSim.currTime; 205 | syndbSim.TriggerInfoMap[newTriggerId] = newTriggerInfo; 206 | 207 | // Iterate over the neighbors and schedule a triggerPkt for each neighbor 208 | auto it = this->neighborSwitchTable.begin(); 209 | 210 | for(it; it != this->neighborSwitchTable.end(); it++){ 211 | 212 | dstSwitchId = it->first; 213 | 214 | this->createSendTriggerPkt(dstSwitchId, newTriggerId, this->id, syndbSim.currTime, syndbSim.currTime); // when generating, the pktArrivalTime is syndbSim.currTime 215 | } 216 | 217 | } 218 | 219 | void Switch::createSendTriggerPkt(switch_id_t dstSwitchId, trigger_id_t triggerId, switch_id_t originSwitchId, sim_time_t origTriggerTime, sim_time_t pktArrivalTime){ 220 | 221 | syndb_status_t status; 222 | routeScheduleInfo rsinfo; 223 | 224 | triggerpkt_p newTriggerPkt = triggerpkt_p(new TriggerPkt(triggerId, syndbConfig.triggerPktSize)); 225 | newTriggerPkt->srcSwitchId = this->id; 226 | newTriggerPkt->dstSwitchId = dstSwitchId; // neighbor switch ID 227 | newTriggerPkt->triggerOriginSwId = originSwitchId; 228 | newTriggerPkt->triggerTime = origTriggerTime; 229 | 230 | status = this->routeScheduleTriggerPkt(newTriggerPkt, pktArrivalTime, rsinfo); 231 | if(status == syndb_status_t::success){ 232 | // debug_print("Routed and scheduled Trigger Pkt {} from switch {} --> {}", newTriggerPkt->triggerId, this->id, dstSwitchId); 233 | } 234 | else 235 | { 236 | std::string msg = "Failed to routeScheduleTriggerPkt"; 237 | throw std::logic_error(msg); 238 | } 239 | 240 | 241 | // Create, fill and add a new trigger pkt event 242 | pktevent_p newEvent = pktevent_p(new PktEvent); 243 | 244 | newEvent->pkt = newTriggerPkt; 245 | newEvent->pktForwardTime = rsinfo.pktNextForwardTime; 246 | newEvent->currSwitch = syndbSim.topo->getSwitchById(this->id); 247 | newEvent->nextSwitch = rsinfo.nextSwitch; 248 | 249 | syndbSim.TriggerPktEventList.push_back(newEvent); 250 | } 251 | 252 | syndb_status_t Switch::routeScheduleTriggerPkt(triggerpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo) { 253 | Switch* nextHopSwitch; 254 | 255 | nextHopSwitch = syndbSim.topo->getSwitchById(pkt->dstSwitchId); // since triggerPkts sent to neighbors only 256 | 257 | return this->scheduleToNextHopSwitch(pkt->size, pktArrivalTime, nextHopSwitch, rsinfo, PacketType::TriggerPkt); 258 | } 259 | 260 | 261 | void Switch::snapshotRingBuffer(sim_time_t triggerPktRcvTime){ 262 | #if RING_BUFFER 263 | ndebug_print("### Ring Buffer for Switch {} ###", this->id); 264 | ndebug_print("Time: {}ns", triggerPktRcvTime); 265 | this->ringBuffer.printRingBuffer(); 266 | #endif 267 | } 268 | 269 | /****************************************/ 270 | /* SimpleSwitch Methods */ 271 | /****************************************/ 272 | 273 | syndb_status_t SimpleSwitch::routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo){ 274 | // Two steps for updating the rsinfo struct 275 | // Step 1: Do the routing: determines nextSwitch, nextLink, nextLink's queue (correct next_idle_time) 276 | // Step 2: (common) Do the scheduling: determines the pktNextForwardTime for the correct nextLink's queue 277 | 278 | switch_id_t dstTorId; 279 | 280 | dstTorId = syndbSim.topo->getTorId(pkt->dstHost); 281 | 282 | if(dstTorId == this->id){ // intra-rack routing 283 | return this->intraRackRouteNormalPkt(pkt, pktArrivalTime, rsinfo); 284 | } // end of intra-rack routing case 285 | else // inter-rack routing 286 | { 287 | Switch* nextHopSwitch; 288 | nextHopSwitch = this->getNextHop(dstTorId); 289 | 290 | // call the switch-to-switch scheduling since we know the nextHopSwitch 291 | return this->scheduleToNextHopSwitch(pkt->size, pktArrivalTime, nextHopSwitch, rsinfo, PacketType::NormalPkt); 292 | 293 | } // end of inter-rack routing 294 | 295 | } 296 | 297 | Switch* SimpleSwitch::getNextHop(switch_id_t dstSwitchId){ 298 | 299 | // First, find if the dstSwitchId is in the neighbor switch list 300 | 301 | auto it = this->neighborSwitchTable.find(dstSwitchId); 302 | 303 | if(it != this->neighborSwitchTable.end()){ // dst switch is a neighbor 304 | // So it itself is the nextHop 305 | // simply return the shared_pointer to the dstSwitchId 306 | return syndbSim.topo->getSwitchById(dstSwitchId); 307 | } 308 | 309 | // Not a neighbor. Now refer to the routing table. 310 | 311 | switch_id_t nextHopSwitchId; 312 | auto it1 = this->routingTable.find(dstSwitchId); 313 | 314 | if (it1 != routingTable.end()){ // Next hop found 315 | 316 | nextHopSwitchId = it1->second; 317 | 318 | // Simply return the pointer to the nextHopSwitch 319 | return syndbSim.topo->getSwitchById(nextHopSwitchId); 320 | 321 | } 322 | else // Err No known route to dst ToR 323 | { // ideally this should never happen 324 | std::string msg = fmt::format("Switch {} couldn't find any route to dst switch {}", this->id, dstSwitchId); 325 | throw std::logic_error(msg); 326 | } 327 | } 328 | 329 | Switch::~Switch(){ 330 | // this->swPktArrivalFile->close(); 331 | } 332 | -------------------------------------------------------------------------------- /topology/switch.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SWITCH_H 2 | #define SWITCH_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "utils/types.hpp" 11 | #include "topology/link.hpp" 12 | #include "topology/syndb_ringbuffer.hpp" 13 | #include "traffic/packet.hpp" 14 | 15 | 16 | typedef std::unordered_map neighbor_switch_table_t; 17 | typedef std::unordered_map neighbor_host_table_t; 18 | 19 | enum class SwitchType {Simple, FtTor, FtAggr, FtCore}; 20 | 21 | inline std::string switchTypeToString(SwitchType type){ 22 | switch(type){ 23 | case SwitchType::Simple: 24 | return "Simple"; 25 | break; 26 | case SwitchType::FtTor: 27 | return "Tor"; 28 | break; 29 | case SwitchType::FtAggr: 30 | return "Aggr"; 31 | break; 32 | case SwitchType::FtCore: 33 | return "Core"; 34 | break; 35 | default: 36 | std::string msg = fmt::format("Unknown SwitchType {}", type); 37 | throw std::logic_error(msg); 38 | } 39 | } 40 | 41 | struct routeScheduleInfo; 42 | 43 | struct Switch; 44 | typedef std::shared_ptr switch_p; 45 | 46 | 47 | /* Switch struct */ 48 | struct Switch 49 | { 50 | switch_id_t id; 51 | SwitchType type; 52 | sim_time_t hop_delay; 53 | sim_time_t hop_delay_variation; 54 | neighbor_switch_table_t neighborSwitchTable; 55 | neighbor_host_table_t neighborHostTable; 56 | std::default_random_engine randHopDelay; 57 | 58 | /* SyNDB specific members */ 59 | #if RING_BUFFER 60 | RingBuffer ringBuffer; 61 | #endif 62 | // std::unique_ptr swPktArrivalFile; 63 | std::set triggerHistory; 64 | 65 | /* Switch's processing on receiving a pkt: logging, SyNDB, etc. */ 66 | void receiveNormalPkt(normalpkt_p pkt, sim_time_t rxTime); 67 | void receiveTriggerPkt(triggerpkt_p pkt, sim_time_t rxTime); 68 | void generateTrigger(); 69 | void createSendTriggerPkt(switch_id_t dstSwitchId, trigger_id_t triggerId, switch_id_t originSwitchId, sim_time_t origTriggerTime, sim_time_t pktArrivalTime); 70 | void snapshotRingBuffer(sim_time_t triggerPktRcvTime); 71 | 72 | /* Fills rinfo. Returns Success or Failure */ 73 | syndb_status_t routeScheduleTriggerPkt(triggerpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 74 | virtual syndb_status_t routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo) = 0; // <--- pure virtual. Impl by derived classes 75 | 76 | syndb_status_t intraRackRouteNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 77 | /* Inter-switch scheduling */ 78 | syndb_status_t scheduleToNextHopSwitch(const pkt_size_t pktsize, const sim_time_t pktArrivalTime, Switch* nextHopSwitch, routeScheduleInfo &rsinfo, PacketType ptype); 79 | void schedulePkt(const pkt_size_t pktsize, const sim_time_t pktArrivalTime, const link_speed_gbps_t linkSpeed, sim_time_t &qNextIdleTime, byte_count_t &byte_count); 80 | 81 | sim_time_t getRandomHopDelay(); 82 | 83 | Switch() = default; 84 | Switch(switch_id_t id); 85 | ~Switch(); 86 | 87 | }; 88 | 89 | struct SimpleSwitch : Switch{ 90 | 91 | std::unordered_map routingTable; 92 | 93 | /* Overriding the virtual functions of the base class */ 94 | syndb_status_t routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 95 | 96 | 97 | Switch* getNextHop(switch_id_t dstSwitchId); 98 | 99 | SimpleSwitch(switch_id_t id):Switch(id) {}; 100 | 101 | }; 102 | 103 | struct routeScheduleInfo 104 | { 105 | Switch* nextSwitch; 106 | sim_time_t pktNextForwardTime; 107 | }; 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /topology/switch_ft.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "simulation/simulation.hpp" 3 | #include "topology/switch_ft.hpp" 4 | 5 | 6 | Switch* SwitchFtTorAggr::getNextHop(host_id_t dstHostId){ 7 | switch_id_t nextHopSwitchId; 8 | racklocal_host_id_t rackLocalHostId; 9 | Switch* nextHopSwitch; 10 | 11 | rackLocalHostId = dstHostId % (this->fatTreeScaleK / 2); 12 | 13 | auto it = this->routingTable.find(rackLocalHostId); 14 | 15 | if(it == this->routingTable.end()){ // this should NOT happen 16 | std::string msg = fmt::format("rackLocalHostId {} not found in Tor/Aggr switch {} routing table", rackLocalHostId, this->id); 17 | 18 | throw std::logic_error(msg); 19 | } 20 | 21 | nextHopSwitchId = it->second; 22 | nextHopSwitch = syndbSim.topo->getSwitchById(nextHopSwitchId); 23 | 24 | return nextHopSwitch; 25 | } 26 | 27 | syndb_status_t SwitchFtTor::routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo){ 28 | 29 | switch_id_t dstTorId; 30 | 31 | dstTorId = syndbSim.topo->getTorId(pkt->dstHost); 32 | 33 | if(dstTorId == this->id){ // intra-rack routing 34 | return this->intraRackRouteNormalPkt(pkt, pktArrivalTime, rsinfo); 35 | } // end of intra-rack routing case 36 | else // inter-rack routing 37 | { 38 | Switch* nextHopSwitch; 39 | nextHopSwitch = this->getNextHop(pkt->dstHost); 40 | 41 | // call the switch-to-switch scheduling since we know the nextHopSwitch 42 | return this->scheduleToNextHopSwitch(pkt->size, pktArrivalTime, nextHopSwitch, rsinfo, PacketType::NormalPkt); 43 | 44 | } 45 | } 46 | 47 | 48 | syndb_status_t SwitchFtAggr::routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo){ 49 | switch_id_t dstTorId; 50 | Switch* nextHopSwitch; 51 | dstTorId = syndbSim.topo->getTorId(pkt->dstHost); 52 | 53 | // find if dstTor is in the neighbors (if intra-pod routing) 54 | auto it = this->neighborSwitchTable.find(dstTorId); 55 | if(it != this->neighborSwitchTable.end()){ // intra-pod routing 56 | nextHopSwitch = syndbSim.topo->getSwitchById(dstTorId); 57 | } 58 | else // inter-pod routing. Send to the uplink core 59 | { 60 | // Get the uplink core switch from the routing table 61 | nextHopSwitch = this->getNextHop(pkt->dstHost); 62 | } 63 | 64 | // call the switch-to-switch scheduling since we know the nextHopSwitch 65 | return this->scheduleToNextHopSwitch(pkt->size, pktArrivalTime, nextHopSwitch, rsinfo, PacketType::NormalPkt); 66 | 67 | } 68 | 69 | 70 | Switch* SwitchFtCore::getNextHop(host_id_t dstHostId){ 71 | Switch* nextHopSwitch; 72 | pod_id_t podId; 73 | ft_scale_t kBy2 = this->fatTreeScaleK / 2; 74 | 75 | podId = dstHostId / (kBy2 * kBy2); 76 | 77 | auto it = this->routingTable.find(podId); 78 | 79 | if(it == this->routingTable.end()){ 80 | std::string msg = fmt::format("No route to pod {} on core switch {}", podId, this->id); 81 | throw std::logic_error(msg); 82 | } 83 | 84 | // it->second is the aggr switch id 85 | nextHopSwitch = syndbSim.topo->getSwitchById(it->second); 86 | 87 | return nextHopSwitch; 88 | 89 | } 90 | 91 | syndb_status_t SwitchFtCore::routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo){ 92 | 93 | Switch* nextHopSwitch; 94 | nextHopSwitch = this->getNextHop(pkt->dstHost); 95 | 96 | // call the switch-to-switch scheduling since we know the nextHopSwitch 97 | return this->scheduleToNextHopSwitch(pkt->size, pktArrivalTime, nextHopSwitch, rsinfo, PacketType::NormalPkt); 98 | 99 | } 100 | -------------------------------------------------------------------------------- /topology/switch_ft.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FTSWITCHES_H 2 | #define FTSWITCHES_H 3 | 4 | #include "topology/switch.hpp" 5 | 6 | 7 | /* Abstract class for common implementations between ToR/Aggr switches */ 8 | struct SwitchFtTorAggr : Switch 9 | { 10 | ft_scale_t fatTreeScaleK; 11 | pod_id_t podId; 12 | // For ToR: 13 | // For Aggr: 14 | std::unordered_map routingTable; 15 | 16 | /* Functions specific to ToR/Aggr switch's routing */ 17 | Switch* getNextHop(host_id_t dstHostId); 18 | 19 | inline SwitchFtTorAggr(switch_id_t id) : Switch(id){ 20 | this->fatTreeScaleK = syndbConfig.fatTreeTopoK; 21 | }; 22 | }; 23 | 24 | 25 | struct SwitchFtTor : SwitchFtTorAggr 26 | { 27 | // resuse constructor of the base class 28 | using SwitchFtTorAggr::SwitchFtTorAggr; 29 | 30 | /* Overriding the virtual function of the base class */ 31 | syndb_status_t routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 32 | 33 | }; 34 | 35 | struct SwitchFtAggr : SwitchFtTorAggr 36 | { 37 | std::vector coreSwitchesList; 38 | // resuse constructor of the base class 39 | using SwitchFtTorAggr::SwitchFtTorAggr; 40 | 41 | /* Overriding the virtual function of the base class */ 42 | syndb_status_t routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 43 | 44 | }; 45 | 46 | 47 | struct SwitchFtCore : Switch 48 | { 49 | ft_scale_t fatTreeScaleK; 50 | // 51 | std::unordered_map routingTable; 52 | 53 | /* Overriding the virtual function of the base class */ 54 | syndb_status_t routeScheduleNormalPkt(normalpkt_p &pkt, const sim_time_t pktArrivalTime, routeScheduleInfo &rsinfo); 55 | 56 | Switch* getNextHop(host_id_t dstHostId); 57 | 58 | inline SwitchFtCore(switch_id_t id) : Switch(id) { 59 | this->fatTreeScaleK = syndbConfig.fatTreeTopoK; 60 | }; 61 | }; 62 | 63 | 64 | 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /topology/syndb_ringbuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "topology/syndb_ringbuffer.hpp" 2 | #include "utils/logger.hpp" 3 | 4 | RingBuffer::RingBuffer(){ 5 | this->end = -1; // ring buffer is empty 6 | this->next = 0; // points to the start after wrap around 7 | this->wrapAround = false; 8 | } 9 | 10 | void RingBuffer::insertPrecord(pkt_id_t pktId, sim_time_t arrivalTime){ 11 | 12 | pRecordArray[next].pktId = pktId; 13 | pRecordArray[next].arrivalTime = arrivalTime; 14 | 15 | // Common pointers management 16 | this->end = this->next; 17 | this->next = (this->next + 1) % this->pRecordArray.size(); 18 | 19 | if(this->next == 0 && this->wrapAround == false){ // next becomes zero after incr 20 | this->wrapAround = true; 21 | } 22 | } 23 | 24 | pRecord RingBuffer::getPrecord(ringbuffer_index_t idx){ 25 | return this->pRecordArray.at(idx); 26 | } 27 | 28 | ringbuffer_index_t RingBuffer::getStart(){ 29 | if(this->isEmpty()) 30 | return -1; 31 | else if (this->wrapAround == false) 32 | return 0; 33 | else 34 | return this->next; 35 | } 36 | 37 | ringbuffer_index_t RingBuffer::getEnd(){ 38 | return this->end; 39 | } 40 | 41 | bool RingBuffer::isEmpty(){ 42 | return this->end == -1; 43 | } 44 | 45 | actualRingBufferInfo RingBuffer::getActualRingBufferInfo(uint32_t actualSize){ 46 | actualRingBufferInfo info; 47 | ringbuffer_index_t start, end; 48 | ringbuffer_index_t elementsTillEnd, remainingElements; 49 | end = this->getEnd(); 50 | 51 | elementsTillEnd = end + 1; // since array is zero indexed 52 | 53 | if(elementsTillEnd < actualSize){ // either wrapped around OR not enough elements even for actualSize 54 | 55 | if(this->wrapAround == true){ 56 | remainingElements = actualSize - elementsTillEnd; 57 | start = this->pRecordArray.size() - remainingElements; 58 | } 59 | else // NOT wrapped around and elements in ringBuffer < actualSize 60 | { 61 | start = 0; 62 | } 63 | 64 | } 65 | else // elementsTillEnd >= actualSize 66 | { 67 | start = (end + 1) - actualSize; 68 | } 69 | 70 | info.start = start; 71 | info.end = end; 72 | 73 | return info; 74 | 75 | } 76 | 77 | ringbuffer_index_t RingBuffer::getNextIndex(ringbuffer_index_t idx){ 78 | return (idx + 1) % this->pRecordArray.size(); 79 | } 80 | 81 | void RingBuffer::printRingBufferRange(ringbuffer_index_t start, ringbuffer_index_t end){ 82 | pRecord precord; 83 | ringbuffer_index_t idx = start; 84 | ringbuffer_index_t terminating_idx = this->getNextIndex(end); // the idx after end 85 | do 86 | { 87 | precord = this->getPrecord(idx); 88 | ndebug_print("{} {}", precord.pktId, precord.arrivalTime); 89 | idx = this->getNextIndex(idx); 90 | } while (idx != terminating_idx); 91 | } 92 | 93 | void RingBuffer::printRingBuffer(){ 94 | ringbuffer_index_t start, end; 95 | start = this->getStart(); 96 | end = this->getEnd(); 97 | 98 | this->printRingBufferRange(start, end); 99 | 100 | } 101 | 102 | 103 | void RingBuffer::printActualRingBuffer(uint32_t actualSize){ 104 | 105 | actualRingBufferInfo info = this->getActualRingBufferInfo(actualSize); 106 | 107 | this->printRingBufferRange(info.start, info.end); 108 | 109 | } 110 | -------------------------------------------------------------------------------- /topology/syndb_ringbuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SWITCH_SYNDB_H 2 | #define SWITCH_SYNDB_H 3 | 4 | #include 5 | #include "utils/types.hpp" 6 | #include "simulation/config.hpp" 7 | 8 | 9 | struct pRecord 10 | { 11 | pkt_id_t pktId; 12 | sim_time_t arrivalTime; 13 | }; 14 | 15 | struct actualRingBufferInfo 16 | { 17 | ringbuffer_index_t start; 18 | ringbuffer_index_t end; 19 | }; 20 | 21 | 22 | struct RingBuffer 23 | { 24 | private: 25 | 26 | std::array pRecordArray; 27 | ringbuffer_index_t next, end; 28 | bool wrapAround; 29 | 30 | public: 31 | RingBuffer(); 32 | void insertPrecord(pkt_id_t pktId, sim_time_t arrivalTime); 33 | pRecord getPrecord(ringbuffer_index_t idx); 34 | ringbuffer_index_t getStart(); 35 | ringbuffer_index_t getEnd(); 36 | actualRingBufferInfo getActualRingBufferInfo(uint32_t actualSize); 37 | bool isEmpty(); 38 | 39 | void printRingBufferRange(ringbuffer_index_t start, ringbuffer_index_t end); 40 | void printRingBuffer(); 41 | void printActualRingBuffer(uint32_t actualSize); 42 | ringbuffer_index_t getNextIndex(ringbuffer_index_t idx); 43 | }; 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /topology/topology.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "simulation/config.hpp" 4 | #include "simulation/simulation.hpp" 5 | #include "topology/topology.hpp" 6 | #include "utils/logger.hpp" 7 | 8 | 9 | Topology::Topology(){ 10 | this->switchTypeIDMap[SwitchType::Simple] = std::set(); 11 | this->switchTypeIDMap[SwitchType::FtTor] = std::set(); 12 | this->switchTypeIDMap[SwitchType::FtAggr] = std::set(); 13 | this->switchTypeIDMap[SwitchType::FtCore] = std::set(); 14 | } 15 | 16 | SwitchType Topology::getSwitchTypeById(switch_id_t id){ 17 | auto typeit = this->switchTypeIDMap.begin(); 18 | for(typeit; typeit != this->switchTypeIDMap.end(); typeit++){ 19 | if(typeit->second.find(id) != typeit->second.end()) // Found the switch ID 20 | return typeit->first; 21 | } 22 | 23 | std::string msg = fmt::format("Switch id {} has no assigned type. This should NEVER happen!",id); 24 | throw std::logic_error(msg); 25 | } 26 | 27 | Switch* Topology::getSwitchById(switch_id_t id){ 28 | auto it = this->switchIDMap.find(id); 29 | if(it != this->switchIDMap.end()){ // found the switch_p 30 | return it->second.get(); 31 | } 32 | else 33 | { 34 | std::string msg = fmt::format("No switch_p found for switch_id {}. This should NEVER happen!", id); 35 | throw std::logic_error(msg); 36 | } 37 | } 38 | 39 | Host* Topology::getHostById(host_id_t hostId){ 40 | auto it = this->hostIDMap.find(hostId); 41 | if(it != this->hostIDMap.end()){ // found the switch_p 42 | return it->second.get(); 43 | } 44 | else 45 | { 46 | std::string msg = fmt::format("No host_p found for host_id {}. This should NEVER happen!", hostId); 47 | throw std::logic_error(msg); 48 | } 49 | } 50 | 51 | switch_id_t Topology::getTorId(host_id_t hostId){ 52 | 53 | auto it = hostTorMap.find(hostId); 54 | 55 | if(it == hostTorMap.end()){ 56 | std::string msg = fmt::format("No ToR found for host {} in the topology!", hostId); 57 | throw std::logic_error(msg); 58 | } 59 | // We have found the ToR, if we reach here 60 | return it->second; 61 | } 62 | 63 | host_tor_link_p Topology::createNewToRLink(){ 64 | 65 | // host_tor_link_p newLink = host_tor_link_p(new HostTorLink(this->getNextLinkId(), syndbConfig.torLinkSpeedGbps)); 66 | host_tor_link_p newLink = std::make_shared(this->getNextLinkId(), syndbConfig.torLinkSpeedGbps); 67 | this->torLinkVector.push_back(newLink); 68 | 69 | return newLink; 70 | } 71 | 72 | network_link_p Topology::createNewNetworLink(switch_id_t sw1, switch_id_t sw2){ 73 | 74 | // network_link_p newLink = network_link_p(new NetworkLink(this->getNextLinkId(), syndbConfig.networkLinkSpeedGbps, sw1, sw2)); 75 | network_link_p newLink = std::make_shared(this->getNextLinkId(), syndbConfig.networkLinkSpeedGbps, sw1, sw2); 76 | this->networkLinkVector.push_back(newLink); 77 | 78 | return newLink; 79 | } 80 | 81 | switch_p Topology::createNewSwitch(SwitchType type){ 82 | switch_p newSwitch; 83 | 84 | switch (type) 85 | { 86 | case SwitchType::FtTor: 87 | newSwitch = std::make_shared(this->getNextSwitchId()); 88 | break; 89 | case SwitchType::FtAggr: 90 | newSwitch = std::make_shared(this->getNextSwitchId()); 91 | break; 92 | case SwitchType::FtCore: 93 | newSwitch = std::make_shared(this->getNextSwitchId()); 94 | break; 95 | case SwitchType::Simple: 96 | default: 97 | newSwitch = std::make_shared(this->getNextSwitchId()); 98 | break; 99 | } 100 | 101 | newSwitch->type = type; 102 | 103 | // newSwitch->swPktArrivalFile = std::unique_ptr(new std::ofstream(fmt::format("./pktarrival/{}_sw{}.txt", switchTypeToString(type), newSwitch->id), std::ofstream::out)); 104 | 105 | this->switchIDMap[newSwitch->id] = newSwitch; 106 | this->switchTypeIDMap[type].insert(newSwitch->id); 107 | 108 | return newSwitch; 109 | } 110 | 111 | host_p Topology::createNewHost(bool trafficGenDisabled){ 112 | 113 | // host_p newHost = host_p(new Host(this->getNextHostId(), trafficGenDisabled)); 114 | host_p newHost = std::make_shared(this->getNextHostId(), trafficGenDisabled); 115 | 116 | this->hostIDMap[newHost->id] = newHost; 117 | 118 | return newHost; 119 | } 120 | 121 | 122 | void Topology::addHostToTor(host_p &host, switch_p &tor){ 123 | 124 | host_tor_link_p newLink = createNewToRLink(); 125 | 126 | // Update things on Host 127 | host->torLink = newLink; 128 | host->torSwitch = tor.get(); 129 | 130 | // Update things on Switch 131 | tor->neighborHostTable[host->id] = newLink.get(); 132 | 133 | // Update things on Topology 134 | this->hostTorMap[host->id] = tor->id; 135 | 136 | // debug_print("Connected h{} to sw{}", host->id, tor->id); 137 | 138 | } 139 | 140 | void Topology::connectSwitchToSwitch(switch_p &s1, switch_p &s2){ 141 | 142 | network_link_p newLink = createNewNetworLink(s1->id, s2->id); 143 | 144 | // Update things on s1 145 | s1->neighborSwitchTable[s2->id] = newLink.get(); 146 | 147 | // Update things on s2 148 | s2->neighborSwitchTable[s1->id] = newLink.get(); 149 | 150 | // debug_print("Connected sw{} to sw{}", s1->id, s2->id); 151 | 152 | } 153 | 154 | 155 | void SimpleTopology::buildTopo(){ 156 | 157 | host_id_t hostId; 158 | switch_id_t switchId; 159 | host_p h0, h1, h2, h3; 160 | switch_p s0, s1, s2; 161 | 162 | // Create all hosts 163 | h0 = this->createNewHost(); 164 | h1 = this->createNewHost(); 165 | // h2 = this->createNewHost(); 166 | // h3 = this->createNewHost(); 167 | 168 | // Create all switches 169 | s0 = this->createNewSwitch(SwitchType::Simple); 170 | s1 = this->createNewSwitch(SwitchType::Simple); 171 | s2 = this->createNewSwitch(SwitchType::Simple); 172 | 173 | this->addHostToTor(h0, s0); 174 | // this->addHostToTor(h2, s0); 175 | this->addHostToTor(h1, s1); 176 | // this->addHostToTor(h3, s1); 177 | 178 | connectSwitchToSwitch(s0, s2); 179 | connectSwitchToSwitch(s1, s2); 180 | 181 | // Setup routing on s0. Need to downcast shared_pointer to SimpleSwitch 182 | auto s0_ss = std::dynamic_pointer_cast(s0); 183 | s0_ss->routingTable[s1->id] = s2->id; 184 | 185 | // Setup routing on s1. Need to downcast shared_pointer to SimpleSwitch 186 | auto s1_ss = std::dynamic_pointer_cast(s1); 187 | s1_ss->routingTable[s0->id] = s2->id; 188 | 189 | // Setup routing on s2 190 | // NO need since both the other ToRs are neighbors 191 | } 192 | 193 | /* 194 | h0 --- s0 --- s1 --- s2 --- s3 --- s4 --- h1 195 | */ 196 | void LineTopology::buildTopo(){ 197 | 198 | host_p h0, h1; 199 | switch_p s0, s1, s2, s3, s4; 200 | 201 | // Create all hosts 202 | h0 = this->createNewHost(); 203 | h1 = this->createNewHost(true); 204 | 205 | // Create all switches 206 | s0 = this->createNewSwitch(SwitchType::Simple); 207 | s1 = this->createNewSwitch(SwitchType::Simple); 208 | s2 = this->createNewSwitch(SwitchType::Simple); 209 | s3 = this->createNewSwitch(SwitchType::Simple); 210 | s4 = this->createNewSwitch(SwitchType::Simple); 211 | 212 | this->addHostToTor(h0, s0); 213 | this->addHostToTor(h1, s4); 214 | 215 | this->connectSwitchToSwitch(s0, s1); 216 | this->connectSwitchToSwitch(s1, s2); 217 | this->connectSwitchToSwitch(s2, s3); 218 | this->connectSwitchToSwitch(s3, s4); 219 | 220 | // Setup routing on the switches. Need to downcast shared_pointer to SimpleSwitch 221 | auto s0_ss = std::dynamic_pointer_cast(s0); 222 | auto s1_ss = std::dynamic_pointer_cast(s1); 223 | auto s2_ss = std::dynamic_pointer_cast(s2); 224 | auto s3_ss = std::dynamic_pointer_cast(s3); 225 | auto s4_ss = std::dynamic_pointer_cast(s4); 226 | 227 | // Add routes for ToR switches when not direct neighbor 228 | s0_ss->routingTable[s4->id] = s1->id; 229 | s1_ss->routingTable[s4->id] = s2->id; 230 | s2_ss->routingTable[s0->id] = s1->id; 231 | s2_ss->routingTable[s4->id] = s3->id; 232 | s3_ss->routingTable[s0->id] = s2->id; 233 | s4_ss->routingTable[s0->id] = s3->id; 234 | 235 | ndebug_print_yellow("Built Line topo:"); 236 | ndebug_print("h0 --- s0 --- s1 --- s2 --- s3 --- s4 --- h1\n"); 237 | 238 | } 239 | -------------------------------------------------------------------------------- /topology/topology.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TOPOLOGY_H 2 | #define TOPOLOGY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "topology/host.hpp" 8 | #include "topology/link.hpp" 9 | #include "topology/switch.hpp" 10 | #include "topology/switch_ft.hpp" 11 | 12 | typedef std::unordered_map host_tor_map_t; 13 | typedef std::unordered_map host_id_map_t; 14 | typedef std::unordered_map switch_id_map_t; 15 | 16 | 17 | struct Topology 18 | { 19 | host_id_t nextHostId = 0; 20 | link_id_t nextLinkId = 0; 21 | switch_id_t nextSwitchId = 0; 22 | 23 | // Hold all shared_ptrs so that hosts, links, switches don't get destroyed by mistake 24 | // Keeping two links separate for possible future optimizations 25 | std::vector networkLinkVector; 26 | std::vector torLinkVector; 27 | host_id_map_t hostIDMap; 28 | switch_id_map_t switchIDMap; 29 | 30 | host_tor_map_t hostTorMap; // updated by addHostToTor() 31 | std::map> switchTypeIDMap; // updated by createNewSwitch() 32 | 33 | switch_id_t getTorId(host_id_t hostId); 34 | Switch* getSwitchById(switch_id_t id); 35 | SwitchType getSwitchTypeById(switch_id_t id); 36 | Host* getHostById(host_id_t hostId); 37 | 38 | inline host_id_t getNextHostId() {return this->nextHostId++;} 39 | inline link_id_t getNextLinkId() {return this->nextLinkId++;} 40 | inline switch_id_t getNextSwitchId() {return this->nextSwitchId++;} 41 | 42 | host_tor_link_p createNewToRLink(); 43 | network_link_p createNewNetworLink(switch_id_t sw1, switch_id_t sw2); 44 | switch_p createNewSwitch(SwitchType type); 45 | host_p createNewHost(bool trafficGenDisabled = false); 46 | 47 | void addHostToTor(host_p &host, switch_p &tor); 48 | void connectSwitchToSwitch(switch_p &s1, switch_p &s2); 49 | 50 | Topology(); 51 | virtual void buildTopo() = 0; 52 | 53 | }; 54 | 55 | /* 56 | s2 57 | / \ 58 | s0 s1 59 | | | 60 | h0 h1 61 | 62 | */ 63 | struct SimpleTopology : Topology 64 | { 65 | // Override the virtual function of the abstract class 66 | void buildTopo(); 67 | }; 68 | 69 | /* 70 | h0 --- s0 --- s1 --- s2 --- s3 --- s4 --- h1 71 | */ 72 | struct LineTopology : Topology 73 | { 74 | // Override the virtual function of the abstract class 75 | void buildTopo(); 76 | }; 77 | 78 | 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv: -------------------------------------------------------------------------------- 1 | 10000 2 | 10000 3 | 10000 4 | 10000 5 | 10000 6 | 10000 7 | 10000 8 | 10000 9 | 10000 10 | 10000 11 | 20000 12 | 20000 13 | 20000 14 | 20000 15 | 20000 16 | 20000 17 | 20000 18 | 20000 19 | 20000 20 | 20000 21 | 30000 22 | 30000 23 | 30000 24 | 30000 25 | 100000 26 | 100000 27 | 100000 28 | 100000 29 | 100000 30 | 100000 31 | 250000 32 | 250000 33 | 250000 34 | 250000 35 | 250000 36 | 250000 37 | 250000 38 | 250000 39 | 250000 40 | 250000 41 | 900000 42 | 900000 43 | 900000 44 | 900000 45 | 900000 46 | 1000000 47 | 1000000 48 | 1000000 49 | 1000000 50 | 1000000 51 | 2000000 52 | 2000000 53 | 2000000 54 | 2000000 55 | 2000000 56 | 2000000 57 | 2000000 58 | 2000000 59 | 2000000 60 | 2000000 61 | 2000000 62 | 2000000 63 | 2000000 64 | 2000000 65 | 2000000 66 | 2000000 67 | 2000000 68 | 2000000 69 | 2000000 70 | 2000000 71 | 2000000 72 | 2000000 73 | 2000000 74 | 2000000 75 | 2000000 76 | 2000000 77 | 2000000 78 | 2000000 79 | 2000000 80 | 2000000 81 | 2000000 82 | 2000000 83 | 2000000 84 | 2000000 85 | 2000000 86 | 2000000 87 | 2000000 88 | 2000000 89 | 2000000 90 | 2000000 91 | 10000000 92 | 10000000 93 | 10000000 94 | 10000000 95 | 10000000 96 | 10000000 97 | 10000000 98 | 10000000 99 | 10000000 100 | 80000000 -------------------------------------------------------------------------------- /traffic-dist/fb_webserver_packetsizedist_cdf.csv: -------------------------------------------------------------------------------- 1 | 80 2 | 80 3 | 80 4 | 80 5 | 80 6 | 80 7 | 80 8 | 80 9 | 80 10 | 80 11 | 80 12 | 80 13 | 80 14 | 80 15 | 80 16 | 80 17 | 80 18 | 80 19 | 80 20 | 80 21 | 80 22 | 80 23 | 80 24 | 80 25 | 80 26 | 80 27 | 80 28 | 80 29 | 80 30 | 80 31 | 80 32 | 80 33 | 80 34 | 80 35 | 80 36 | 80 37 | 80 38 | 80 39 | 80 40 | 80 41 | 80 42 | 80 43 | 80 44 | 80 45 | 100 46 | 100 47 | 100 48 | 100 49 | 100 50 | 120 51 | 120 52 | 120 53 | 120 54 | 120 55 | 120 56 | 120 57 | 120 58 | 120 59 | 120 60 | 180 61 | 180 62 | 180 63 | 180 64 | 180 65 | 200 66 | 200 67 | 200 68 | 200 69 | 200 70 | 200 71 | 210 72 | 210 73 | 210 74 | 210 75 | 210 76 | 210 77 | 210 78 | 210 79 | 210 80 | 210 81 | 250 82 | 250 83 | 250 84 | 300 85 | 300 86 | 300 87 | 300 88 | 400 89 | 500 90 | 600 91 | 750 92 | 1000 93 | 1200 94 | 1200 95 | 1200 96 | 1200 97 | 1300 98 | 1300 99 | 1400 100 | 1500 -------------------------------------------------------------------------------- /traffic-dist/flowinterarrival_cdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajkiranjoshi/syndb-sim/4be3e637d94bfd988869757f883cdb16170647df/traffic-dist/flowinterarrival_cdf.png -------------------------------------------------------------------------------- /traffic-dist/packetinterarrival_cdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajkiranjoshi/syndb-sim/4be3e637d94bfd988869757f883cdb16170647df/traffic-dist/packetinterarrival_cdf.png -------------------------------------------------------------------------------- /traffic-dist/packetinterarrival_ns_cdf.csv: -------------------------------------------------------------------------------- 1 | 8 2 | 8 3 | 8 4 | 8 5 | 8 6 | 8 7 | 8 8 | 8 9 | 8 10 | 8 11 | 8 12 | 8 13 | 8 14 | 20 15 | 20 16 | 20 17 | 20 18 | 20 19 | 20 20 | 80 21 | 80 22 | 80 23 | 80 24 | 80 25 | 80 26 | 80 27 | 80 28 | 80 29 | 80 30 | 80 31 | 80 32 | 80 33 | 80 34 | 80 35 | 80 36 | 80 37 | 80 38 | 80 39 | 80 40 | 80 41 | 80 42 | 80 43 | 80 44 | 80 45 | 80 46 | 80 47 | 80 48 | 80 49 | 80 50 | 400 51 | 400 52 | 400 53 | 400 54 | 400 55 | 400 56 | 400 57 | 400 58 | 400 59 | 400 60 | 400 61 | 400 62 | 400 63 | 400 64 | 400 65 | 400 66 | 400 67 | 400 68 | 400 69 | 400 70 | 600 71 | 600 72 | 600 73 | 600 74 | 600 75 | 600 76 | 600 77 | 600 78 | 600 79 | 600 80 | 600 81 | 800 82 | 800 83 | 800 84 | 800 85 | 800 86 | 800 87 | 800 88 | 800 89 | 800 90 | 1000 91 | 1000 92 | 1000 93 | 1000 94 | 1000 95 | 1000 96 | 1000 97 | 8000 98 | 8000 99 | 8000 100 | 8000 -------------------------------------------------------------------------------- /traffic-dist/packetsizedist_cdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajkiranjoshi/syndb-sim/4be3e637d94bfd988869757f883cdb16170647df/traffic-dist/packetsizedist_cdf.png -------------------------------------------------------------------------------- /traffic/incastGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // std::random_shuffle 6 | #include "traffic/incastGenerator.hpp" 7 | #include "simulation/config.hpp" 8 | #include "simulation/simulation.hpp" 9 | #include "utils/utils.hpp" 10 | #include "utils/logger.hpp" 11 | #include "topology/host.hpp" 12 | 13 | IncastGenerator::IncastGenerator(){ 14 | 15 | assert(syndbConfig.incastFanInRatio <= syndbConfig.numHosts && "Incast fan-in ratio must NOT be larger than total numHosts!"); 16 | 17 | sim_time_t totalTime = (sim_time_t)(syndbConfig.totalTimeMSecs * (float)1000000); 18 | 19 | sim_time_t fullUtilTimeNeeded = ((double)syndbConfig.percentIncastTime / 100.0) * (double) totalTime; 20 | 21 | /* ASSUMPTION: 22 | We are going to change/override packet sizes to 1500B. Time for which one incast keeps a link fully utilized = serialization time of 1550B pkt x syndbConfig.incastFanInRatio 23 | */ 24 | sim_time_t fullUtilTimePerIncast = syndbConfig.incastFanInRatio * getSerializationDelay(1500, syndbConfig.torLinkSpeedGbps); 25 | sim_time_t incastsPerTargetLink = fullUtilTimeNeeded / fullUtilTimePerIncast; 26 | 27 | // Handle the case that simulation time is much small such that fullUtilTimeNeeded > fullUtilTimePerIncast 28 | // Guarantee that at least 1 incast per target link 29 | incastsPerTargetLink = std::max(incastsPerTargetLink, 1); 30 | 31 | host_id_t numTargetHosts = ((double)syndbConfig.percentTargetIncastHosts / 100.0) * syndbConfig.numHosts; 32 | sim_time_t totalIncasts = numTargetHosts * incastsPerTargetLink; 33 | this->totalIncasts = totalIncasts; 34 | /* 35 | // Single test trigger 36 | incastScheduleInfo_p newIncast = std::shared_ptr(new incastScheduleInfo()); 37 | newIncast->time = 25000; 38 | newIncast->targetHostId = 0; 39 | for(int i=1; i < syndbConfig.numHosts; i++){ 40 | newIncast->sourceHosts.push_back(i); 41 | } 42 | this->incastSchedule.push_back(newIncast); 43 | */ 44 | // Here OnWard: Scheduling the incasts over time 45 | sim_time_t availableTime = totalTime - this->initialDelay; 46 | 47 | // Pick randomly numTargetHosts number of unique hosts 48 | std::set targetHosts; 49 | uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 50 | std::default_random_engine randTargetHosts(seed); 51 | 52 | while (targetHosts.size() != numTargetHosts) 53 | { 54 | host_id_t host = randTargetHosts() % syndbConfig.numHosts; 55 | targetHosts.insert(host); 56 | } 57 | 58 | // Fill the vector with repeated host IDs 59 | std::vector targetHostsVector; 60 | for(auto it = targetHosts.begin(); it != targetHosts.end(); it++){ 61 | host_id_t host = *it; 62 | for(int i=0; i < incastsPerTargetLink; i++){ 63 | targetHostsVector.push_back(host); 64 | } 65 | } 66 | std::random_shuffle(targetHostsVector.begin(), targetHostsVector.end()); 67 | 68 | // Generate the schedule and add hosts from targetHostsVector sequentially 69 | sim_time_t interIncastGap = availableTime / (totalIncasts + 1); 70 | sim_time_t halfSimTimeIncrement = syndbSim.timeIncrement / 2; 71 | 72 | // Align the interIncastGap to sim timeIncr 73 | interIncastGap = ((interIncastGap + halfSimTimeIncrement) / syndbSim.timeIncrement) * syndbSim.timeIncrement; 74 | 75 | seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 76 | std::default_random_engine randSourceHosts(seed); 77 | sim_time_t currTime = this->initialDelay + interIncastGap; 78 | host_id_t srcHost; 79 | 80 | for(auto it = targetHostsVector.begin(); it != targetHostsVector.end(); it++){ 81 | 82 | incastScheduleInfo_p newIncast = std::shared_ptr(new incastScheduleInfo()); 83 | newIncast->time = currTime; 84 | newIncast->targetHostId = *it; 85 | 86 | while (newIncast->sourceHosts.size() != syndbConfig.incastFanInRatio) 87 | { 88 | srcHost = randSourceHosts() % syndbConfig.numHosts; 89 | if(srcHost != newIncast->targetHostId) 90 | newIncast->sourceHosts.insert(srcHost); 91 | } 92 | 93 | this->incastSchedule.push_back(newIncast); 94 | 95 | currTime += interIncastGap; // update for next incast 96 | } 97 | // update nextIncast pointers from the schedule 98 | this->updateNextIncast(); 99 | } 100 | 101 | 102 | void IncastGenerator::updateNextIncast(){ 103 | if(this->incastSchedule.size() > 0){ 104 | this->nextIncast = *this->incastSchedule.begin(); 105 | this->nextIncastTime = this->nextIncast->time; 106 | this->incastSchedule.pop_front(); 107 | } 108 | } 109 | 110 | void IncastGenerator::generateIncast(){ 111 | 112 | if(syndbSim.currTime == this->nextIncastTime){ // it MUST be equal 113 | 114 | host_id_t targetHost = this->nextIncast->targetHostId; 115 | 116 | for(auto it = this->nextIncast->sourceHosts.begin(); it != this->nextIncast->sourceHosts.end(); it++){ 117 | Host* host = syndbSim.topo->getHostById(*it); 118 | 119 | host->nextPkt->size = 1500; 120 | host->nextPkt->dstHost = targetHost; 121 | 122 | sim_time_t newNextPktTime = host->prevPktTime + getSerializationDelay(1500, syndbConfig.torLinkSpeedGbps); 123 | host->nextPktTime = newNextPktTime; 124 | host->torLink->next_idle_time_to_tor = newNextPktTime; 125 | 126 | // ndebug_print("Incast pkt ID: {}", host->nextPkt->id); 127 | } 128 | 129 | #if LOGGING 130 | syndbSim.pktDumper->dumpIncastInfo(*this->nextIncast); 131 | #endif 132 | 133 | this->updateNextIncast(); 134 | } 135 | 136 | } 137 | 138 | void IncastGenerator::printIncastSchedule(){ 139 | 140 | ndebug_print_yellow("Incast Schedule: {} total incasts", this->totalIncasts); 141 | 142 | // Print the lined-up incast first 143 | this->nextIncast->printScheduleInfo(); 144 | 145 | // Then print the rest 146 | 147 | for(auto it = this->incastSchedule.begin(); it != this->incastSchedule.end(); it++){ 148 | (*it)->printScheduleInfo(); 149 | } 150 | 151 | } 152 | 153 | void incastScheduleInfo::printScheduleInfo(){ 154 | #ifdef DEBUG 155 | host_id_t targetHost = this->targetHostId; 156 | sim_time_t incastTime = this->time; 157 | std::string srcHosts = ""; 158 | for(auto it = this->sourceHosts.begin(); it != this->sourceHosts.end(); it++){ 159 | srcHosts.append(fmt::format("{} ", *it)); 160 | } 161 | debug_print("Time: {}\tTarget: {} | Sources: {}", incastTime, targetHost, srcHosts); 162 | #endif 163 | } 164 | -------------------------------------------------------------------------------- /traffic/incastGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INCASTGENERATOR_H 2 | #define INCASTGENERATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils/types.hpp" 9 | 10 | 11 | struct incastScheduleInfo{ 12 | sim_time_t time; 13 | host_id_t targetHostId; 14 | 15 | std::set sourceHosts; 16 | 17 | void printScheduleInfo(); 18 | }; 19 | 20 | typedef std::shared_ptr incastScheduleInfo_p; 21 | 22 | struct IncastGenerator 23 | { 24 | std::list incastSchedule; 25 | const sim_time_t initialDelay = 10000; // 10us - for both topologies 26 | 27 | sim_time_t totalIncasts; 28 | 29 | sim_time_t nextIncastTime; 30 | incastScheduleInfo_p nextIncast; 31 | 32 | IncastGenerator(); 33 | void generateIncast(); 34 | void updateNextIncast(); 35 | void printIncastSchedule(); 36 | }; 37 | 38 | 39 | struct IncastGeneratorSimpleTopo: IncastGenerator 40 | { 41 | IncastGeneratorSimpleTopo(); 42 | }; 43 | 44 | 45 | struct IncastGeneratorFatTreeTopo : IncastGenerator 46 | { 47 | IncastGeneratorFatTreeTopo(); 48 | }; 49 | 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /traffic/packet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "traffic/packet.hpp" 3 | #include "utils/logger.hpp" 4 | #include "simulation/simulation.hpp" 5 | 6 | Pkt::Pkt(pkt_size_t size){ 7 | this->size = size; 8 | 9 | // debug_print(fmt::format("[Sim Time {}ns] Packet {} constructed!", syndbSim.currTime, id)); 10 | } 11 | 12 | NormalPkt::~NormalPkt(){ 13 | // debug_print(fmt::format("[Sim Time {}ns] Normal Packet {} destructed!", syndbSim.currTime, this->id)); 14 | } 15 | 16 | 17 | NormalPkt::NormalPkt(pkt_id_t id, pkt_size_t size):Pkt::Pkt(size){ 18 | this->id = id; 19 | this->endTime = 0; 20 | } 21 | 22 | TriggerPkt::TriggerPkt(trigger_id_t triggerId, pkt_size_t size):Pkt::Pkt(size){ 23 | this->triggerId = triggerId; 24 | } 25 | -------------------------------------------------------------------------------- /traffic/packet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PACKET_H 2 | #define PACKET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "utils/types.hpp" 8 | 9 | struct switchINTInfo 10 | { 11 | switch_id_t swId; 12 | sim_time_t rxTime; 13 | }; 14 | 15 | 16 | 17 | /* Pkt Struct */ 18 | typedef struct Pkt { 19 | pkt_size_t size; 20 | 21 | Pkt() = default; 22 | Pkt(pkt_size_t size); 23 | 24 | // ~Pkt(); 25 | 26 | } Pkt; 27 | 28 | typedef struct NormalPkt : Pkt { 29 | pkt_id_t id; 30 | host_id_t srcHost; 31 | host_id_t dstHost; 32 | 33 | /* INT data for simulation */ 34 | sim_time_t startTime, endTime; 35 | std::list switchINTInfoList; 36 | 37 | NormalPkt(pkt_id_t id, pkt_size_t size); 38 | ~NormalPkt(); 39 | // using Pkt::Pkt; // Inheriting constructor of base class Pkt 40 | 41 | } NormalPkt; 42 | 43 | // typedef std::shared_ptr normalpkt_p; 44 | typedef NormalPkt* normalpkt_p; 45 | 46 | /* triggerPkt Struct */ 47 | typedef struct TriggerPkt : Pkt { 48 | trigger_id_t triggerId; 49 | switch_id_t srcSwitchId; 50 | switch_id_t dstSwitchId; 51 | trigger_id_t triggerOriginSwId; 52 | sim_time_t triggerTime; 53 | 54 | TriggerPkt(trigger_id_t triggerId, pkt_size_t size); 55 | // using Pkt::Pkt; // Inheriting constructor of base class Pkt 56 | 57 | } TriggerPkt; 58 | 59 | typedef std::shared_ptr triggerpkt_p; 60 | 61 | enum class PacketType {NormalPkt, TriggerPkt}; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /traffic/randomGenCDF.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "simulation/config.hpp" 4 | #include "randomGenCDF.hpp" 5 | using namespace std; 6 | 7 | 8 | std::vector RandomFromCDF::readCDFFile (string fileName) { 9 | fstream myCDFFile; 10 | string line; 11 | vector > cdfMatrix; 12 | vector distribution; 13 | myCDFFile.open(fileName, ios::in); 14 | if (!myCDFFile) { 15 | printf("CDF file not found!!\n"); 16 | } 17 | while (getline(myCDFFile, line)) { 18 | pair myPair; 19 | std::istringstream iss(line); 20 | int a, b; 21 | char c; 22 | iss>>a; 23 | distribution.push_back(a); 24 | } 25 | myCDFFile.close(); 26 | return distribution; 27 | } 28 | 29 | void RandomFromCDF::loadCDFs (std::string packetsizeDistFile, std::string packetarrivalDistFile) { 30 | packetSizeDist = readCDFFile(packetsizeDistFile); 31 | packetArrivalDist = readCDFFile(packetarrivalDistFile); 32 | uint64_t mySeed1 = std::chrono::system_clock::now().time_since_epoch().count(); 33 | std::this_thread::sleep_for(std::chrono::microseconds(1)); 34 | uint64_t mySeed2 = std::chrono::system_clock::now().time_since_epoch().count(); 35 | generator.seed(mySeed1); 36 | generator2.seed(mySeed2); 37 | uniformDist = std::uniform_int_distribution<>(0,99); 38 | } 39 | 40 | int RandomFromCDF::getNextPacketSize () { 41 | int packetSize; 42 | int random = uniformDist(generator); 43 | packetSize = packetSizeDist.at(random); 44 | return packetSize; 45 | } 46 | 47 | int RandomFromCDF::getNextPacketDelay () { 48 | int packetDelay; 49 | int random = uniformDist(generator2); 50 | packetDelay = packetArrivalDist.at(random); 51 | packetDelay = (int)((double) packetDelay / ((double)syndbConfig.targetBaseNetworkLoadPercent / 3.0)); 52 | return packetDelay; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /traffic/randomGenCDF.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RANDOMGENCDF_H 2 | #define RANDOMGENCDF_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "utils/types.hpp" 13 | 14 | 15 | typedef struct randomCDF 16 | { 17 | std::vector packetSizeDist; 18 | std::vector packetArrivalDist; 19 | 20 | std::default_random_engine generator; 21 | std::default_random_engine generator2; 22 | 23 | std::uniform_int_distribution uniformDist; 24 | 25 | std::vector readCDFFile(std::string fileName); 26 | void loadCDFs(std::string packetsizeDistFile, std::string flowarrivalDistFile); 27 | 28 | int getNextPacketSize(); 29 | int getNextPacketDelay(); 30 | 31 | } RandomFromCDF; 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /traffic/trafficGenerator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "traffic/trafficGenerator.hpp" 4 | #include "simulation/simulation.hpp" 5 | #include "utils/utils.hpp" 6 | 7 | 8 | 9 | 10 | 11 | 12 | TrafficGenerator::~TrafficGenerator(){ 13 | // this->interPktGapFile.close(); 14 | } 15 | 16 | /* Data-ceter Traffic generator based on */ 17 | /* Load variation: return pkt_size 0, if no packet is to be sent. */ 18 | 19 | void DcTrafficGenerator::getNextPacket(packetInfo &pktInfo){ 20 | 21 | pktInfo.size = myRandomFromCDF.getNextPacketSize(); 22 | pktInfo.sendDelay = myRandomFromCDF.getNextPacketDelay(); 23 | 24 | // this->interPktGapFile << sendDelay << std::endl; 25 | 26 | } 27 | 28 | int DcTrafficGenerator::loadTrafficDistribution (std::string packetsizeDistFile, std::string flowarrivalDistFile) { 29 | pkt_size_t base_size = 80; // in bytes 30 | pkt_size_t size_on_wire = base_size + 24; 31 | // int pps = ((this->torLinkSpeed * 1000000000)/ (size_on_wire * 8)); 32 | // sim_time_t min_delay_ns = ((double)1/(double)pps * 1000000000); 33 | sim_time_t min_delay_ns = (size_on_wire * 8) / syndbConfig.torLinkSpeedGbps; 34 | 35 | 36 | myRandomFromCDF.loadCDFs("traffic-dist/fb_webserver_packetsizedist_cdf.csv", "traffic-dist/packetinterarrival_ns_cdf.csv"); 37 | return 0; 38 | } 39 | 40 | /* Simple pkt generator for now: continuous generation */ 41 | /* Load variation: return pkt_size 0, if no packet is to be sent. */ 42 | void SimpleTrafficGenerator::getNextPacket(packetInfo &pktInfo){ 43 | 44 | pktInfo.size = syndbConfig.fixedPktSizeForSimpleTrafficGen; 45 | pktInfo.sendDelay = 0; 46 | 47 | } 48 | 49 | int SimpleTrafficGenerator::loadTrafficDistribution (std::string packetsizeDistFile, std::string flowarrivalDistFile) { 50 | 51 | return 0; 52 | } 53 | 54 | // int main () { 55 | // TrafficGenerator *myGen = new DcTrafficGenerator(100, 100, 1); 56 | // myGen->loadTrafficDistribution("../traffic-dist/fb_webserver_packetsizedist_cdf.csv", "../traffic-dist/fb_webserver_flowinterarrival_ns_cdf.csv"); 57 | // for (int i=0;i<100;i++) { 58 | // packetInfo pktinfo = myGen->getNextPacket(); 59 | // printf("Pkt Size = %d, sendDelay=%ld\n", pktinfo.size, pktinfo.sendDelay); 60 | // } 61 | // return 0; 62 | // } -------------------------------------------------------------------------------- /traffic/trafficGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRAFFICGEN_H 2 | #define TRAFFICGEN_H 3 | 4 | #include 5 | #include "utils/types.hpp" 6 | #include "traffic/packet.hpp" 7 | #include "randomGenCDF.hpp" 8 | 9 | struct packetInfo 10 | { 11 | 12 | pkt_size_t size; 13 | time_t sendDelay; 14 | 15 | 16 | }; 17 | 18 | 19 | struct TrafficGenerator 20 | { 21 | 22 | 23 | ~TrafficGenerator(); 24 | 25 | virtual void getNextPacket(packetInfo &pktInfo) = 0; 26 | virtual int loadTrafficDistribution(std::string packetsizeDistFile, std::string packetarrivalDistFile) = 0; 27 | }; 28 | 29 | 30 | /* SimpleTrafficGenerator struct */ 31 | struct SimpleTrafficGenerator : TrafficGenerator 32 | { 33 | 34 | /* Overriding method of the abstract class */ 35 | void getNextPacket(packetInfo &pktInfo); 36 | int loadTrafficDistribution(std::string packetsizeDistFile, std::string packetarrivalDistFile); 37 | }; 38 | 39 | /* DC Trafficgenerator struct */ 40 | struct DcTrafficGenerator : TrafficGenerator 41 | { 42 | RandomFromCDF myRandomFromCDF; 43 | 44 | // using TrafficGenerator::TrafficGenerator; 45 | 46 | void getNextPacket(packetInfo &pktInfo); 47 | int loadTrafficDistribution(std::string packetsizeDistFile, std::string packetarrivalDistFile); 48 | }; 49 | 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /traffic/trafficPattern.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "traffic/trafficPattern.hpp" 5 | #include "simulation/simulation.hpp" 6 | #include "topology/host.hpp" 7 | #include "utils/logger.hpp" 8 | 9 | host_id_t SimpleTopoTrafficPattern::applyTrafficPattern(){ 10 | // Hard-coded logic for destination host. Mainly for SimpleTopology 11 | return (this->parentHostId + 1) % 2; // 1 for 0 and 0 for 1 12 | } 13 | 14 | AlltoAllTrafficPattern::AlltoAllTrafficPattern(host_id_t hostId): TrafficPattern::TrafficPattern(hostId){ 15 | this->nextDst = (hostId + 1) % syndbConfig.numHosts; 16 | } 17 | 18 | host_id_t AlltoAllTrafficPattern::applyTrafficPattern(){ 19 | host_id_t dstHost; 20 | 21 | dstHost = this->nextDst; 22 | 23 | this->nextDst = (this->nextDst + 1) % syndbConfig.numHosts; 24 | 25 | return dstHost; 26 | /* Termination Logic: 27 | - when dstHost becomes same as parentHostId, it's a loopback pkt 28 | - after a loopback pkt is detected in Host::sendpkt(), no more calls to generatePkt() and so no more calls to applyTrafficPattern() 29 | */ 30 | } 31 | 32 | 33 | FtUniformTrafficPattern::FtUniformTrafficPattern(host_id_t hostId):TrafficPattern::TrafficPattern(hostId){ 34 | host_id_t halfPoint = syndbConfig.numHosts / 2; 35 | 36 | if(hostId < halfPoint){ // this host is in the left half 37 | this->fixedDstHost = hostId + halfPoint; 38 | } 39 | else // this host is in the right half 40 | { 41 | this->fixedDstHost = hostId - halfPoint; 42 | } 43 | } 44 | 45 | host_id_t FtUniformTrafficPattern::applyTrafficPattern(){ 46 | return this->fixedDstHost; 47 | } 48 | 49 | FtMixedTrafficPattern::FtMixedTrafficPattern(host_id_t hostId):TrafficPattern::TrafficPattern(hostId){ 50 | 51 | uint64_t seed1 = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 52 | this->randTrafficType = std::default_random_engine(seed1); 53 | 54 | // sleep to ensure suffiently different next seed 55 | std::this_thread::sleep_for(std::chrono::microseconds(1)); 56 | 57 | uint64_t seed2 = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 58 | this->randIntraRackHost = std::default_random_engine(seed2); 59 | 60 | // sleep to ensure suffiently different next seed 61 | std::this_thread::sleep_for(std::chrono::microseconds(1)); 62 | 63 | uint64_t seed3 = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 64 | this->randInterRackHost = std::default_random_engine(seed3); 65 | 66 | } 67 | 68 | void FtMixedTrafficPattern::initTopoInfo(){ 69 | 70 | host_id_t min = std::numeric_limits::max(); 71 | host_id_t max = 0; 72 | host_id_t rackHostId; 73 | 74 | switch_id_t torId = syndbSim.topo->getTorId(this->parentHostId); 75 | const Switch* tor = syndbSim.topo->getSwitchById(torId); 76 | 77 | for(auto it = tor->neighborHostTable.begin(); it != tor->neighborHostTable.end(); it++){ 78 | rackHostId = it->first; 79 | 80 | if(rackHostId < min) 81 | min = rackHostId; 82 | 83 | if(rackHostId > max) 84 | max = rackHostId; 85 | } 86 | 87 | this->rackMinId = min; 88 | this->rackMaxId = max; 89 | 90 | } 91 | 92 | TrafficDstType FtMixedTrafficPattern::getDstType(){ 93 | 94 | TrafficDstType distType; 95 | 96 | uint_fast32_t randval = this->randTrafficType() % 100; 97 | 98 | if(randval <= syndbConfig.ftMixedPatternPercentIntraRack) 99 | distType = TrafficDstType::IntraRack; 100 | else 101 | distType = TrafficDstType::InterRack; 102 | 103 | return distType; 104 | } 105 | 106 | host_id_t FtMixedTrafficPattern::getRandomIntraRackHost(){ 107 | 108 | host_id_t dstHost; 109 | uint_fast32_t randval; 110 | 111 | host_id_t numHostsPerRack = syndbConfig.fatTreeTopoK / 2; 112 | 113 | do { 114 | randval = this->randIntraRackHost() % numHostsPerRack; 115 | dstHost = this->rackMinId + randval; 116 | } while (dstHost == this->parentHostId); 117 | 118 | return dstHost; 119 | 120 | } 121 | 122 | host_id_t FtMixedTrafficPattern::getRandomInterRackHost(){ 123 | 124 | host_id_t dstHost; 125 | uint_fast32_t randval; 126 | 127 | do 128 | { 129 | dstHost = this->randInterRackHost() % syndbConfig.numHosts; 130 | } while (dstHost >= this->rackMinId && dstHost <= this->rackMaxId); 131 | 132 | return dstHost; 133 | } 134 | 135 | host_id_t FtMixedTrafficPattern::applyTrafficPattern(){ 136 | 137 | TrafficDstType dstType = this->getDstType(); 138 | 139 | if(dstType == TrafficDstType::IntraRack){ 140 | return this->getRandomIntraRackHost(); 141 | } 142 | else{ 143 | return this->getRandomInterRackHost(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /traffic/trafficPattern.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRAFFICPATTERN_H 2 | #define TRAFFICPATTERN_H 3 | 4 | #include 5 | #include "utils/types.hpp" 6 | 7 | struct TrafficPattern 8 | { 9 | host_id_t parentHostId; 10 | 11 | TrafficPattern(host_id_t hostId) {this->parentHostId = hostId;}; 12 | virtual host_id_t applyTrafficPattern() = 0; 13 | }; 14 | 15 | struct SimpleTopoTrafficPattern : TrafficPattern 16 | { 17 | // Using constructor same as the base class. 18 | using TrafficPattern::TrafficPattern; 19 | host_id_t applyTrafficPattern(); 20 | }; 21 | 22 | struct AlltoAllTrafficPattern : TrafficPattern 23 | { 24 | host_id_t nextDst; 25 | 26 | AlltoAllTrafficPattern(host_id_t hostId); 27 | host_id_t applyTrafficPattern(); 28 | }; 29 | 30 | struct FtUniformTrafficPattern : TrafficPattern 31 | { 32 | host_id_t fixedDstHost; 33 | 34 | FtUniformTrafficPattern(host_id_t hostId); 35 | host_id_t applyTrafficPattern(); 36 | }; 37 | 38 | struct FtMixedTrafficPattern : TrafficPattern 39 | { 40 | host_id_t rackMinId, rackMaxId; 41 | 42 | std::default_random_engine randTrafficType; 43 | std::default_random_engine randIntraRackHost; 44 | std::default_random_engine randInterRackHost; 45 | 46 | FtMixedTrafficPattern(host_id_t hostId); 47 | host_id_t applyTrafficPattern(); 48 | 49 | void initTopoInfo(); 50 | 51 | private: 52 | TrafficDstType getDstType(); 53 | host_id_t getRandomIntraRackHost(); 54 | host_id_t getRandomInterRackHost(); 55 | }; 56 | 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /traffic/traffictester.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | using namespace std; 14 | 15 | typedef struct randomCDF 16 | { 17 | std::vector packetSizeDist; 18 | std::vector packetArrivalDist; 19 | 20 | unsigned mySeed; 21 | 22 | std::default_random_engine generator; 23 | std::default_random_engine generator2; 24 | 25 | std::uniform_int_distribution uniformDist; 26 | 27 | std::vector readCDFFile(std::string fileName); 28 | void loadCDFs(std::string packetsizeDistFile, std::string flowarrivalDistFile, int min_delay_ns); 29 | 30 | int getNextPacketSize(); 31 | uint64_t getNextFlowDelay(); 32 | uint64_t getNextPacketDelay(); 33 | 34 | } RandomFromCDF; 35 | 36 | 37 | std::vector RandomFromCDF::readCDFFile (string fileName) { 38 | fstream myCDFFile; 39 | string line; 40 | vector > cdfMatrix; 41 | vector distribution; 42 | myCDFFile.open(fileName, ios::in); 43 | if (!myCDFFile) { 44 | printf("CDF file not found!!\n"); 45 | } 46 | while (getline(myCDFFile, line)) { 47 | pair myPair; 48 | std::istringstream iss(line); 49 | int a, b; 50 | char c; 51 | iss>>a; 52 | distribution.push_back(a); 53 | } 54 | myCDFFile.close(); 55 | return distribution; 56 | } 57 | 58 | void RandomFromCDF::loadCDFs (std::string packetsizeDistFile, std::string packetarrivalDistFile, int min_delay_ns) { 59 | packetSizeDist = readCDFFile(packetsizeDistFile); 60 | packetArrivalDist = readCDFFile(packetarrivalDistFile); 61 | mySeed = std::chrono::system_clock::now().time_since_epoch().count(); 62 | generator.seed(mySeed); 63 | generator2.seed(mySeed); 64 | uniformDist = std::uniform_int_distribution<>(0,99); 65 | //lognormalDist = std::lognormal_distribution<>(min_delay_ns, min_delay_ns*10000); 66 | // lognormalDist = std::lognormal_distribution<>(5, 0.1); 67 | // weibullDist = std::weibull_distribution<>(5, 0.1); 68 | // printf("Log min=%lf, mac=%lf\n", lognormalDist.min(), lognormalDist.max()); 69 | // printf("Weibull min=%lf, mac=%lf\n", weibullDist.min(), weibullDist.max()); 70 | 71 | } 72 | 73 | int RandomFromCDF::getNextPacketSize () { 74 | int packetSize; 75 | int random = uniformDist(generator); 76 | packetSize = packetSizeDist.at(random); 77 | return packetSize; 78 | } 79 | 80 | 81 | uint64_t RandomFromCDF::getNextPacketDelay () { 82 | uint32_t packetDelay; 83 | int random = uniformDist(generator2); 84 | packetDelay = packetArrivalDist.at(random); 85 | printf("%d\n", packetDelay); 86 | return packetDelay; 87 | } 88 | 89 | RandomFromCDF myRandomFromCDF; 90 | 91 | uint32_t torLinkSpeed = 100; 92 | uint32_t load = 100; 93 | 94 | 95 | int loadTrafficDistribution (std::string packetsizeDistFile, std::string packetarrivalDistFile) { 96 | uint32_t base_size = 80; // in bytes 97 | uint32_t size_on_wire = base_size + 24; 98 | // int pps = ((this->torLinkSpeed * 1000000000)/ (size_on_wire * 8)); 99 | // sim_time_t min_delay_ns = ((double)1/(double)pps * 1000000000); 100 | uint32_t min_delay_ns = (size_on_wire * 8) / torLinkSpeed; 101 | printf("Min delay = %u\n", min_delay_ns); 102 | myRandomFromCDF.loadCDFs(packetsizeDistFile, packetarrivalDistFile, min_delay_ns); 103 | return 0; 104 | } 105 | 106 | void getNextPacket(){ 107 | 108 | uint32_t pkt_size = myRandomFromCDF.getNextPacketSize(); 109 | uint64_t sendDelay = myRandomFromCDF.getNextPacketDelay(); 110 | 111 | 112 | printf("Pkt Size = %d, sendDelay=%llu\n", pkt_size, sendDelay); 113 | 114 | } 115 | 116 | 117 | int main () { 118 | loadTrafficDistribution("../traffic-dist/fb_webserver_packetsizedist_cdf.csv", "../traffic-dist/packetinterarrival_ns_cdf.csv"); 119 | for (int i=0;i<100;i++) { 120 | getNextPacket(); 121 | } 122 | return 0; 123 | } 124 | */ -------------------------------------------------------------------------------- /traffic/triggerGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // std::random_shuffle 5 | #include "simulation/simulation.hpp" 6 | #include "traffic/triggerGenerator.hpp" 7 | #include "utils/logger.hpp" 8 | #include "simulation/config.hpp" 9 | #include "topology/fattree_topology.hpp" 10 | 11 | 12 | 13 | TriggerGenerator::TriggerGenerator(sim_time_t switchToSwitchOWD, uint16_t totalTriggers){ 14 | // assumes the constructor will be called after the topo is built 15 | 16 | this->baseIncrement = switchToSwitchOWD; 17 | this->totalTriggers = totalTriggers; 18 | 19 | // compute feasibility of triggers 20 | sim_time_t totalTime = (sim_time_t)(syndbConfig.totalTimeMSecs * (float)1000000); 21 | if(this->initialDelay >= totalTime){ 22 | std::string msg = fmt::format("Total sim time of {}ms <= initial trigger delay of {}ms. Fix syndbConfig.triggerInitialDelay and/or syndbConfig.totalTimeMSecs", syndbConfig.totalTimeMSecs, (double)this->initialDelay/1000000.0); 23 | throw std::logic_error(msg); 24 | } 25 | 26 | sim_time_t availableTime = totalTime - this->initialDelay; 27 | 28 | uint16_t maxPossibleTriggers = (availableTime / this->baseIncrement) - 1; 29 | 30 | if(totalTriggers > maxPossibleTriggers){ 31 | std::string msg = fmt::format("Cannot place {} triggers for total sim time of {}ms. Max triggers possible for this sim time are {}.", totalTriggers, syndbConfig.totalTimeMSecs, maxPossibleTriggers); 32 | throw std::logic_error(msg); 33 | } 34 | 35 | sim_time_t totalExtraTime = availableTime - ((this->totalTriggers + 1) * this->baseIncrement); 36 | sim_time_t extraTimePerTrigger = totalExtraTime / this->totalTriggers; 37 | uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 38 | std::default_random_engine generator(seed); 39 | std::uniform_int_distribution extraTimeDist((extraTimePerTrigger * 9 / 10), extraTimePerTrigger); 40 | this->getRandomExtraTime = std::bind(extraTimeDist, generator); 41 | 42 | } 43 | 44 | void TriggerGenerator::generateTrigger(){ 45 | 46 | if(this->nextTriggerTime == syndbSim.currTime){ // it MUST be equal 47 | Switch* currSwitch = syndbSim.topo->getSwitchById(this->nextSwitchId); 48 | currSwitch->generateTrigger(); 49 | 50 | this->updateNextTrigger(); 51 | } 52 | 53 | } 54 | 55 | void TriggerGenerator::updateNextTrigger(){ 56 | static auto nextTrigger = this->triggerSchedule.begin(); 57 | 58 | this->nextTriggerTime = nextTrigger->time; 59 | this->nextSwitchId = nextTrigger->switchId; 60 | 61 | nextTrigger++; 62 | } 63 | 64 | /* 65 | Constructs the trigger schedule for Simple topo. Then calls updateNextTrigger() so that nextTriggerTime and nextSwitchId are initialized. 66 | */ 67 | TriggerGeneratorSimpleTopo::TriggerGeneratorSimpleTopo():TriggerGenerator::TriggerGenerator(2012, syndbConfig.numTriggersPerSwitchType){ 68 | 69 | sim_time_t halfSimTimeIncrement = syndbSim.timeIncrement / 2; 70 | sim_time_t currBaseTime = this->initialDelay + this->baseIncrement; 71 | sim_time_t nextTime; 72 | switch_id_t nextSwitch; 73 | 74 | uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 75 | std::default_random_engine generator(seed); 76 | std::uniform_int_distribution switchSelectDist(0, syndbSim.topo->nextSwitchId-1); 77 | auto getRandomSwitchId = std::bind(switchSelectDist, std::ref(generator)); 78 | 79 | for(int i=0; i < this->totalTriggers; i++){ 80 | triggerScheduleInfo newScheduleInfo; 81 | 82 | nextSwitch = getRandomSwitchId(); 83 | nextTime = currBaseTime + this->getRandomExtraTime(); 84 | // round nextTime to nearest simulator increment 85 | nextTime = ((nextTime + halfSimTimeIncrement) / syndbSim.timeIncrement) * syndbSim.timeIncrement; 86 | 87 | newScheduleInfo.time = nextTime; 88 | newScheduleInfo.switchId = nextSwitch; 89 | 90 | this->triggerSchedule.push_back(newScheduleInfo); 91 | 92 | // update currBaseTime 93 | // currBaseTime += this->baseIncrement; 94 | currBaseTime = nextTime + this->baseIncrement; 95 | } 96 | 97 | this->updateNextTrigger(); 98 | } 99 | 100 | TriggerGeneratorLineTopo::TriggerGeneratorLineTopo():TriggerGenerator::TriggerGenerator(8876, syndbConfig.numTriggersPerSwitchType){ 101 | // 8876: 4 x 2219. 2219 is one-hop delay for 1500B pkt on a 10G link 102 | 103 | sim_time_t halfSimTimeIncrement = syndbSim.timeIncrement / 2; 104 | sim_time_t currBaseTime = this->initialDelay + this->baseIncrement; 105 | sim_time_t nextTime, randomExtraTime; 106 | switch_id_t nextSwitch; 107 | 108 | for(int i=0; i < this->totalTriggers; i++){ 109 | 110 | triggerScheduleInfo newScheduleInfo; 111 | 112 | nextSwitch = 4; // hard-coded last switch 113 | randomExtraTime = this->getRandomExtraTime(); 114 | nextTime = currBaseTime + randomExtraTime; 115 | // round nextTime to nearest simulator increment 116 | nextTime = ((nextTime + halfSimTimeIncrement) / syndbSim.timeIncrement) * syndbSim.timeIncrement; 117 | 118 | newScheduleInfo.time = nextTime; 119 | newScheduleInfo.switchId = nextSwitch; 120 | 121 | this->triggerSchedule.push_back(newScheduleInfo); 122 | 123 | // update currBaseTime 124 | // currBaseTime += this->baseIncrement; 125 | currBaseTime = nextTime + this->baseIncrement; 126 | } 127 | 128 | this->updateNextTrigger(); 129 | 130 | } 131 | 132 | 133 | void TriggerGenerator::printTriggerSchedule(){ 134 | ndebug_print_yellow("Trigger Schedule: {} total triggers", this->triggerSchedule.size()); 135 | 136 | auto it = this->triggerSchedule.begin(); 137 | 138 | for(it; it != this->triggerSchedule.end(); it++){ 139 | debug_print("{} {}", it->time, it->switchId); 140 | } 141 | 142 | } 143 | 144 | /* 145 | Constructs the trigger schedule for FatTree topo. Then calls updateNextTrigger() so that nextTriggerTime and nextSwitchId are initialized. 146 | */ 147 | TriggerGeneratorFatTreeTopo::TriggerGeneratorFatTreeTopo():TriggerGenerator::TriggerGenerator(4024, 3 * syndbConfig.numTriggersPerSwitchType){ 148 | 149 | std::shared_ptr fatTreeTopo = std::dynamic_pointer_cast(syndbSim.topo); 150 | 151 | std::vector coreSwitches(fatTreeTopo->switchTypeIDMap[SwitchType::FtCore].begin(),fatTreeTopo->switchTypeIDMap[SwitchType::FtCore].end()); 152 | std::vector aggrSwitches(fatTreeTopo->switchTypeIDMap[SwitchType::FtAggr].begin(),fatTreeTopo->switchTypeIDMap[SwitchType::FtAggr].end()); 153 | std::vector torSwitches(fatTreeTopo->switchTypeIDMap[SwitchType::FtTor].begin(),fatTreeTopo->switchTypeIDMap[SwitchType::FtTor].end()); 154 | 155 | // debug_print_yellow("Initialized vectors of switchID"); 156 | // debug_print("Total switches: {} core, {} aggr, {} tor", coreSwitches.size(), aggrSwitches.size(), torSwitches.size()); 157 | 158 | sim_time_t halfSimTimeIncrement = syndbSim.timeIncrement / 2; 159 | sim_time_t currBaseTime = this->initialDelay + this->baseIncrement; 160 | sim_time_t nextTime, randomExtraTime; 161 | switch_id_t nextSwitch; 162 | 163 | uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 164 | std::default_random_engine generator(seed); 165 | std::uniform_int_distribution torSelectDist(0, torSwitches.size()-1); 166 | std::uniform_int_distribution aggrSelectDist(0, aggrSwitches.size()-1); 167 | std::uniform_int_distribution coreSelectDist(0, coreSwitches.size()-1); 168 | 169 | auto getRandomTorSwitchIdx = std::bind(torSelectDist, generator); 170 | auto getRandomAggrSwitchIdx = std::bind(aggrSelectDist, generator); 171 | auto getRandomCoreSwitchIdx = std::bind(coreSelectDist, generator); 172 | 173 | std::vector nextSwitchIds; 174 | 175 | for(int i=0; i < syndbConfig.numTriggersPerSwitchType; i++) 176 | nextSwitchIds.push_back(torSwitches[getRandomTorSwitchIdx()]); 177 | 178 | for(int i=0; i < syndbConfig.numTriggersPerSwitchType; i++) 179 | nextSwitchIds.push_back(aggrSwitches[getRandomAggrSwitchIdx()]); 180 | 181 | for(int i=0; i < syndbConfig.numTriggersPerSwitchType; i++) 182 | nextSwitchIds.push_back(coreSwitches[getRandomCoreSwitchIdx()]); 183 | 184 | std::random_shuffle(nextSwitchIds.begin(), nextSwitchIds.end()); 185 | 186 | for(int i=0; i < nextSwitchIds.size(); i++){ 187 | 188 | triggerScheduleInfo newScheduleInfo; 189 | 190 | nextSwitch = nextSwitchIds[i]; 191 | randomExtraTime = this->getRandomExtraTime(); 192 | nextTime = currBaseTime + randomExtraTime; 193 | // round nextTime to nearest simulator increment 194 | nextTime = ((nextTime + halfSimTimeIncrement) / syndbSim.timeIncrement) * syndbSim.timeIncrement; 195 | 196 | newScheduleInfo.time = nextTime; 197 | newScheduleInfo.switchId = nextSwitch; 198 | 199 | this->triggerSchedule.push_back(newScheduleInfo); 200 | 201 | // update currBaseTime 202 | // currBaseTime += this->baseIncrement; 203 | currBaseTime = nextTime + this->baseIncrement; 204 | } 205 | 206 | this->updateNextTrigger(); 207 | 208 | } 209 | -------------------------------------------------------------------------------- /traffic/triggerGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRIGGERGENERATOR_H 2 | #define TRIGGERGENERATOR_H 3 | 4 | #include 5 | #include "utils/types.hpp" 6 | #include "simulation/config.hpp" 7 | 8 | struct triggerInfo { 9 | sim_time_t triggerOrigTime; 10 | switch_id_t originSwitch; 11 | std::map rxSwitchTimes; 12 | }; 13 | 14 | struct triggerScheduleInfo{ 15 | sim_time_t time; 16 | switch_id_t switchId; 17 | }; 18 | 19 | struct TriggerGenerator 20 | { 21 | std::list triggerSchedule; 22 | const sim_time_t initialDelay = syndbConfig.triggerInitialDelay; // 10us - for both topologies 23 | sim_time_t baseIncrement; // set to topology's switchToSwitchOWD 24 | uint16_t totalTriggers; 25 | sim_time_t totalExtraTime; 26 | std::function getRandomExtraTime; 27 | 28 | sim_time_t nextTriggerTime; 29 | switch_id_t nextSwitchId; 30 | 31 | TriggerGenerator(sim_time_t switchToSwitchOWD, uint16_t totalTriggers); 32 | void generateTrigger(); 33 | void updateNextTrigger(); 34 | void printTriggerSchedule(); 35 | }; 36 | 37 | 38 | struct TriggerGeneratorSimpleTopo: TriggerGenerator 39 | { 40 | TriggerGeneratorSimpleTopo(); 41 | }; 42 | 43 | struct TriggerGeneratorLineTopo: TriggerGenerator 44 | { 45 | TriggerGeneratorLineTopo(); 46 | }; 47 | 48 | 49 | struct TriggerGeneratorFatTreeTopo : TriggerGenerator 50 | { 51 | TriggerGeneratorFatTreeTopo(); 52 | }; 53 | 54 | 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /utils/logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "utils/logger.hpp" 5 | 6 | -------------------------------------------------------------------------------- /utils/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "simulation/simulation.hpp" 9 | 10 | 11 | 12 | template 13 | void debug_print(const std::string &format, const Args&... args){ 14 | #ifdef DEBUG 15 | fmt::print(format, args...); 16 | std::putc('\n', stdout); 17 | #endif 18 | } 19 | 20 | template 21 | void debug_print_yellow(const std::string &format, const Args&... args){ 22 | #ifdef DEBUG 23 | std::string msg = fmt::format(format, args...); 24 | fmt::print(fg(fmt::color::yellow), msg); 25 | std::putc('\n', stdout); 26 | #endif 27 | } 28 | 29 | template 30 | void ndebug_print(const std::string &format, const Args&... args){ 31 | 32 | std::string msg = fmt::format(format, args...); 33 | 34 | #if LOGGING 35 | syndbSim.pktDumper->logSimSummary(msg); 36 | #endif 37 | 38 | fmt::print(msg); 39 | std::putc('\n', stdout); 40 | } 41 | 42 | template 43 | void ndebug_print_yellow(const std::string &format, const Args&... args){ 44 | 45 | std::string msg = fmt::format(format, args...); 46 | 47 | #if LOGGING 48 | syndbSim.pktDumper->logSimSummary(msg); 49 | #endif 50 | 51 | fmt::print(fg(fmt::color::yellow), msg); 52 | std::putc('\n', stdout); 53 | } 54 | 55 | 56 | 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /utils/memusage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # memusg -- Measure memory usage of processes 3 | # Usage: memusg COMMAND [ARGS]... 4 | # 5 | # Author: Jaeho Shin 6 | # Created: 2010-08-16 7 | ############################################################################ 8 | # Copyright 2010 Jaeho Shin. # 9 | # # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); # 11 | # you may not use this file except in compliance with the License. # 12 | # You may obtain a copy of the License at # 13 | # # 14 | # http://www.apache.org/licenses/LICENSE-2.0 # 15 | # # 16 | # Unless required by applicable law or agreed to in writing, software # 17 | # distributed under the License is distributed on an "AS IS" BASIS, # 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 19 | # See the License for the specific language governing permissions and # 20 | # limitations under the License. # 21 | ############################################################################ 22 | set -um 23 | 24 | # check input 25 | [[ $# -gt 0 ]] || { sed -n '2,/^#$/ s/^# //p' <"$0"; exit 1; } 26 | 27 | # TODO support more options: peak, footprint, sampling rate, etc. 28 | 29 | pgid=$(ps -o pgid= $$) 30 | # make sure we're in a separate process group 31 | if [[ "$pgid" == "$(ps -o pgid= $(ps -o ppid= $$))" ]]; then 32 | cmd= 33 | set -- "$0" "$@" 34 | for a; do cmd+="'${a//"'"/"'\\''"}' "; done 35 | exec bash -i -c "$cmd" 36 | fi 37 | 38 | # detect operating system and prepare measurement 39 | case $(uname) in 40 | Darwin|*BSD) sizes() { /bin/ps -o rss= -g $1; } ;; 41 | Linux) sizes() { /bin/ps -o rss= -$1; } ;; 42 | *) echo "$(uname): unsupported operating system" >&2; exit 2 ;; 43 | esac 44 | 45 | # monitor the memory usage in the background. 46 | ( 47 | peak=0 48 | while sizes=$(sizes $pgid) 49 | do 50 | set -- $sizes 51 | sample=$((${@/#/+})) 52 | let peak="sample > peak ? sample : peak" 53 | sleep 0.1 54 | done 55 | echo "memusg: peak=$peak" >&2 56 | ) & 57 | monpid=$! 58 | 59 | 60 | # run the given command 61 | exec "$@" 62 | -------------------------------------------------------------------------------- /utils/pktdumper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "utils/pktdumper.hpp" 6 | #include "utils/logger.hpp" 7 | #include "traffic/triggerGenerator.hpp" 8 | #include 9 | #include 10 | 11 | 12 | 13 | void PktDumper::openFiles(switch_id_t numberOfSwitches, host_id_t numberOfHosts) { 14 | // create date-time string to use in the prefix string 15 | std::time_t currentTime = std::time(nullptr); 16 | std::string dateTimeString = fmt::format("{:%Y-%m-%d}_{:%H.%M.%S}", fmt::localtime(currentTime), fmt::localtime(currentTime)); 17 | 18 | // clear stpdlog default pattern 19 | debug_print("Clearing default spdlog dump pattern."); 20 | spdlog::set_pattern("%v"); 21 | spdlog::init_thread_pool(QUEUE_SIZE, 1); 22 | 23 | 24 | this->prefixStringForFileName = "dump_" + dateTimeString + "_"; 25 | 26 | std::string simSummaryFileName = "./data/" + prefixStringForFileName + "summary.txt"; 27 | this->simSummaryFilePointer = spdlog::basic_logger_mt("summary", simSummaryFileName); 28 | 29 | // open all file pointers in write/output mode 30 | std::string triggerFileName = "./data/" + prefixStringForFileName + "trigger.txt"; 31 | this->triggerFilePointer = spdlog::basic_logger_mt("trigger", triggerFileName); 32 | 33 | std::string incastFileName = "./data/" + prefixStringForFileName + "incast.txt"; 34 | this->incastFilePointer = spdlog::basic_logger_mt("incast", incastFileName); 35 | 36 | std::string sourceDestinationFile = "./data/" + prefixStringForFileName + "sourceDestination.txt"; 37 | this->sourceDestinationFilePointer = spdlog::basic_logger_mt("sourceDestination", sourceDestinationFile); 38 | 39 | debug_print("Number of Switches: {}", numberOfSwitches); 40 | for (int i = 0; i < numberOfSwitches; i++) { 41 | std::string fileName = "./data/"+ prefixStringForFileName + "switch_" + std::to_string(i) + ".txt"; 42 | auto file = spdlog::basic_logger_mt("switch_" + std::to_string(i), fileName); 43 | this->switchFilePointers.push_back(std::move(file)); 44 | } 45 | 46 | debug_print("Number of Hosts: {}", numberOfHosts); 47 | 48 | ndebug_print("PktDump file prefix: {}", this->prefixStringForFileName); 49 | } 50 | 51 | 52 | PktDumper::~PktDumper() { 53 | // close all file pointers 54 | // this->triggerFilePointer.close(); 55 | // this->sourceDestinationFilePointer.close(); 56 | 57 | // for (int i = 0; i < this->switchFilePointers.size(); i++) { 58 | // this->switchFilePointers[i].close(); 59 | // } 60 | // spdlog::shutdown(); 61 | } 62 | 63 | 64 | void PktDumper::dumpPacket(const normalpkt_p pkt){ 65 | 66 | debug_print_yellow("-------- HOSTS ----------"); 67 | debug_print("Start Time: {}", pkt->startTime); 68 | debug_print("End Time: {}", pkt->endTime); 69 | this->sourceDestinationFilePointer->info("{}\t{}\t{}", pkt->id, pkt->srcHost, pkt->dstHost); 70 | 71 | debug_print_yellow("------- SWITCHES ---------"); 72 | std::list::iterator switchTimeStampsIterator; 73 | for (switchTimeStampsIterator = pkt->switchINTInfoList.begin(); switchTimeStampsIterator != pkt->switchINTInfoList.end(); switchTimeStampsIterator++) { 74 | this->switchFilePointers[switchTimeStampsIterator->swId]->info("{}\t{}", switchTimeStampsIterator->rxTime, pkt->id); 75 | } 76 | 77 | } 78 | 79 | 80 | void PktDumper::dumpTriggerInfo(const trigger_id_t &triggerId, triggerInfo &tinfo, const SwitchType &switchType){ 81 | 82 | std::string stringForTriggerFile = std::to_string(triggerId) + "\t" + std::to_string(tinfo.triggerOrigTime) + "\t" + std::to_string(tinfo.originSwitch); 83 | 84 | std::map::iterator rxSwitchTimesIterator = tinfo.rxSwitchTimes.begin(); 85 | for (; rxSwitchTimesIterator != tinfo.rxSwitchTimes.end(); rxSwitchTimesIterator++) { 86 | stringForTriggerFile += "\t" + std::to_string(rxSwitchTimesIterator->first) + "\t" + std::to_string(rxSwitchTimesIterator->second); 87 | } 88 | 89 | this->triggerFilePointer->info("{}", stringForTriggerFile); 90 | } 91 | 92 | void PktDumper::dumpIncastInfo(const incastScheduleInfo &incastInfo){ 93 | this->incastFilePointer->info("{}\t{}", incastInfo.time, incastInfo.targetHostId); 94 | } 95 | 96 | void PktDumper::logSimSummary(const std::string &msg){ 97 | // this->simSummaryFilePointer->info("{}",msg); 98 | this->simSummaryFilePointer->info("{}", msg); 99 | } 100 | -------------------------------------------------------------------------------- /utils/pktdumper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PACKETDUMPER_H 2 | #define PACKETDUMPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "traffic/packet.hpp" 11 | #include "traffic/incastGenerator.hpp" 12 | #include "traffic/triggerGenerator.hpp" 13 | #include "topology/switch.hpp" 14 | #include 15 | #include 16 | 17 | 18 | // need to declare logger.hpp first because of conflict in fmt 19 | #include 20 | #include 21 | #include 22 | 23 | #define QUEUE_SIZE 32768 * 2 24 | typedef struct PktDumper 25 | { 26 | std::string prefixStringForFileName; 27 | 28 | std::shared_ptr triggerFilePointer, sourceDestinationFilePointer, incastFilePointer, simSummaryFilePointer; 29 | std::vector> switchFilePointers; 30 | 31 | ~PktDumper(); 32 | PktDumper() = default; 33 | 34 | void openFiles(switch_id_t numberOfSwitches, host_id_t numberOfHosts); 35 | void dumpPacket(const normalpkt_p pkt); 36 | void dumpTriggerInfo(const trigger_id_t &triggerId, triggerInfo &tinfo, const SwitchType &switchType); 37 | void dumpIncastInfo(const incastScheduleInfo &incastInfo); 38 | void logSimSummary(const std::string &msg); 39 | 40 | } PktDumper; 41 | 42 | 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /utils/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | /* Simulation Related Types */ 8 | typedef uint64_t sim_time_t; 9 | 10 | /* Packet related types */ 11 | typedef uint16_t pkt_size_t; 12 | typedef uint64_t pkt_id_t; 13 | 14 | /* Host related types */ 15 | typedef uint16_t host_id_t; 16 | 17 | /* Switch related types */ 18 | typedef uint16_t switch_id_t; 19 | 20 | /* Link Related Types */ 21 | typedef uint8_t link_speed_gbps_t; 22 | typedef uint32_t link_id_t; 23 | typedef uint64_t byte_count_t; 24 | 25 | /* TrafficGen Related Types */ 26 | typedef uint8_t load_t; 27 | 28 | /* SyNDB Related Types */ 29 | typedef uint16_t trigger_id_t; 30 | typedef int32_t ringbuffer_index_t; 31 | 32 | /* Fat Tree Related Types */ 33 | typedef uint8_t pod_id_t; 34 | typedef uint8_t ft_scale_t; 35 | typedef uint8_t racklocal_host_id_t; 36 | 37 | 38 | typedef union { 39 | switch_id_t switch_id; 40 | host_id_t host_id; 41 | } next_hop_id; 42 | 43 | enum class syndb_status_t {success, failure}; 44 | 45 | enum class TopologyType {Simple, FatTree, Line}; 46 | enum class TrafficPatternType {SimpleTopo, AlltoAll, FtUniform, FtMixed}; 47 | enum class TrafficGenType {Continuous, Distribution}; 48 | enum class TrafficDstType {IntraRack, InterRack}; 49 | 50 | inline std::string trafficPatternTypeToString(TrafficPatternType type){ 51 | switch(type){ 52 | case TrafficPatternType::SimpleTopo: 53 | return "SimpleTopo"; 54 | break; 55 | case TrafficPatternType::AlltoAll: 56 | return "AlltoAll"; 57 | break; 58 | case TrafficPatternType::FtUniform: 59 | return "FtUniform"; 60 | break; 61 | case TrafficPatternType::FtMixed: 62 | return "FtMixed"; 63 | break; 64 | default: 65 | std::string msg = fmt::format("Unknown TrafficPatternType {}", type); 66 | throw std::logic_error(msg); 67 | break; 68 | } 69 | } 70 | 71 | inline std::string trafficGenTypeToString(TrafficGenType type){ 72 | switch(type){ 73 | case TrafficGenType::Continuous: 74 | return "Continuous"; 75 | break; 76 | case TrafficGenType::Distribution: 77 | return "Distribution"; 78 | break; 79 | default: 80 | std::string msg = fmt::format("Unknown TrafficGenType {}", type); 81 | throw std::logic_error(msg); 82 | } 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /utils/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "utils/types.hpp" 5 | 6 | inline sim_time_t getSerializationDelay(pkt_size_t pktSize, link_speed_gbps_t linkSpeed){ 7 | pkt_size_t size_on_wire = pktSize + 24; 8 | return ((size_on_wire * 8) / linkSpeed); 9 | } 10 | 11 | 12 | #endif 13 | --------------------------------------------------------------------------------