├── .gitattributes ├── .gitignore ├── LICENSE ├── MQSim.exe ├── MQSim.sln ├── MQSim.vcxproj ├── MQSim.vcxproj.filters ├── Makefile ├── README.md ├── README.txt ├── config.txt ├── examples ├── real world workloads │ ├── config.txt │ ├── ssdconfig.xml │ └── workload.xml └── synthetic workloads │ ├── config.txt │ ├── ssdconfig.xml │ └── workload.xml ├── flush_interval(us).txt ├── free_block_log.txt ├── src ├── cxl │ ├── CFLRU.cpp │ ├── CFLRU.h │ ├── CXL_Config.cpp │ ├── CXL_Config.h │ ├── CXL_MSHR.cpp │ ├── CXL_MSHR.h │ ├── CXL_PCIe.cpp │ ├── CXL_PCIe.h │ ├── DRAM_Model.cpp │ ├── DRAM_Model.h │ ├── DRAM_Subsystem.cpp │ ├── DRAM_Subsystem.h │ ├── Host_Interface_CXL.cpp │ ├── Host_Interface_CXL.h │ ├── OutputLog.cpp │ ├── OutputLog.h │ ├── Prefetching_Alg.cpp │ ├── Prefetching_Alg.h │ ├── lrfu_heap.cpp │ └── lrfu_heap.h ├── exec │ ├── Device_Parameter_Set.cpp │ ├── Device_Parameter_Set.h │ ├── Execution_Parameter_Set.cpp │ ├── Execution_Parameter_Set.h │ ├── Flash_Parameter_Set.cpp │ ├── Flash_Parameter_Set.h │ ├── Host_Parameter_Set.cpp │ ├── Host_Parameter_Set.h │ ├── Host_System.cpp │ ├── Host_System.h │ ├── IO_Flow_Parameter_Set.cpp │ ├── IO_Flow_Parameter_Set.h │ ├── Parameter_Set_Base.h │ ├── SSD_Device.cpp │ └── SSD_Device.h ├── host │ ├── ASCII_Trace_Definition.h │ ├── Host_Defs.h │ ├── Host_IO_Request.h │ ├── IO_Flow_Base.cpp │ ├── IO_Flow_Base.h │ ├── IO_Flow_Synthetic.cpp │ ├── IO_Flow_Synthetic.h │ ├── IO_Flow_Trace_Based.cpp │ ├── IO_Flow_Trace_Based.h │ ├── PCIe_Link.cpp │ ├── PCIe_Link.h │ ├── PCIe_Message.h │ ├── PCIe_Root_Complex.cpp │ ├── PCIe_Root_Complex.h │ ├── PCIe_Switch.cpp │ ├── PCIe_Switch.h │ ├── SATA_HBA.cpp │ └── SATA_HBA.h ├── main.cpp ├── nvm_chip │ ├── NVM_Chip.h │ ├── NVM_Memory_Address.h │ ├── NVM_Types.h │ └── flash_memory │ │ ├── Block.cpp │ │ ├── Block.h │ │ ├── Die.cpp │ │ ├── Die.h │ │ ├── FlashTypes.h │ │ ├── Flash_Chip.cpp │ │ ├── Flash_Chip.h │ │ ├── Flash_Command.h │ │ ├── Page.h │ │ ├── Physical_Page_Address.cpp │ │ ├── Physical_Page_Address.h │ │ ├── Plane.cpp │ │ ├── Plane.h │ │ └── SubPage.h ├── sim │ ├── Engine.cpp │ ├── Engine.h │ ├── EventTree.cpp │ ├── EventTree.h │ ├── Sim_Defs.h │ ├── Sim_Event.h │ ├── Sim_Object.h │ └── Sim_Reporter.h ├── ssd │ ├── Address_Mapping_Unit_Base.cpp │ ├── Address_Mapping_Unit_Base.h │ ├── Address_Mapping_Unit_Hybrid.cpp │ ├── Address_Mapping_Unit_Hybrid.h │ ├── Address_Mapping_Unit_Page_Level.cpp │ ├── Address_Mapping_Unit_Page_Level.h │ ├── Data_Cache_Flash.cpp │ ├── Data_Cache_Flash.h │ ├── Data_Cache_Manager_Base.cpp │ ├── Data_Cache_Manager_Base.h │ ├── Data_Cache_Manager_Flash_Advanced.cpp │ ├── Data_Cache_Manager_Flash_Advanced.h │ ├── Data_Cache_Manager_Flash_Simple.cpp │ ├── Data_Cache_Manager_Flash_Simple.h │ ├── FTL.cpp │ ├── FTL.h │ ├── Flash_Block_Manager.cpp │ ├── Flash_Block_Manager.h │ ├── Flash_Block_Manager_Base.cpp │ ├── Flash_Block_Manager_Base.h │ ├── Flash_Transaction_Queue.cpp │ ├── Flash_Transaction_Queue.h │ ├── GC_and_WL_Unit_Base.cpp │ ├── GC_and_WL_Unit_Base.h │ ├── GC_and_WL_Unit_Page_Level.cpp │ ├── GC_and_WL_Unit_Page_Level.h │ ├── Host_Interface_Base.cpp │ ├── Host_Interface_Base.h │ ├── Host_Interface_Defs.h │ ├── Host_Interface_NVMe.cpp │ ├── Host_Interface_NVMe.h │ ├── Host_Interface_SATA.cpp │ ├── Host_Interface_SATA.h │ ├── NVM_Channel_Base.h │ ├── NVM_Firmware.cpp │ ├── NVM_Firmware.h │ ├── NVM_PHY_Base.cpp │ ├── NVM_PHY_Base.h │ ├── NVM_PHY_ONFI.cpp │ ├── NVM_PHY_ONFI.h │ ├── NVM_PHY_ONFI_NVDDR2.cpp │ ├── NVM_PHY_ONFI_NVDDR2.h │ ├── NVM_Transaction.h │ ├── NVM_Transaction_Flash.cpp │ ├── NVM_Transaction_Flash.h │ ├── NVM_Transaction_Flash_ER.cpp │ ├── NVM_Transaction_Flash_ER.h │ ├── NVM_Transaction_Flash_RD.cpp │ ├── NVM_Transaction_Flash_RD.h │ ├── NVM_Transaction_Flash_WR.cpp │ ├── NVM_Transaction_Flash_WR.h │ ├── ONFI_Channel_Base.cpp │ ├── ONFI_Channel_Base.h │ ├── ONFI_Channel_NVDDR2.cpp │ ├── ONFI_Channel_NVDDR2.h │ ├── Queue_Probe.cpp │ ├── Queue_Probe.h │ ├── SSD_Defs.h │ ├── Stats.cpp │ ├── Stats.h │ ├── TSU_Base.cpp │ ├── TSU_Base.h │ ├── TSU_FLIN.cpp │ ├── TSU_FLIN.h │ ├── TSU_OutofOrder.cpp │ ├── TSU_OutofOrder.h │ ├── User_Request.cpp │ └── User_Request.h └── utils │ ├── CMRRandomGenerator.cpp │ ├── CMRRandomGenerator.h │ ├── DistributionTypes.h │ ├── Helper_Functions.cpp │ ├── Helper_Functions.h │ ├── Logical_Address_Partitioning_Unit.cpp │ ├── Logical_Address_Partitioning_Unit.h │ ├── RandomGenerator.cpp │ ├── RandomGenerator.h │ ├── StringTools.cpp │ ├── StringTools.h │ ├── Workload_Statistics.h │ ├── XMLWriter.cpp │ ├── XMLWriter.h │ └── rapidxml │ ├── license.txt │ ├── manual.html │ ├── rapidxml.hpp │ ├── rapidxml_iterators.hpp │ ├── rapidxml_print.hpp │ └── rapidxml_utils.hpp ├── ssdconfig.xml ├── workload.IO_Flow.No_0.log_read ├── workload.IO_Flow.No_0.log_write ├── workload.xml ├── workload_scenario_1.xml ├── workload_settings ├── workload_for_synthetic.xml └── workload_for_trace.xml └── workload_syntheic.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Modified by Shao-Peng Yang at Syracuse University 2 | Copyright (c) 2018, SAFARI Research Group at ETH Zurich University 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /MQSim.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spypaul/MQSim_CXL/357ed7bde9c780c75418122c2a87a9f5c12cf61d/MQSim.exe -------------------------------------------------------------------------------- /MQSim.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MQSim", "MQSim.vcxproj", "{DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Debug|x64.ActiveCfg = Debug|x64 17 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Debug|x64.Build.0 = Debug|x64 18 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Debug|x86.ActiveCfg = Debug|Win32 19 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Debug|x86.Build.0 = Debug|Win32 20 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Release|x64.ActiveCfg = Release|x64 21 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Release|x64.Build.0 = Release|x64 22 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Release|x86.ActiveCfg = Release|Win32 23 | {DF6B928B-78A2-4285-BFF8-8136B4AEDB6A}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4EFD6969-CB8A-4935-A2BE-5F95A9E5D0FC} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | LD := g++ 3 | CC_FLAGS := -std=c++11 -O3 -g 4 | 5 | MODULES := exec host nvm_chip nvm_chip/flash_memory sim ssd utils 6 | SRC_DIR := $(addprefix src/,$(MODULES)) src 7 | BUILD_DIR := $(addprefix build/,$(MODULES)) build 8 | 9 | SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp)) 10 | SRC := src/main.cpp $(SRC) 11 | OBJ := $(patsubst src/%.cpp,build/%.o,$(SRC)) 12 | INCLUDES := $(addprefix -I,$(SRC_DIR)) 13 | 14 | vpath %.cpp $(SRC_DIR) 15 | 16 | define make-goal 17 | $1/%.o: %.cpp 18 | $(CC) $(CC_FLAGS) $(INCLUDES) -c $$< -o $$@ 19 | endef 20 | 21 | .PHONY: all checkdirs clean 22 | 23 | all: checkdirs MQSim 24 | 25 | MQSim: $(OBJ) 26 | $(LD) $^ -o $@ 27 | 28 | checkdirs: $(BUILD_DIR) 29 | 30 | $(BUILD_DIR): 31 | mkdir -p $@ 32 | 33 | clean: 34 | rm -rf $(BUILD_DIR) 35 | rm -f MQSim 36 | 37 | $(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir)))) 38 | -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | DRAM_mode 0 2 | Has_cache 1 3 | DRAM_size 67108864 4 | Mix_mode 1 5 | Cache_portion_percentage 100 6 | Has_mshr 1 7 | Cache_placement 16 8 | Cache_policy CFLRU 9 | Prefetcher Best-offset 10 | Total_number_of_requests 20000000 -------------------------------------------------------------------------------- /examples/real world workloads/config.txt: -------------------------------------------------------------------------------- 1 | DRAM_mode 0 2 | Has_cache 1 3 | DRAM_size 67108864 4 | Mix_mode 1 5 | Cache_portion_percentage 100 6 | Has_mshr 1 7 | Cache_placement 16 8 | Cache_policy CFLRU 9 | Prefetcher Best-offset 10 | Total_number_of_requests 20000000 -------------------------------------------------------------------------------- /examples/real world workloads/ssdconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.00000 5 | 4 6 | 400000 7 | false 8 | 1000000 9 | 10 | 11 | 321 12 | false 13 | FLASH 14 | NVME 15 | 65535 16 | 512 17 | ADVANCED 18 | SHARED 19 | 16777216 20 | 8192 21 | 1600 22 | 1 23 | 13 24 | 13 25 | 13 26 | PAGE_LEVEL 27 | true 28 | 268435456 29 | SHARED 30 | PCWD 31 | OUT_OF_ORDER 32 | 0.127 33 | 0.01000 34 | GREEDY 35 | false 36 | true 37 | 0.001000 38 | false 39 | false 40 | 200 41 | 100000 42 | 10000 43 | 20000 44 | 8 45 | 1 46 | 1200 47 | 8 48 | NVDDR2 49 | 50 | SLC 51 | ERASE 52 | 3000 53 | 3000 54 | 3000 55 | 100000 56 | 100000 57 | 100000 58 | 1000000 59 | 10000 60 | 100000 61 | 20000 62 | 1 63 | 4 64 | 512 65 | 512 66 | 16384 67 | 448 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /examples/real world workloads/workload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | TURNED_OFF 7 | 0,1,2,3,4,5,6,7 8 | 0,1,2,3,4,5,6,7 9 | 0 10 | 0,1,2,3 11 | 30 12 | traces/synthetic_stride_p.trace 13 | 100 14 | 1 15 | NANOSECOND 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/synthetic workloads/config.txt: -------------------------------------------------------------------------------- 1 | DRAM_mode 0 2 | Has_cache 1 3 | DRAM_size 8589934592 4 | Mix_mode 1 5 | Cache_portion_percentage 100 6 | Has_mshr 1 7 | Cache_placement 2097152 8 | Cache_policy FIFO 9 | Prefetcher No 10 | Total_number_of_requests 20000000 -------------------------------------------------------------------------------- /examples/synthetic workloads/ssdconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.00000 5 | 4 6 | 400000 7 | false 8 | 1000000 9 | 10 | 11 | 321 12 | false 13 | FLASH 14 | NVME 15 | 65535 16 | 512 17 | ADVANCED 18 | SHARED 19 | 16777216 20 | 8192 21 | 1600 22 | 1 23 | 13 24 | 13 25 | 13 26 | PAGE_LEVEL 27 | true 28 | 268435456 29 | SHARED 30 | PCWD 31 | OUT_OF_ORDER 32 | 0.127 33 | 0.01000 34 | GREEDY 35 | false 36 | true 37 | 0.001000 38 | false 39 | false 40 | 200 41 | 100000 42 | 10000 43 | 20000 44 | 32 45 | 1 46 | 1200 47 | 32 48 | NVDDR2 49 | 50 | SLC 51 | ERASE 52 | 25000 53 | 25000 54 | 25000 55 | 200000 56 | 200000 57 | 200000 58 | 1000000 59 | 10000 60 | 100000 61 | 20000 62 | 1 63 | 4 64 | 32 65 | 512 66 | 16384 67 | 448 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /examples/synthetic workloads/workload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | TURNED_OFF 7 | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 8 | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 9 | 0 10 | 0,1,2,3 11 | 30 12 | traces/synthetic_stride_p.trace 13 | 100 14 | 1 15 | NANOSECOND 16 | 17 | 18 | -------------------------------------------------------------------------------- /free_block_log.txt: -------------------------------------------------------------------------------- 1 | 429041117 3 0 0 0 0 2 | 429041242 3 0 0 0 0 3 | 429041680 3 0 0 0 0 4 | 429044733 3 0 0 0 3 5 | 429045435 3 0 0 0 0 6 | 429045435 3 0 0 0 1 7 | 429049030 3 0 0 0 3 8 | 429049121 4 2 0 0 3 9 | 434468766 3 0 0 0 0 10 | 434468811 4 3 0 0 1 11 | 435775421 3 0 0 0 0 12 | 435777082 4 1 0 0 3 13 | 436588690 3 0 0 0 0 14 | 436594254 4 0 0 0 2 15 | -------------------------------------------------------------------------------- /src/cxl/CFLRU.cpp: -------------------------------------------------------------------------------- 1 | #include "CFLRU.h" 2 | 3 | CFLRU::CFLRU(uint64_t cache_size) { 4 | if (cache_size >= 4096) { 5 | window = 4096; 6 | } 7 | else { 8 | window = cache_size / 2; 9 | } 10 | } 11 | CFLRU::~CFLRU() { 12 | while (head != NULL && head != tail) { 13 | LRUNode* n = head->right; 14 | delete head; 15 | head = n; 16 | } 17 | if (head != NULL) delete head; 18 | m.clear(); 19 | } 20 | 21 | void CFLRU::add(uint64_t pn) { 22 | LRUNode* nnode{ new LRUNode }; 23 | nnode->page_num = pn; 24 | 25 | if (head == NULL) { 26 | head = nnode; 27 | tail = nnode; 28 | m.emplace(pn, nnode); 29 | return; 30 | } 31 | 32 | nnode->right = head; 33 | head->left = nnode; 34 | head = nnode; 35 | 36 | m.emplace(pn, nnode); 37 | } 38 | 39 | uint64_t CFLRU::pop() { 40 | LRUNode* p{ tail }, * target{ NULL }; 41 | uint64_t evict_addr{ 0 }; 42 | 43 | for (auto i = 0; i < window; i++) { 44 | if (!p->dirty) { 45 | target = p; 46 | break; 47 | } 48 | p = p->left; 49 | } 50 | 51 | if (target != NULL && target != tail) { 52 | if (target == head) { 53 | target->right->left = NULL; 54 | head = target->right; 55 | evict_addr = target->page_num; 56 | m.erase(m.find(target->page_num)); 57 | delete target; 58 | return evict_addr; 59 | } 60 | target->left->right = target->right; 61 | target->right->left = target->left; 62 | evict_addr = target->page_num; 63 | m.erase(m.find(target->page_num)); 64 | delete target; 65 | return evict_addr; 66 | } 67 | 68 | target = tail; 69 | tail = target->left; 70 | tail->right = NULL; 71 | 72 | evict_addr = target->page_num; 73 | m.erase(m.find(target->page_num)); 74 | delete target; 75 | 76 | return evict_addr; 77 | } 78 | 79 | void CFLRU::modify(uint64_t pn, bool dirty) { 80 | LRUNode* target{ m.find(pn)->second }; 81 | 82 | if (target != head) { 83 | if (target == tail) { 84 | if (!target->dirty) target->dirty = dirty; 85 | tail = target->left; 86 | tail->right = NULL; 87 | 88 | head->left = target; 89 | target->right = head; 90 | target->left = NULL; 91 | head = target; 92 | return; 93 | } 94 | 95 | head->left = target; 96 | target->left->right = target->right; 97 | target->right->left = target->left; 98 | if (!target->dirty) target->dirty = dirty; 99 | target->right = head; 100 | target->left = NULL; 101 | head = target; 102 | return; 103 | } 104 | 105 | if (!target->dirty) target->dirty = dirty; 106 | return; 107 | } 108 | -------------------------------------------------------------------------------- /src/cxl/CFLRU.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma once 3 | #include 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | class LRUNode { 10 | public: 11 | uint64_t page_num{ 0 }; 12 | bool dirty{ 0 }; 13 | LRUNode* left{ NULL }; 14 | LRUNode* right{ NULL }; 15 | }; 16 | 17 | class CFLRU { 18 | public: 19 | CFLRU() {}; 20 | CFLRU(uint64_t cache_size); 21 | ~CFLRU(); 22 | void add(uint64_t pn); 23 | uint64_t pop(); 24 | void modify(uint64_t pn, bool dirty); 25 | private: 26 | uint64_t window{ 0 }; 27 | LRUNode* head{ NULL }; 28 | LRUNode* tail{ NULL }; 29 | map m; 30 | 31 | 32 | 33 | }; -------------------------------------------------------------------------------- /src/cxl/CXL_Config.cpp: -------------------------------------------------------------------------------- 1 | #include"CXL_Config.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | void cxl_config::readConfigFile() { 9 | 10 | ifstream configfile{ "config.txt" }; 11 | 12 | 13 | while (!configfile.eof()) { 14 | string info; 15 | 16 | configfile >> info; 17 | 18 | if (info == "DRAM_size") { 19 | uint64_t value; 20 | configfile >> dec >> value; 21 | dram_size = value; 22 | } 23 | else if (info == "DRAM_mode") { 24 | uint64_t value; 25 | configfile >> dec >> value; 26 | dram_mode = (bool)value; 27 | } 28 | else if (info == "Has_cache") { 29 | uint64_t value; 30 | configfile >> dec >> value; 31 | has_cache = value; 32 | } 33 | else if (info == "Mix_mode") { 34 | uint64_t value; 35 | configfile >> dec >> value; 36 | mix_mode = static_cast(value); 37 | } 38 | else if (info == "Cache_portion_percentage") { 39 | uint64_t value; 40 | configfile >> dec >> value; 41 | cache_portion_size = dram_size * value / 100; 42 | prefetch_portion_size = dram_size - cache_portion_size; 43 | } 44 | else if (info == "Has_mshr") { 45 | uint64_t value; 46 | configfile >> dec >> value; 47 | has_mshr = static_cast(value); 48 | } 49 | else if (info == "SSD_page_size") { 50 | uint64_t value; 51 | configfile >> dec >> value; 52 | ssd_page_size = value; 53 | } 54 | else if (info == "Cache_policy") { 55 | string policy; 56 | configfile >> policy; 57 | if (policy == "Random") { 58 | cpolicy = cachepolicy::random; 59 | } 60 | else if (policy == "LRU2") { 61 | cpolicy = cachepolicy::lru2; 62 | } 63 | else if (policy == "FIFO") { 64 | cpolicy = cachepolicy::fifo; 65 | } 66 | else if (policy == "LFU") { 67 | cpolicy = cachepolicy::lfu; 68 | } 69 | else if (policy == "LRFU") { 70 | cpolicy = cachepolicy::lrfu; 71 | } 72 | else if (policy == "LRU") { 73 | cpolicy = cachepolicy::lru; 74 | } 75 | else if (policy == "CFLRU") { 76 | cpolicy = cachepolicy::cflru; 77 | } 78 | else if (policy == "CPU") { 79 | cpolicy = cachepolicy::cpu; 80 | } 81 | } 82 | else if (info == "Prefetch_cache_policy") { 83 | string policy; 84 | configfile >> policy; 85 | if (policy == "Random") { 86 | pref_cpolicy = cachepolicy::random; 87 | } 88 | else if (policy == "LRU2") { 89 | pref_cpolicy = cachepolicy::lru2; 90 | } 91 | else if (policy == "LRFU") { 92 | pref_cpolicy = cachepolicy::lrfu; 93 | } 94 | else if (policy == "CPU") { 95 | pref_cpolicy = cachepolicy::cpu; 96 | } 97 | } 98 | else if (info == "LRFU_p_lambda") { 99 | double p, lambda; 100 | configfile >> p >> lambda; 101 | lrfu_p = p; 102 | lrfu_lambda = lambda; 103 | } 104 | else if (info == "Cache_placement") { 105 | uint64_t sa; 106 | configfile >> sa; 107 | set_associativity = sa; 108 | } 109 | else if (info == "Prefetcher") { 110 | string ptype; 111 | configfile >> ptype; 112 | if (ptype == "No") { 113 | prefetch_policy = prefetchertype::no; 114 | } 115 | else if (ptype == "Tagged") { 116 | prefetch_policy = prefetchertype::tagged; 117 | } 118 | else if (ptype == "Best-offset") { 119 | prefetch_policy = prefetchertype::bo; 120 | } 121 | else if (ptype == "STMS") { 122 | prefetch_policy = prefetchertype::stms; 123 | } 124 | else if (ptype == "Leap") { 125 | prefetch_policy = prefetchertype::leap; 126 | } 127 | else if (ptype == "Readahead") { 128 | prefetch_policy = prefetchertype::readahead; 129 | 130 | } 131 | else if (ptype == "Feedback_direct") { 132 | prefetch_policy = prefetchertype::feedback_direct; 133 | 134 | } 135 | 136 | } 137 | else if (info == "Total_number_of_requests") { 138 | uint64_t value{ 0 }; 139 | 140 | configfile >> value; 141 | 142 | total_number_of_requets = value; 143 | } 144 | 145 | } 146 | configfile.close(); 147 | } -------------------------------------------------------------------------------- /src/cxl/CXL_Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | typedef enum class cachepolicy { 8 | random, 9 | lru2, 10 | fifo, 11 | lfu, 12 | lru, 13 | cflru, 14 | lrfu,//not working 15 | cpu//no need of it 16 | }cachepolicy; 17 | 18 | typedef enum class prefetchertype { 19 | no, 20 | tagged, 21 | bo, 22 | stms, 23 | leap, 24 | readahead, 25 | feedback_direct 26 | }prefetchertype; 27 | 28 | 29 | class cxl_config { 30 | public: 31 | uint64_t dram_size; 32 | bool mix_mode{1}; 33 | uint64_t cache_portion_size; 34 | uint64_t prefetch_portion_size; 35 | uint64_t ssd_page_size; 36 | uint64_t logical_sector_size{ 512 }; 37 | cachepolicy cpolicy; 38 | cachepolicy pref_cpolicy; 39 | double lrfu_p; 40 | double lrfu_lambda; 41 | uint64_t set_associativity; 42 | prefetchertype prefetch_policy; 43 | uint64_t total_number_of_requets; 44 | bool has_mshr; 45 | bool has_cache; 46 | bool dram_mode{ 0 }; 47 | uint64_t num_sec{ 8 }; 48 | 49 | cxl_config() { 50 | dram_size = 0; 51 | cache_portion_size = 0; 52 | prefetch_portion_size = 0; 53 | ssd_page_size = 4096; 54 | cpolicy = cachepolicy::random; 55 | pref_cpolicy = cachepolicy::random; 56 | lrfu_p = 2; 57 | lrfu_lambda = 1; 58 | set_associativity = 4; 59 | prefetch_policy = prefetchertype::tagged; 60 | total_number_of_requets = 0; 61 | has_mshr = 1; 62 | has_cache = 1; 63 | }; 64 | 65 | void readConfigFile(); 66 | 67 | }; 68 | 69 | -------------------------------------------------------------------------------- /src/cxl/CXL_MSHR.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include "../ssd/Host_Interface_Defs.h" 9 | 10 | using namespace std; 11 | 12 | class mshr_request { 13 | public: 14 | 15 | uint64_t time{0}; 16 | Submission_Queue_Entry* sqe{NULL}; 17 | 18 | mshr_request(uint64_t t, Submission_Queue_Entry* s) { 19 | time = t; 20 | sqe = s; 21 | }; 22 | ~mshr_request() { 23 | if (sqe) { 24 | delete sqe; 25 | } 26 | } 27 | }; 28 | 29 | class cxl_mshr { 30 | public: 31 | cxl_mshr(); 32 | ~cxl_mshr(); 33 | 34 | bool isInProgress(uint64_t lba); 35 | 36 | void insertRequest(uint64_t lba, uint64_t time, Submission_Queue_Entry* sqe); 37 | bool removeRequest(uint64_t lba, list &readcount, list &writecount, bool& wasfull); 38 | 39 | mshr_request* removeRequestNew(uint64_t lba, list& readcount, list& writecount, bool& wasfull, uint64_t dram_avail, bool serviced_before, bool& completely_removed); 40 | 41 | bool isFull() { return full; } 42 | 43 | uint64_t getSize() { 44 | return max_row_size - row_count; 45 | } 46 | 47 | private: 48 | map*>* mshr; 49 | 50 | uint64_t max_row_size{ 1024 }; 51 | uint64_t max_col_size{ 65 }; 52 | 53 | uint64_t row_count{ 0 }; 54 | uint64_t max_col_count{ 0 }; 55 | bool full{ 0 }; 56 | 57 | }; -------------------------------------------------------------------------------- /src/cxl/CXL_PCIe.h: -------------------------------------------------------------------------------- 1 | #ifndef CXL_PCIE_H 2 | #define CXL_PCIE_H 3 | 4 | #include 5 | #include "../sim/Sim_Defs.h" 6 | #include "../sim/Sim_Object.h" 7 | #include "../sim/Sim_Event.h" 8 | #include"../sim/Engine.h" 9 | #include "../host/Host_IO_Request.h" 10 | #include "../host/IO_Flow_Base.h" 11 | #include "../host/PCIe_Switch.h" 12 | #include "../ssd/Host_Interface_Defs.h" 13 | //#include "Host_Interface_CXL.h" 14 | 15 | //namespace SSD_Components { 16 | // class Host_Interface_CXL; 17 | //} 18 | 19 | 20 | namespace Host_Components { 21 | class PCIe_Switch; 22 | class IO_Flow_Base; 23 | class CXL_PCIe :public MQSimEngine::Sim_Object { 24 | public: 25 | CXL_PCIe(const sim_object_id_type& id); 26 | 27 | void Deliver(PCIe_Message* message); 28 | void Start_simulation(); 29 | void Validate_simulation_config(); 30 | void Execute_simulator_event(MQSimEngine::Sim_Event* event); 31 | void Set_pcie_switch(PCIe_Switch* pcie_switch); 32 | void Set_io_flow(IO_Flow_Base* iof) { io_flow = iof; } 33 | 34 | bool device_avail() { 35 | return (requests_queue.size() < device_request_queue_max_size); 36 | } 37 | void Request_completed() { 38 | if (request_count >= device_request_queue_max_size) { 39 | Simulator->Register_sim_event(Simulator->Time(), (MQSimEngine::Sim_Object*)io_flow, 0,0); 40 | } 41 | //request_count--; 42 | } 43 | 44 | void MSHR_full(); 45 | void MSHR_not_full(); 46 | 47 | void mark_dram_full(); 48 | 49 | void mark_dram_free(); 50 | 51 | void mark_flash_full(); 52 | 53 | void mark_flash_free(); 54 | 55 | std::list requests_queue; 56 | 57 | uint64_t skipped_trace_reading{ 0 }; 58 | 59 | private: 60 | PCIe_Switch* pcie_switch{NULL}; 61 | uint64_t returned_request_count{ 0 }; 62 | 63 | uint64_t device_request_queue_max_size{ 32 }; 64 | uint64_t request_count{ 0 }; 65 | bool mshr_full{ 0 }; 66 | IO_Flow_Base* io_flow{ NULL }; 67 | uint64_t skipped_requests{ 0 }; 68 | 69 | uint64_t device_dram_avail{ 1 }; 70 | uint64_t flash_device_avail{ 1 }; 71 | }; 72 | } 73 | 74 | #endif -------------------------------------------------------------------------------- /src/cxl/DRAM_Model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../sim/Sim_Object.h" 7 | #include "../sim/Sim_Reporter.h" 8 | #include "../ssd/User_Request.h" 9 | #include "../ssd/Data_Cache_Manager_Base.h" 10 | #include "../ssd/Host_Interface_Base.h" 11 | #include "OutputLog.h" 12 | 13 | 14 | namespace SSD_Components { 15 | 16 | enum class CXL_DRAM_EVENTS { 17 | CACHE_HIT, 18 | CACHE_MISS, 19 | CACHE_HIT_UNDER_MISS, 20 | PREFETCH_READY, 21 | SLOW_PREFETCH 22 | }; 23 | struct CXL_DRAM_ACCESS { 24 | unsigned int Size_in_bytes{ 0 }; 25 | stream_id_type stream_id{ 0 }; 26 | uint64_t lba{ 0 }; 27 | bool rw{ 1 }; 28 | CXL_DRAM_EVENTS type{ CXL_DRAM_EVENTS::CACHE_HIT }; 29 | sim_time_type initiate_time{0}; 30 | sim_time_type arrive_dram_time{ 0 }; 31 | 32 | CXL_DRAM_ACCESS(unsigned int size, uint64_t addr, bool read, CXL_DRAM_EVENTS t , sim_time_type ti) { 33 | Size_in_bytes = size; 34 | lba = addr; 35 | rw = read; 36 | type = t; 37 | initiate_time = ti; 38 | } 39 | }; 40 | class CXL_DRAM_Model : public MQSimEngine::Sim_Object { 41 | public: 42 | CXL_DRAM_Model(const sim_object_id_type& id, Host_Interface_Base* hosti, 43 | unsigned int dram_row_size, unsigned int dram_data_rate, unsigned int dram_busrt_size 44 | , sim_time_type dram_tRCD, sim_time_type dram_tCL, sim_time_type dram_tRP); 45 | 46 | ~CXL_DRAM_Model(); 47 | 48 | void service_cxl_dram_access(CXL_DRAM_ACCESS* request); 49 | 50 | 51 | void Start_simulation() {}; 52 | 53 | 54 | void Validate_simulation_config() {}; 55 | 56 | void Setup_triggers() {}; 57 | 58 | void attachHostInterface(Host_Interface_Base* hosti); 59 | 60 | void Execute_simulator_event(MQSimEngine::Sim_Event* ev); 61 | 62 | bool dram_is_busy{ 0 }; 63 | 64 | uint64_t getDRAMAvailability(); 65 | 66 | uint64_t cache_miss_count{ 0 }, cache_hum_count{ 0 },cache_hit_count{ 0 }, total_number_of_requests{ 0 }, flash_read_count{ 0 }, number_of_accesses{0}, prefetch_amount{0}; 67 | float perc{ 1 }; 68 | bool results_printed{ 0 }; 69 | 70 | private: 71 | unsigned int dram_row_size{0};//The size of the DRAM rows in bytes 72 | unsigned int dram_data_rate{0};//in MT/s 73 | unsigned int dram_busrt_size{0}; 74 | double dram_burst_transfer_time_ddr{0};//The transfer time of two bursts, changed from sim_time_type to double to increase precision 75 | sim_time_type dram_tRCD{ 0 }, dram_tCL{ 0 }, dram_tRP{0};//DRAM access parameters in nano-seconds 76 | Host_Interface_Base* hi{NULL}; 77 | 78 | std::list* waiting_request_queue; 79 | uint64_t max_wait_queue_size{ 8 }; 80 | 81 | CXL_DRAM_ACCESS* current_access{NULL}; 82 | std::map>* list_of_current_access{ NULL }; 83 | uint64_t num_working_request{ 0 }; 84 | uint64_t num_chan{ 1 }; 85 | 86 | 87 | 88 | }; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /src/cxl/DRAM_Subsystem.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAM_SUBSYSTEM_H 2 | #define DRAM_SUBSYSTEM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "CXL_Config.h" 10 | #include "OutputLog.h" 11 | #include "lrfu_heap.h" 12 | #include "CFLRU.h" 13 | 14 | class lruTwoListClass { 15 | private: 16 | list active; 17 | list inactive; 18 | uint64_t activeBound; 19 | public: 20 | lruTwoListClass() { activeBound = 0; } 21 | 22 | void init(uint64_t numCL); 23 | void add(uint64_t lba); 24 | uint64_t getCandidate(); 25 | uint64_t evictLBA(); 26 | void updateWhenHit(uint64_t lba, bool& falsehit); 27 | void reset(); 28 | }; 29 | 30 | class lfuNode { 31 | public: 32 | uint64_t addr; 33 | uint64_t count; 34 | 35 | lfuNode(uint64_t a) { addr = a; count = 0; } 36 | }; 37 | 38 | class lfuHeap { 39 | public: 40 | 41 | void add(uint64_t addr); 42 | uint64_t top(); 43 | void pop(); 44 | void update(uint64_t addr); 45 | 46 | private: 47 | vector h; 48 | map m; 49 | }; 50 | 51 | 52 | using namespace std; 53 | namespace SSD_Components { 54 | 55 | class dram_subsystem { 56 | public: 57 | dram_subsystem() {}; 58 | dram_subsystem(cxl_config confival); 59 | ~dram_subsystem(); 60 | 61 | void initDRAM(); 62 | bool isCacheHit(uint64_t lba); 63 | 64 | 65 | void process_cache_hit(bool rw, uint64_t lba, bool& falsehit); 66 | //void process_miss_data_ready(bool rw, uint64_t lba, list* flush_lba, uint64_t simtime, set* prefetched_lba); 67 | void process_miss_data_ready_new(bool rw, uint64_t lba, list* flush_lba, uint64_t simtime, set* prefetched_lba, set& taggedAddr, set& prefetch_pollution_tracker, set not_finished); 68 | 69 | bool is_next_evict_candidate(uint64_t lba); 70 | 71 | uint64_t get_cache_index(uint64_t lba); 72 | 73 | uint64_t eviction_count{ 0 }, flush_count{0}; 74 | 75 | private: 76 | cxl_config cpara; 77 | map* dram_mapping{ NULL }; // LBA, cache line index 78 | 79 | 80 | list* freeCL{ NULL }; // aligned by ssd block size 81 | 82 | vector*>* all_freeCL{ NULL }; 83 | 84 | set* cachedlba{ NULL };//for random 85 | //vector*>* all_cachedlba{ NULL }; 86 | vector*>* all_cachedlba{ NULL }; 87 | 88 | vector*>* all_fifocachedlba{ NULL }; 89 | vector* all_cflrucachedlba{ NULL }; 90 | vector* all_lfucachedlba{NULL}; 91 | 92 | lrfuHeap* lrfucachedlba{NULL}; //for lrfu 93 | vector* all_lrfucachedlba{ NULL }; 94 | 95 | lruTwoListClass* lru2cachedlba{NULL}; 96 | vector* all_lru2cachedlba{ NULL }; 97 | 98 | map < uint64_t, uint64_t>* dirtyCL{ NULL }; //cache line index, write count 99 | vector*>* all_dirtyCL{ NULL }; 100 | 101 | //For mix seoeration mode 102 | 103 | map* pref_dram_mapping{ NULL }; 104 | list* pref_freeCL{ NULL }; 105 | 106 | set* pref_cachedlba{ NULL };//for random 107 | lrfuHeap* pref_lrfucachedlba{ NULL }; //for lrfu 108 | lruTwoListClass* pref_lru2cachedlba{ NULL }; 109 | 110 | 111 | map* pref_dirtyCL{ NULL }; 112 | 113 | uint64_t* next_eviction_candidate{ NULL }; 114 | uint64_t* pref_next_eviction_candidate{ NULL }; 115 | 116 | }; 117 | 118 | 119 | } 120 | 121 | 122 | #endif -------------------------------------------------------------------------------- /src/cxl/OutputLog.cpp: -------------------------------------------------------------------------------- 1 | #include "OutputLog.h" 2 | 3 | //outlog outputf{ "output.txt" }; 4 | //outlog evictf{ "evictionlog.txt" }; 5 | ofstream of_overall{ "./Results/overall.txt" }; 6 | 7 | 8 | outlog::outlog(string filename) { 9 | if (!of.is_open()) { 10 | of.open(filename); 11 | } 12 | } 13 | 14 | outlog::~outlog() { 15 | if (of.is_open()) { 16 | of.close(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cxl/OutputLog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | class outlog { 7 | public: 8 | ofstream of; 9 | outlog(string filename); 10 | ~outlog(); 11 | }; 12 | 13 | //extern outlog outputf; 14 | extern outlog evictf; 15 | extern ofstream of_overall; 16 | -------------------------------------------------------------------------------- /src/cxl/Prefetching_Alg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class boClass { 12 | private: 13 | list rrtable; 14 | uint64_t maxtablesize{ 1024 }; 15 | uint64_t maxoffset{ 128 }; 16 | vector offsetscore; 17 | uint64_t badscore{ 3 }; 18 | uint64_t maxround{ 8 }; 19 | uint64_t boprefetchK{ 16 }; 20 | public: 21 | bool prefetch_on{ 0 }; 22 | uint64_t offset{ 0 }; 23 | uint64_t offsetundertest{ 1 }; 24 | uint64_t round{ 0 }; 25 | set olist; 26 | 27 | boClass(); 28 | void bosetvalues(uint64_t hsize, uint64_t maxoff, uint64_t b, uint64_t r); 29 | void addhistory(uint64_t addr); 30 | void incrementscore(uint64_t offset); 31 | void resetscore(); 32 | uint64_t findmax(); 33 | void findoffsets(); 34 | bool validoffset(uint64_t offset); 35 | bool inhistory(uint64_t addr); 36 | bool endround(); 37 | bool endlphase(); 38 | void reset(); 39 | }; 40 | 41 | 42 | class leapClass { 43 | private: 44 | list> hbuffer; 45 | uint64_t maxbuffersize{ 39 }; 46 | //uint64_t windowsize{ maxbuffersize }; 47 | uint64_t splitvalue{ 8 }; 48 | const uint64_t maxprefetchamount{ 16 }; 49 | uint64_t lastprefetchamount{ 0 }; 50 | uint64_t lastprefetchhit{ 0 }; 51 | 52 | uint64_t leapinitialprefetchamount{ 1 }; 53 | public: 54 | int64_t last_offset{ 0 }; 55 | void setvalues(uint64_t bsize, uint64_t svalue); 56 | void leapinit(); 57 | int64_t findoffset(); 58 | void historyinsert(uint64_t addr); 59 | uint64_t getk(uint64_t prefetchHitCount); 60 | void reset(); 61 | }; -------------------------------------------------------------------------------- /src/cxl/lrfu_heap.cpp: -------------------------------------------------------------------------------- 1 | #include "lrfu_heap.h" 2 | 3 | 4 | lrfuHeap::~lrfuHeap() { 5 | while (!Q.empty()) { 6 | bnode* ptr{ Q.back() }; 7 | 8 | Q.pop_back(); 9 | delete ptr; 10 | } 11 | } 12 | 13 | void lrfuHeap::init(double pvalue, double lvalue) { 14 | current_time = 0; 15 | p = pvalue; 16 | lambda = lvalue; 17 | } 18 | 19 | void lrfuHeap::add(bnode* block) { 20 | Q.push_back(block); 21 | uint64_t bindex{ Q.size() - 1 }; 22 | bool violation{ 1 }; 23 | 24 | while (bindex > 0 && violation) { 25 | uint64_t parentindex{ (bindex - 1) / 2 }; 26 | 27 | if (F(current_time - block->last_reference_time) * block->crf < F(current_time - Q[parentindex]->last_reference_time) * Q[parentindex]->crf) { 28 | 29 | swap(Q[bindex], Q[parentindex]); 30 | 31 | M[Q[bindex]->lba] = bindex; 32 | 33 | bindex = parentindex; 34 | 35 | } 36 | else { 37 | violation = 0; 38 | } 39 | 40 | } 41 | M.emplace(block->lba, bindex); 42 | } 43 | uint64_t lrfuHeap::removeRoot() { 44 | bnode* victimn{ Q[0] }; 45 | uint64_t victimlba{ victimn->lba }; 46 | M.erase(Q[0]->lba); 47 | delete victimn; 48 | 49 | if (Q.size() == 1) { 50 | Q.pop_back(); 51 | return victimlba; 52 | } 53 | Q[0] = Q.back(); 54 | Q.pop_back(); 55 | M[Q[0]->lba] = 0; 56 | restore(0); 57 | 58 | return victimlba; 59 | } 60 | uint64_t lrfuHeap::getCandidate() { 61 | bnode* candidate{ Q[0] }; 62 | return candidate->lba; 63 | } 64 | 65 | void lrfuHeap::updateWhenHit(uint64_t lba, bool& falsehit) { 66 | if (!M.count(lba)) { 67 | falsehit = 1; 68 | return; 69 | } 70 | 71 | bnode* n{ Q[M[lba]] }; 72 | n->crf = F(0) + F(getTime() - n->last_reference_time) * n->crf; 73 | n->last_reference_time = getTime(); 74 | restore(M[lba]); 75 | advanceTime(); 76 | } 77 | 78 | void lrfuHeap::restore(uint64_t bindex) { 79 | if ((2 * bindex + 1) >= Q.size()) return; // if the node is a leaf node 80 | 81 | uint64_t lindex{ 2 * bindex + 1 }, rindex{ 2 * bindex + 2 }; 82 | uint64_t smallerindex{ 0 }; 83 | if (lindex < Q.size() && rindex < Q.size()) {//have two child 84 | smallerindex = (F(current_time - Q[lindex]->last_reference_time) * Q[lindex]->crf < F(current_time - Q[rindex]->last_reference_time)* Q[rindex]->crf) ? lindex : rindex; 85 | } 86 | else { 87 | smallerindex = lindex; 88 | } 89 | 90 | if (F(current_time - Q[bindex]->last_reference_time) * Q[bindex]->crf > F(current_time - Q[smallerindex]->last_reference_time) * Q[smallerindex]->crf) { 91 | swap(Q[bindex], Q[smallerindex]); 92 | M[Q[bindex]->lba] = bindex; 93 | bindex = smallerindex; 94 | M[Q[bindex]->lba] = bindex; 95 | restore(bindex); 96 | } 97 | 98 | 99 | } 100 | 101 | 102 | 103 | double lrfuHeap::F(uint64_t timeDiff) { 104 | return pow(1 / p, lambda * static_cast(timeDiff)); 105 | } 106 | 107 | uint64_t lrfuHeap::getTime() { 108 | return current_time; 109 | } 110 | 111 | void lrfuHeap::advanceTime() { 112 | current_time++; 113 | } 114 | 115 | void lrfuHeap::reset() { 116 | M.clear(); 117 | 118 | while (!Q.empty()) { 119 | bnode* ptr{ Q.back() }; 120 | 121 | Q.pop_back(); 122 | delete ptr; 123 | } 124 | Q.clear(); 125 | } -------------------------------------------------------------------------------- /src/cxl/lrfu_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | 7 | struct bnode { 8 | 9 | bnode(double cvalue, uint64_t ltime, uint64_t addr) { crf = cvalue; last_reference_time = ltime; lba = addr; } 10 | 11 | double crf; 12 | uint64_t last_reference_time; 13 | uint64_t lba; 14 | 15 | }; 16 | 17 | class lrfuHeap { 18 | private: 19 | vector Q; 20 | map M; 21 | uint64_t current_time; 22 | double p; 23 | double lambda; 24 | 25 | public: 26 | 27 | lrfuHeap() { current_time = 0; p = 1; lambda = 0; } 28 | ~lrfuHeap(); 29 | 30 | void init(double pvalue, double lvalue); 31 | void add(bnode* block); 32 | uint64_t removeRoot(); 33 | uint64_t getCandidate(); 34 | 35 | void updateWhenHit(uint64_t lba, bool& falsehit); 36 | void restore(uint64_t bindex); 37 | 38 | double F(uint64_t timeDiff); 39 | uint64_t getTime(); 40 | void advanceTime(); 41 | void reset(); 42 | }; -------------------------------------------------------------------------------- /src/exec/Execution_Parameter_Set.cpp: -------------------------------------------------------------------------------- 1 | #include "Execution_Parameter_Set.h" 2 | 3 | 4 | Host_Parameter_Set Execution_Parameter_Set::Host_Configuration; 5 | Device_Parameter_Set Execution_Parameter_Set::SSD_Device_Configuration; 6 | 7 | 8 | void Execution_Parameter_Set::XML_serialize(Utils::XmlWriter& xmlwriter) 9 | { 10 | std::string tmp; 11 | tmp = "Execution_Parameter_Set"; 12 | xmlwriter.Write_open_tag(tmp); 13 | 14 | Host_Configuration.XML_serialize(xmlwriter); 15 | SSD_Device_Configuration.XML_serialize(xmlwriter); 16 | 17 | xmlwriter.Write_close_tag(); 18 | } 19 | 20 | void Execution_Parameter_Set::XML_deserialize(rapidxml::xml_node<> *node) 21 | { 22 | try { 23 | for (auto param = node->first_node(); param; param = param->next_sibling()) { 24 | if (strcmp(param->name(), "Host_Parameter_Set") == 0) { 25 | Host_Configuration.XML_deserialize(param); 26 | } else if (strcmp(param->name(), "Device_Parameter_Set") == 0) { 27 | SSD_Device_Configuration.XML_deserialize(param); 28 | } 29 | } 30 | } catch (...) { 31 | PRINT_ERROR("Error in the Execution_Parameter_Set!") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/exec/Execution_Parameter_Set.h: -------------------------------------------------------------------------------- 1 | #ifndef EXECUTION_PARAMETER_SET_H 2 | #define EXECUTION_PARAMETER_SET_H 3 | 4 | #include 5 | #include "Parameter_Set_Base.h" 6 | #include "Device_Parameter_Set.h" 7 | #include "IO_Flow_Parameter_Set.h" 8 | #include "Host_Parameter_Set.h" 9 | 10 | class Execution_Parameter_Set : public Parameter_Set_Base 11 | { 12 | public: 13 | static Host_Parameter_Set Host_Configuration; 14 | static Device_Parameter_Set SSD_Device_Configuration; 15 | 16 | void XML_serialize(Utils::XmlWriter& xmlwriter); 17 | void XML_deserialize(rapidxml::xml_node<> *node); 18 | }; 19 | 20 | #endif // !EXECUTION_PARAMETER_SET_H 21 | -------------------------------------------------------------------------------- /src/exec/Flash_Parameter_Set.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASH_PARAMETER_SET_H 2 | #define FLASH_PARAMETER_SET_H 3 | 4 | #include "../sim/Sim_Defs.h" 5 | #include "../nvm_chip/flash_memory/FlashTypes.h" 6 | #include "Parameter_Set_Base.h" 7 | 8 | class Flash_Parameter_Set : Parameter_Set_Base 9 | { 10 | public: 11 | static Flash_Technology_Type Flash_Technology; 12 | static NVM::FlashMemory::Command_Suspension_Mode CMD_Suspension_Support; 13 | static sim_time_type Page_Read_Latency_LSB; 14 | static sim_time_type Page_Read_Latency_CSB; 15 | static sim_time_type Page_Read_Latency_MSB; 16 | static sim_time_type Page_Program_Latency_LSB; 17 | static sim_time_type Page_Program_Latency_CSB; 18 | static sim_time_type Page_Program_Latency_MSB; 19 | static sim_time_type Block_Erase_Latency;//Block erase latency in nano-seconds 20 | static unsigned int Block_PE_Cycles_Limit; 21 | static sim_time_type Suspend_Erase_Time;//in nano-seconds 22 | static sim_time_type Suspend_Program_Time;//in nano-seconds 23 | static unsigned int Die_No_Per_Chip; 24 | static unsigned int Plane_No_Per_Die; 25 | static unsigned int Block_No_Per_Plane; 26 | static unsigned int Page_No_Per_Block;//Page no per block 27 | static unsigned int Page_Capacity;//Flash page capacity in bytes 28 | static unsigned int Page_Metadat_Capacity;//Flash page metadata capacity in bytes 29 | void XML_serialize(Utils::XmlWriter& xmlwriter); 30 | void XML_deserialize(rapidxml::xml_node<> *node); 31 | }; 32 | 33 | #endif // !FLASH_PARAMETER_SET_H 34 | -------------------------------------------------------------------------------- /src/exec/Host_Parameter_Set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Host_Parameter_Set.h" 3 | 4 | 5 | double Host_Parameter_Set::PCIe_Lane_Bandwidth = 0.4;//uint is GB/s 6 | unsigned int Host_Parameter_Set::PCIe_Lane_Count = 4; 7 | sim_time_type Host_Parameter_Set::SATA_Processing_Delay;//The overall hardware and software processing delay to send/receive a SATA message in nanoseconds 8 | bool Host_Parameter_Set::Enable_ResponseTime_Logging = false; 9 | sim_time_type Host_Parameter_Set::ResponseTime_Logging_Period_Length = 400000;//nanoseconds 10 | std::string Host_Parameter_Set::Input_file_path; 11 | std::vector Host_Parameter_Set::IO_Flow_Definitions; 12 | 13 | void Host_Parameter_Set::XML_serialize(Utils::XmlWriter& xmlwriter) 14 | { 15 | std::string tmp; 16 | tmp = "Host_Parameter_Set"; 17 | xmlwriter.Write_open_tag(tmp); 18 | 19 | std::string attr = "PCIe_Lane_Bandwidth"; 20 | std::string val = std::to_string(PCIe_Lane_Bandwidth); 21 | xmlwriter.Write_attribute_string(attr, val); 22 | 23 | attr = "PCIe_Lane_Count"; 24 | val = std::to_string(PCIe_Lane_Count); 25 | xmlwriter.Write_attribute_string(attr, val); 26 | 27 | attr = "SATA_Processing_Delay"; 28 | val = std::to_string(SATA_Processing_Delay); 29 | xmlwriter.Write_attribute_string(attr, val); 30 | 31 | attr = "Enable_ResponseTime_Logging"; 32 | val = (Enable_ResponseTime_Logging ? "true" : "false"); 33 | xmlwriter.Write_attribute_string(attr, val); 34 | 35 | attr = "ResponseTime_Logging_Period_Length"; 36 | val = std::to_string(ResponseTime_Logging_Period_Length); 37 | xmlwriter.Write_attribute_string(attr, val); 38 | 39 | xmlwriter.Write_close_tag(); 40 | } 41 | 42 | void Host_Parameter_Set::XML_deserialize(rapidxml::xml_node<> *node) 43 | { 44 | try { 45 | for (auto param = node->first_node(); param; param = param->next_sibling()) { 46 | if (strcmp(param->name(), "PCIe_Lane_Bandwidth") == 0) { 47 | std::string val = param->value(); 48 | PCIe_Lane_Bandwidth = std::stod(val); 49 | } else if (strcmp(param->name(), "PCIe_Lane_Count") == 0) { 50 | std::string val = param->value(); 51 | PCIe_Lane_Count = std::stoul(val); 52 | } else if (strcmp(param->name(), "SATA_Processing_Delay") == 0) { 53 | std::string val = param->value(); 54 | SATA_Processing_Delay = std::stoul(val); 55 | } else if (strcmp(param->name(), "Enable_ResponseTime_Logging") == 0) { 56 | std::string val = param->value(); 57 | std::transform(val.begin(), val.end(), val.begin(), ::toupper); 58 | Enable_ResponseTime_Logging = (val.compare("FALSE") == 0 ? false : true); 59 | } else if (strcmp(param->name(), "ResponseTime_Logging_Period_Length") == 0) { 60 | std::string val = param->value(); 61 | ResponseTime_Logging_Period_Length = std::stoul(val); 62 | } 63 | } 64 | } catch (...) { 65 | PRINT_ERROR("Error in the Host_Parameter_Set!") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/exec/Host_Parameter_Set.h: -------------------------------------------------------------------------------- 1 | #ifndef HOST_PARAMETER_SEt_H 2 | #define HOST_PARAMETER_SEt_H 3 | 4 | #include 5 | #include "Parameter_Set_Base.h" 6 | #include "IO_Flow_Parameter_Set.h" 7 | 8 | class Host_Parameter_Set : public Parameter_Set_Base 9 | { 10 | public: 11 | static double PCIe_Lane_Bandwidth;//uint is GB/s 12 | static unsigned int PCIe_Lane_Count; 13 | static sim_time_type SATA_Processing_Delay;//The overall hardware and software processing delay to send/receive a SATA message in nanoseconds 14 | static bool Enable_ResponseTime_Logging; 15 | static sim_time_type ResponseTime_Logging_Period_Length; 16 | static std::vector IO_Flow_Definitions; 17 | static std::string Input_file_path;//This parameter is not serialized. This is used to inform the Host_System class about the input file path. 18 | 19 | void XML_serialize(Utils::XmlWriter& xmlwriter); 20 | void XML_deserialize(rapidxml::xml_node<> *node); 21 | }; 22 | 23 | #endif // !HOST_PARAMETER_SEt_H 24 | -------------------------------------------------------------------------------- /src/exec/Host_System.h: -------------------------------------------------------------------------------- 1 | #ifndef HOST_SYSTEM_H 2 | #define HOST_SYSTEM_H 3 | 4 | #include 5 | #include "../sim/Sim_Object.h" 6 | #include "../sim/Sim_Reporter.h" 7 | #include "../host/PCIe_Root_Complex.h" 8 | #include "../host/PCIe_Link.h" 9 | #include "../host/PCIe_Switch.h" 10 | #include "../host/PCIe_Message.h" 11 | #include "../host/IO_Flow_Base.h" 12 | #include "../host/Host_IO_Request.h" 13 | #include "../ssd/Host_Interface_Base.h" 14 | #include "Host_Parameter_Set.h" 15 | #include "SSD_Device.h" 16 | #include "../utils/Workload_Statistics.h" 17 | #include "../cxl/CXL_PCIe.h" 18 | 19 | class Host_System : public MQSimEngine::Sim_Object, public MQSimEngine::Sim_Reporter 20 | { 21 | public: 22 | Host_System(Host_Parameter_Set* parameters, bool preconditioning_required, SSD_Components::Host_Interface_Base* ssd_host_interface); 23 | ~Host_System(); 24 | void Start_simulation(); 25 | void Validate_simulation_config(); 26 | void Execute_simulator_event(MQSimEngine::Sim_Event* event); 27 | void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 28 | 29 | void Attach_ssd_device(SSD_Device* ssd_device); 30 | const std::vector Get_io_flows(); 31 | private: 32 | Host_Components::PCIe_Root_Complex* PCIe_root_complex; 33 | Host_Components::PCIe_Link* Link; 34 | Host_Components::PCIe_Switch* PCIe_switch; 35 | Host_Components::SATA_HBA* SATA_hba; 36 | Host_Components::CXL_PCIe* cxl_pcie; 37 | std::vector IO_flows; 38 | SSD_Device* ssd_device; 39 | std::vector get_workloads_statistics(); 40 | bool preconditioning_required; 41 | }; 42 | 43 | #endif // !HOST_SYSTEM_H 44 | -------------------------------------------------------------------------------- /src/exec/IO_Flow_Parameter_Set.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_FLOW_PARAMETER_SET_H 2 | #define IO_FLOW_PARAMETER_SET_H 3 | 4 | #include 5 | #include "../nvm_chip/flash_memory/FlashTypes.h" 6 | #include "../ssd/Host_Interface_Defs.h" 7 | #include "../host/IO_Flow_Synthetic.h" 8 | #include "../host/IO_Flow_Trace_Based.h" 9 | #include "../utils/Workload_Statistics.h" 10 | #include "../utils/DistributionTypes.h" 11 | #include "Parameter_Set_Base.h" 12 | 13 | enum class Flow_Type { SYNTHETIC, TRACE }; 14 | class IO_Flow_Parameter_Set : public Parameter_Set_Base 15 | { 16 | public: 17 | SSD_Components::Caching_Mode Device_Level_Data_Caching_Mode; 18 | Flow_Type Type; 19 | IO_Flow_Priority_Class Priority_Class;//The priority class is only considered when the SSD device uses NVMe host interface 20 | flash_channel_ID_type* Channel_IDs;//Resource partitioning: which channel ids are allocated to this flow 21 | flash_chip_ID_type* Chip_IDs;//Resource partitioning: which chip ids are allocated to this flow 22 | flash_die_ID_type* Die_IDs;//Resource partitioning: which die ids are allocted to this flow 23 | flash_plane_ID_type* Plane_IDs;//Resource partitioning: which plane ids are allocated to this flow 24 | unsigned int Initial_Occupancy_Percentage;//Percentage of the logical space that is written when preconditioning is performed 25 | int Channel_No, Chip_No, Die_No, Plane_No; 26 | unsigned int Relief_Type; // temporal info 27 | void XML_serialize(Utils::XmlWriter& xmlwrite); 28 | void XML_deserialize(rapidxml::xml_node<> *node); 29 | private: 30 | }; 31 | 32 | class IO_Flow_Parameter_Set_Synthetic : public IO_Flow_Parameter_Set 33 | { 34 | public: 35 | IO_Flow_Parameter_Set_Synthetic() { this->Type = Flow_Type::SYNTHETIC; } 36 | unsigned int Working_Set_Percentage;//Percentage of available storage space that is accessed 37 | Utils::Request_Generator_Type Synthetic_Generator_Type; 38 | char Read_Percentage; 39 | Utils::Address_Distribution_Type Address_Distribution; 40 | char Percentage_of_Hot_Region;//This parameters used if the address distribution type is hot/cold (i.e., (100-H)% of the whole I/O requests are going to a H% hot region of the storage space) 41 | bool Generated_Aligned_Addresses; 42 | unsigned int Address_Alignment_Unit; 43 | Utils::Request_Size_Distribution_Type Request_Size_Distribution; 44 | unsigned int Average_Request_Size;//Average request size in sectors 45 | unsigned int Variance_Request_Size;//Variance of request size in sectors 46 | //Host_Components::Request_Generator_Type Generator_Type;//Request generator could be time-based 47 | int Seed; 48 | unsigned int Average_No_of_Reqs_in_Queue;//Average number of I/O requests from this flow in the 49 | unsigned int Bandwidth;//The bandwidth of I/O flow in bytes per second (it should be a multiplication of sector size) 50 | 51 | sim_time_type Stop_Time;//Defines when to stop generating I/O requests 52 | unsigned int Total_Requests_To_Generate;//If Stop_Time is equal to zero, then requst generator considers Total_Requests_To_Generate to decide when to stop generating I/O requests 53 | void XML_serialize(Utils::XmlWriter& xmlwriter); 54 | void XML_deserialize(rapidxml::xml_node<> *node); 55 | }; 56 | 57 | class IO_Flow_Parameter_Set_Trace_Based : public IO_Flow_Parameter_Set 58 | { 59 | public: 60 | IO_Flow_Parameter_Set_Trace_Based() { this->Type = Flow_Type::TRACE; } 61 | std::string File_Path; 62 | int Percentage_To_Be_Executed; 63 | int Relay_Count; 64 | Trace_Time_Unit Time_Unit; 65 | 66 | void XML_serialize(Utils::XmlWriter& xmlwriter); 67 | void XML_deserialize(rapidxml::xml_node<> *node); 68 | }; 69 | 70 | #endif // !IO_FLOW_PARAMETER_SET_H 71 | -------------------------------------------------------------------------------- /src/exec/Parameter_Set_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMETER_SET_BASE_H 2 | #define PARAMETER_SET_BASE_H 3 | 4 | #include "../utils/rapidxml/rapidxml.hpp" 5 | #include "../utils/XMLWriter.h" 6 | 7 | class Parameter_Set_Base 8 | { 9 | public: 10 | virtual void XML_serialize(Utils::XmlWriter& xmlwriter) = 0; 11 | virtual void XML_deserialize(rapidxml::xml_node<> *node) = 0; 12 | }; 13 | 14 | #endif // !PARAMETER_SET_BASE_H -------------------------------------------------------------------------------- /src/exec/SSD_Device.h: -------------------------------------------------------------------------------- 1 | #ifndef SSD_DEVICE_H 2 | #define SSD_DEVICE_H 3 | 4 | #include 5 | #include "../sim/Sim_Object.h" 6 | #include "../sim/Sim_Reporter.h" 7 | #include "../ssd/SSD_Defs.h" 8 | #include "../ssd/Host_Interface_Base.h" 9 | #include "../ssd/Host_Interface_SATA.h" 10 | #include "../ssd/Host_Interface_NVMe.h" 11 | #include "../cxl/DRAM_Model.h" 12 | #include "../cxl/Host_Interface_CXL.h" 13 | #include "../ssd/Data_Cache_Manager_Base.h" 14 | #include "../ssd/Data_Cache_Flash.h" 15 | #include "../ssd/NVM_Firmware.h" 16 | #include "../ssd/NVM_PHY_Base.h" 17 | #include "../ssd/NVM_Channel_Base.h" 18 | #include "../host/PCIe_Switch.h" 19 | #include "../cxl/CXL_PCIe.h" 20 | #include "../nvm_chip/NVM_Types.h" 21 | #include "Device_Parameter_Set.h" 22 | #include "IO_Flow_Parameter_Set.h" 23 | #include "../utils/Workload_Statistics.h" 24 | 25 | 26 | /********************************************************************************************************* 27 | * An SSD device has the following components: 28 | * 29 | * Host_Interface <---> Data_Cache_Manager <----> NVM_Firmware <---> NVM_PHY <---> NVM_Channel <---> Chips 30 | * 31 | *********************************************************************************************************/ 32 | 33 | class SSD_Device : public MQSimEngine::Sim_Object, public MQSimEngine::Sim_Reporter 34 | { 35 | public: 36 | SSD_Device(Device_Parameter_Set* parameters, std::vector* io_flows); 37 | ~SSD_Device(); 38 | bool Preconditioning_required; 39 | NVM::NVM_Type Memory_Type; 40 | SSD_Components::Host_Interface_Base *Host_interface; 41 | SSD_Components::Data_Cache_Manager_Base *Cache_manager; 42 | SSD_Components::NVM_Firmware* Firmware; 43 | SSD_Components::NVM_PHY_Base* PHY; 44 | std::vector Channels; 45 | void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 46 | unsigned int Get_no_of_LHAs_in_an_NVM_write_unit(); 47 | 48 | void Attach_to_host(Host_Components::PCIe_Switch* pcie_switch); 49 | void Perform_preconditioning(std::vector workload_stats); 50 | void Start_simulation(); 51 | void Validate_simulation_config(); 52 | void Execute_simulator_event(MQSimEngine::Sim_Event* event); 53 | static LPA_type Convert_host_logical_address_to_device_address(LHA_type lha); 54 | static page_status_type Find_NVM_subunit_access_bitmap(LHA_type lha); 55 | 56 | unsigned int Channel_count; 57 | unsigned int Chip_no_per_channel; 58 | 59 | 60 | private: 61 | static SSD_Device * my_instance;//Used in static functions 62 | }; 63 | 64 | #endif //!SSD_DEVICE_H 65 | -------------------------------------------------------------------------------- /src/host/ASCII_Trace_Definition.h: -------------------------------------------------------------------------------- 1 | #ifndef ASCII_TRACE_DEFINITION_H 2 | #define ASCII_TRACE_DEFINITION_H 3 | 4 | enum class Trace_Time_Unit { PICOSECOND, NANOSECOND, MICROSECOND};//The unit of arrival times in the input file 5 | #define PicoSecondCoeff 1000000000000 //the coefficient to convert picoseconds to second 6 | #define NanoSecondCoeff 1000000000 //the coefficient to convert nanoseconds to second 7 | #define MicroSecondCoeff 1000000 //the coefficient to convert microseconds to second 8 | 9 | //#define MSR_TRACE 10 | //#define OLD_TRACE 11 | 12 | 13 | /// Default Definition 14 | #if defined(MSR_TRACE) 15 | /// Definition for MSR Trace. 16 | #define ASCIITraceTimeColumn 0 17 | #define ASCIITraceDeviceColumn 2 18 | #define ASCIITraceAddressColumn 4 19 | #define ASCIITraceSizeColumn 5 20 | #define ASCIITraceTypeColumn 3 21 | 22 | #define ASCIITraceWriteCode "Write," 23 | #define ASCIITraceReadCode "Read," 24 | #define ASCIILineDelimiter ',' 25 | #define ASCIIItemsPerLine 7 26 | 27 | #elif defined(OLD_TRACE) 28 | #define ASCIITraceTimeColumn 0 29 | #define ASCIITraceAddressColumn 2 30 | #define ASCIITraceSizeColumn 3 31 | #define ASCIITraceTypeColumn 1 32 | 33 | #define ASCIITraceWriteCode "write " 34 | #define ASCIITraceReadCode "read " 35 | #define ASCIILineDelimiter ' ' 36 | #define ASCIIItemsPerLine 4 37 | 38 | #else 39 | #define ASCIITraceTimeColumn 0 40 | #define ASCIITraceDeviceColumn 1 41 | #define ASCIITraceAddressColumn 2 42 | #define ASCIITraceSizeColumn 3 43 | #define ASCIITraceTypeColumn 4 44 | 45 | #define ASCIITraceWriteCode "0" 46 | #define ASCIITraceReadCode "1" 47 | #define ASCIILineDelimiter ' ' 48 | #define ASCIIItemsPerLine 5 49 | #endif 50 | 51 | 52 | 53 | 54 | #endif // !ASCII_TRACE_DEFINITION_H 55 | -------------------------------------------------------------------------------- /src/host/Host_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef HOST_DEFS_H 2 | #define HOST_DEFS_H 3 | 4 | 5 | #define QUEUE_ID_TO_FLOW_ID(Q) Q - 1 6 | #define FLOW_ID_TO_Q_ID(F) F + 1 7 | #define NVME_COMP_Q_MEMORY_REGION 40 8 | #define DATA_MEMORY_REGION 0xFF0000000000 9 | 10 | const uint64_t SUBMISSION_QUEUE_MEMORY_0 = 0x000000000000; 11 | const uint64_t COMPLETION_QUEUE_MEMORY_0 = 0x00F000000000; 12 | const uint64_t SUBMISSION_QUEUE_MEMORY_1 = 0x010000000000; 13 | const uint64_t COMPLETION_QUEUE_MEMORY_1 = 0x01F000000000; 14 | const uint64_t SUBMISSION_QUEUE_MEMORY_2 = 0x020000000000; 15 | const uint64_t COMPLETION_QUEUE_MEMORY_2 = 0x02F000000000; 16 | const uint64_t SUBMISSION_QUEUE_MEMORY_3 = 0x030000000000; 17 | const uint64_t COMPLETION_QUEUE_MEMORY_3 = 0x03F000000000; 18 | const uint64_t SUBMISSION_QUEUE_MEMORY_4 = 0x040000000000; 19 | const uint64_t COMPLETION_QUEUE_MEMORY_4 = 0x04F000000000; 20 | const uint64_t SUBMISSION_QUEUE_MEMORY_5 = 0x050000000000; 21 | const uint64_t COMPLETION_QUEUE_MEMORY_5 = 0x05F000000000; 22 | const uint64_t SUBMISSION_QUEUE_MEMORY_6 = 0x060000000000; 23 | const uint64_t COMPLETION_QUEUE_MEMORY_6 = 0x06F000000000; 24 | const uint64_t SUBMISSION_QUEUE_MEMORY_7 = 0x070000000000; 25 | const uint64_t COMPLETION_QUEUE_MEMORY_7 = 0x07F000000000; 26 | const uint64_t SUBMISSION_QUEUE_MEMORY_8 = 0x080000000000; 27 | const uint64_t COMPLETION_QUEUE_MEMORY_8 = 0x08F000000000; 28 | 29 | #endif //!HOST_DEFS_H 30 | -------------------------------------------------------------------------------- /src/host/Host_IO_Request.h: -------------------------------------------------------------------------------- 1 | #ifndef HOST_IO_REQUEST_H 2 | #define HOST_IO_REQUEST_H 3 | 4 | #include "../ssd/SSD_Defs.h" 5 | 6 | namespace Host_Components 7 | { 8 | enum class Host_IO_Request_Type { READ, WRITE }; 9 | class Host_IO_Request 10 | { 11 | public: 12 | sim_time_type Arrival_time;//The time that the request has been generated 13 | sim_time_type Enqueue_time;//The time that the request enqueued into the I/O queue 14 | LHA_type Start_LBA; 15 | unsigned int LBA_count; 16 | Host_IO_Request_Type Type; 17 | uint16_t IO_queue_info; 18 | uint16_t Source_flow_id;//Only used in SATA host interface 19 | }; 20 | } 21 | 22 | #endif // !HOST_IO_REQUEST_H 23 | -------------------------------------------------------------------------------- /src/host/IO_Flow_Synthetic.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_FLOW_SYNTHETIC_H 2 | #define IO_FLOW_SYNTHETIC_H 3 | 4 | #include 5 | #include "IO_Flow_Base.h" 6 | #include "../utils/RandomGenerator.h" 7 | #include "../utils/DistributionTypes.h" 8 | 9 | 10 | namespace Host_Components 11 | { 12 | class IO_Flow_Synthetic : public IO_Flow_Base 13 | { 14 | public: 15 | IO_Flow_Synthetic(const sim_object_id_type& name, uint16_t flow_id, LHA_type start_lsa_on_device, LHA_type end_lsa_on_device, double working_set_ratio, uint16_t io_queue_id, 16 | uint16_t nvme_submission_queue_size, uint16_t nvme_completion_queue_size, IO_Flow_Priority_Class priority_class, 17 | double read_ratio, Utils::Address_Distribution_Type address_distribution, double hot_address_ratio, 18 | Utils::Request_Size_Distribution_Type request_size_distribution, unsigned int average_request_size, unsigned int variance_request_size, 19 | Utils::Request_Generator_Type generator_type, sim_time_type Average_inter_arrival_time_nano_sec, unsigned int average_number_of_enqueued_requests, 20 | bool generate_aligned_addresses, unsigned int alignment_value, 21 | int seed, sim_time_type stop_time, double initial_occupancy_ratio, unsigned int total_req_count, HostInterface_Types SSD_device_type, PCIe_Root_Complex* pcie_root_complex, SATA_HBA* sata_hba, 22 | bool enabled_logging, sim_time_type logging_period, std::string logging_file_path); 23 | ~IO_Flow_Synthetic(); 24 | Host_IO_Request* Generate_next_request(); 25 | void NVMe_consume_io_request(Completion_Queue_Entry*); 26 | void SATA_consume_io_request(Host_IO_Request*); 27 | void Start_simulation(); 28 | void Validate_simulation_config(); 29 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 30 | void Get_statistics(Utils::Workload_Statistics& stats, LPA_type(*Convert_host_logical_address_to_device_address)(LHA_type lha), 31 | page_status_type(*Find_NVM_subunit_access_bitmap)(LHA_type lha)); 32 | private: 33 | double read_ratio; 34 | double working_set_ratio; 35 | Utils::RandomGenerator* random_request_type_generator; 36 | int random_request_type_generator_seed; 37 | Utils::Address_Distribution_Type address_distribution; 38 | double hot_region_ratio; 39 | Utils::RandomGenerator* random_address_generator; 40 | int random_address_generator_seed; 41 | Utils::RandomGenerator* random_hot_cold_generator; 42 | int random_hot_cold_generator_seed; 43 | Utils::RandomGenerator* random_hot_address_generator; 44 | int random_hot_address_generator_seed; 45 | LHA_type hot_region_end_lsa; 46 | LHA_type streaming_next_address; 47 | Utils::Request_Size_Distribution_Type request_size_distribution; 48 | unsigned int average_request_size; 49 | unsigned int variance_request_size; 50 | Utils::RandomGenerator* random_request_size_generator; 51 | int random_request_size_generator_seed; 52 | Utils::Request_Generator_Type generator_type; 53 | Utils::RandomGenerator* random_time_interval_generator; 54 | int random_time_interval_generator_seed; 55 | sim_time_type Average_inter_arrival_time_nano_sec; 56 | unsigned int average_number_of_enqueued_requests; 57 | bool generate_aligned_addresses; 58 | unsigned int alignment_value; 59 | int seed; 60 | }; 61 | } 62 | 63 | #endif // !IO_FLOW_SYNTHETIC_H 64 | -------------------------------------------------------------------------------- /src/host/IO_Flow_Trace_Based.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_FLOW_TRACE_BASED_H 2 | #define IO_FLOW_TRACE_BASED_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "IO_Flow_Base.h" 8 | #include "ASCII_Trace_Definition.h" 9 | #include "../cxl/CXL_PCIe.h" 10 | 11 | namespace Host_Components 12 | { 13 | class IO_Flow_Trace_Based : public IO_Flow_Base 14 | { 15 | public: 16 | IO_Flow_Trace_Based(const sim_object_id_type& name, uint16_t flow_id, LHA_type start_lsa_on_device, LHA_type end_lsa_on_device, uint16_t io_queue_id, 17 | uint16_t nvme_submission_queue_size, uint16_t nvme_completion_queue_size, IO_Flow_Priority_Class priority_class, double initial_occupancy_ratio, 18 | std::string trace_file_path, Trace_Time_Unit time_unit, unsigned int total_replay_count, unsigned int percentage_to_be_simulated, 19 | HostInterface_Types SSD_device_type, PCIe_Root_Complex* pcie_root_complex, SATA_HBA* sata_hba, 20 | bool enabled_logging, sim_time_type logging_period, std::string logging_file_path, CXL_PCIe* cxl_pcie); 21 | ~IO_Flow_Trace_Based(); 22 | Host_IO_Request* Generate_next_request(); 23 | void NVMe_consume_io_request(Completion_Queue_Entry*); 24 | void SATA_consume_io_request(Host_IO_Request*); 25 | void Start_simulation(); 26 | void Validate_simulation_config(); 27 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 28 | void Get_statistics(Utils::Workload_Statistics& stats, LPA_type(*Convert_host_logical_address_to_device_address)(LHA_type lha), 29 | page_status_type(*Find_NVM_subunit_access_bitmap)(LHA_type lha)); 30 | private: 31 | Trace_Time_Unit time_unit; 32 | unsigned int percentage_to_be_simulated; 33 | std::string trace_file_path; 34 | std::ifstream trace_file; 35 | unsigned int total_replay_no, replay_counter; 36 | unsigned int total_requests_in_file; 37 | std::vector current_trace_line; 38 | sim_time_type time_offset; 39 | 40 | bool need_to_divide; 41 | 42 | CXL_PCIe* cxl_pcie; 43 | 44 | }; 45 | } 46 | 47 | #endif// !IO_FLOW_TRACE_BASED_H 48 | -------------------------------------------------------------------------------- /src/host/PCIe_Link.cpp: -------------------------------------------------------------------------------- 1 | #include "../sim/Sim_Defs.h" 2 | #include "../sim/Engine.h" 3 | #include "PCIe_Link.h" 4 | #include "PCIe_Message.h" 5 | 6 | namespace Host_Components 7 | { 8 | PCIe_Link::PCIe_Link(const sim_object_id_type& id, PCIe_Root_Complex* root_complex, PCIe_Switch* pcie_switch, 9 | double lane_bandwidth_GBPs, int lane_count, int tlp_header_size, 10 | int tlp_max_payload_size, int dllp_ovehread, int ph_overhead) : 11 | Sim_Object(id), root_complex(root_complex), pcie_switch(pcie_switch), 12 | lane_bandwidth_GBPs(lane_bandwidth_GBPs), lane_count(lane_count), 13 | tlp_header_size(tlp_header_size), tlp_max_payload_size(tlp_max_payload_size), dllp_ovehread(dllp_ovehread), ph_overhead(ph_overhead) 14 | { 15 | packet_overhead = ph_overhead + dllp_ovehread + tlp_header_size; 16 | } 17 | 18 | void PCIe_Link::Set_root_complex(PCIe_Root_Complex* root_complex) 19 | { 20 | this->root_complex = root_complex; 21 | } 22 | 23 | void PCIe_Link::Set_pcie_switch(PCIe_Switch* pcie_switch) 24 | { 25 | this->pcie_switch = pcie_switch; 26 | } 27 | 28 | void PCIe_Link::Deliver(PCIe_Message* message) 29 | { 30 | switch (message->Destination) { 31 | case PCIe_Destination_Type::HOST://Message from SSD device to the host 32 | Message_buffer_toward_root_complex.push(message); 33 | if (Message_buffer_toward_root_complex.size() > 1) {//There are active transfers 34 | return; 35 | } 36 | Simulator->Register_sim_event(Simulator->Time() + estimate_transfer_time(message), this, (void*)(intptr_t)PCIe_Destination_Type::HOST, static_cast(PCIe_Link_Event_Type::DELIVER)); 37 | break; 38 | case PCIe_Destination_Type::DEVICE://Message from Host to the SSD device 39 | Message_buffer_toward_ssd_device.push(message); 40 | if (Message_buffer_toward_ssd_device.size() > 1) { 41 | return; 42 | } 43 | Simulator->Register_sim_event(Simulator->Time() + estimate_transfer_time(message), this, (void*)(intptr_t)PCIe_Destination_Type::DEVICE, static_cast(PCIe_Link_Event_Type::DELIVER)); 44 | break; 45 | default: 46 | break; 47 | } 48 | } 49 | 50 | void PCIe_Link::Start_simulation() {} 51 | 52 | void PCIe_Link::Validate_simulation_config() {} 53 | 54 | void PCIe_Link::Execute_simulator_event(MQSimEngine::Sim_Event* event) 55 | { 56 | PCIe_Message* message = NULL; 57 | PCIe_Destination_Type destination = (PCIe_Destination_Type)(intptr_t)event->Parameters; 58 | switch (destination) { 59 | case PCIe_Destination_Type::HOST: 60 | message = Message_buffer_toward_root_complex.front(); 61 | Message_buffer_toward_root_complex.pop(); 62 | root_complex->Consume_pcie_message(message); 63 | if (Message_buffer_toward_root_complex.size() > 0) {//There are active transfers 64 | Simulator->Register_sim_event(Simulator->Time() + estimate_transfer_time(Message_buffer_toward_root_complex.front()), 65 | this, (void*)(intptr_t)PCIe_Destination_Type::HOST, static_cast(PCIe_Link_Event_Type::DELIVER)); 66 | } 67 | break; 68 | case PCIe_Destination_Type::DEVICE: 69 | message = Message_buffer_toward_ssd_device.front(); 70 | Message_buffer_toward_ssd_device.pop(); 71 | pcie_switch->Deliver_to_device(message); 72 | if (Message_buffer_toward_ssd_device.size() > 0) { 73 | Simulator->Register_sim_event(Simulator->Time() + estimate_transfer_time(Message_buffer_toward_ssd_device.front()), 74 | this, (void*)(intptr_t)PCIe_Destination_Type::DEVICE, static_cast(PCIe_Link_Event_Type::DELIVER)); 75 | } 76 | break; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/host/PCIe_Link.h: -------------------------------------------------------------------------------- 1 | #ifndef PCIE_LINK_H 2 | #define PCIE_LINK_H 3 | 4 | #include "queue" 5 | #include "../sim/Sim_Defs.h" 6 | #include "../sim/Sim_Object.h" 7 | #include "../sim/Sim_Event.h" 8 | #include "PCIe_Message.h" 9 | #include "PCIe_Root_Complex.h" 10 | #include "PCIe_Switch.h" 11 | 12 | namespace Host_Components 13 | { 14 | class PCIe_Switch; 15 | class PCIe_Root_Complex; 16 | enum class PCIe_Link_Event_Type {DELIVER}; 17 | 18 | class PCIe_Link : public MQSimEngine::Sim_Object 19 | { 20 | public: 21 | PCIe_Link(const sim_object_id_type& id, PCIe_Root_Complex* root_complex, PCIe_Switch* pcie_switch, 22 | double lane_bandwidth_GBPs = 1, int lane_count = 4, 23 | int tlp_header_size = 20,//tlp header size in a 64-bit machine 24 | int tlp_max_payload_size = 128, 25 | int dllp_ovehread = 6, 26 | int ph_overhead = 2); 27 | void Deliver(PCIe_Message*); 28 | void Start_simulation(); 29 | void Validate_simulation_config(); 30 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 31 | void Set_root_complex(PCIe_Root_Complex*); 32 | void Set_pcie_switch(PCIe_Switch*); 33 | private: 34 | PCIe_Root_Complex* root_complex; 35 | PCIe_Switch* pcie_switch; 36 | double lane_bandwidth_GBPs;//GB/s 37 | int lane_count; 38 | int tlp_header_size, tlp_max_payload_size; 39 | int dllp_ovehread, ph_overhead; 40 | //sim_time_type byte_transfer_delay_per_lane;//Since the transfer delay of one byte may take lower than one nano-second, we use 8-byte metric 41 | int packet_overhead; 42 | std::queue Message_buffer_toward_ssd_device; 43 | 44 | sim_time_type estimate_transfer_time(PCIe_Message* message) 45 | { 46 | switch (message->Type) { 47 | case PCIe_Message_Type::READ_COMP: 48 | case PCIe_Message_Type::WRITE_REQ: 49 | { 50 | int total_transfered_bytes = (message->Payload_size / tlp_max_payload_size) * (tlp_max_payload_size + packet_overhead) 51 | + (message->Payload_size % tlp_max_payload_size == 0 ? 0 : message->Payload_size % tlp_max_payload_size + packet_overhead); 52 | return (sim_time_type)(((double)((total_transfered_bytes / lane_count) + (total_transfered_bytes % lane_count == 0 ? 0 : 1))) / lane_bandwidth_GBPs); 53 | } 54 | case PCIe_Message_Type::READ_REQ: 55 | return (sim_time_type)((((packet_overhead + 4) / lane_count) + ((packet_overhead + 4) % lane_count == 0 ? 0 : 1)) / lane_bandwidth_GBPs); 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | std::queue Message_buffer_toward_root_complex; 62 | }; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/host/PCIe_Message.h: -------------------------------------------------------------------------------- 1 | #ifndef PCIE_MESSAGE_H 2 | #define PCIE_MESSAGE_H 3 | 4 | #include 5 | 6 | namespace Host_Components 7 | { 8 | enum class PCIe_Destination_Type {HOST, DEVICE}; 9 | enum class PCIe_Message_Type {READ_REQ, WRITE_REQ, READ_COMP}; 10 | 11 | class PCIe_Message 12 | { 13 | public: 14 | PCIe_Destination_Type Destination; 15 | PCIe_Message_Type Type; 16 | void* Payload; 17 | unsigned int Payload_size; 18 | uint64_t Address; 19 | }; 20 | } 21 | 22 | #endif //!PCIE_MESSAGE_H 23 | -------------------------------------------------------------------------------- /src/host/PCIe_Root_Complex.cpp: -------------------------------------------------------------------------------- 1 | #include "PCIe_Root_Complex.h" 2 | 3 | 4 | namespace Host_Components 5 | { 6 | PCIe_Root_Complex::PCIe_Root_Complex(PCIe_Link* pcie_link, HostInterface_Types SSD_device_type, SATA_HBA* sata_hba, std::vector* IO_flows) : 7 | pcie_link(pcie_link), SSD_device_type(SSD_device_type), sata_hba(sata_hba), IO_flows(IO_flows) {} 8 | 9 | void PCIe_Root_Complex::Write_to_memory(const uint64_t address, const void* payload) 10 | { 11 | //This is a request to write back a read request data into memory (in modern systems the write is done to LLC) 12 | if (address >= DATA_MEMORY_REGION) { 13 | //nothing to do 14 | } else { 15 | switch (SSD_device_type) { 16 | case HostInterface_Types::NVME: 17 | { 18 | unsigned int flow_id = QUEUE_ID_TO_FLOW_ID(((Completion_Queue_Entry*)payload)->SQ_ID); 19 | ((*IO_flows)[flow_id])->NVMe_consume_io_request((Completion_Queue_Entry*)payload); 20 | break; 21 | } 22 | case HostInterface_Types::SATA: 23 | sata_hba->SATA_consume_io_request((Completion_Queue_Entry*)payload); 24 | break; 25 | default: 26 | PRINT_ERROR("Uknown Host Interface type in PCIe_Root_Complex") 27 | } 28 | } 29 | } 30 | 31 | void PCIe_Root_Complex::Write_to_device(uint64_t address, uint16_t write_value) 32 | { 33 | PCIe_Message* pcie_message = new Host_Components::PCIe_Message; 34 | pcie_message->Type = PCIe_Message_Type::WRITE_REQ; 35 | pcie_message->Destination = Host_Components::PCIe_Destination_Type::DEVICE; 36 | pcie_message->Address = address; 37 | pcie_message->Payload = (void*)(intptr_t)write_value; 38 | pcie_message->Payload_size = sizeof(write_value); 39 | pcie_link->Deliver(pcie_message); 40 | } 41 | 42 | void PCIe_Root_Complex::Read_from_memory(const uint64_t address, const unsigned int read_size) 43 | { 44 | PCIe_Message* new_pcie_message = new Host_Components::PCIe_Message; 45 | new_pcie_message->Type = PCIe_Message_Type::READ_COMP; 46 | new_pcie_message->Destination = Host_Components::PCIe_Destination_Type::DEVICE; 47 | new_pcie_message->Address = address; 48 | 49 | //This is a request to read the data of a write request 50 | if (address >= DATA_MEMORY_REGION) { 51 | //nothing to do 52 | new_pcie_message->Payload_size = read_size; 53 | new_pcie_message->Payload = NULL;//No need to transfer data in the standalone mode of MQSim 54 | } else { 55 | switch (SSD_device_type) { 56 | case HostInterface_Types::NVME: 57 | { 58 | uint16_t flow_id = QUEUE_ID_TO_FLOW_ID(uint16_t(address >> NVME_COMP_Q_MEMORY_REGION)); 59 | new_pcie_message->Payload = (*IO_flows)[flow_id]->NVMe_read_sqe(address); 60 | new_pcie_message->Payload_size = sizeof(Submission_Queue_Entry); 61 | break; 62 | } 63 | case HostInterface_Types::SATA: 64 | new_pcie_message->Payload = sata_hba->Read_ncq_entry(address); 65 | new_pcie_message->Payload_size = sizeof(Submission_Queue_Entry); 66 | break; 67 | } 68 | } 69 | 70 | pcie_link->Deliver(new_pcie_message); 71 | } 72 | 73 | void PCIe_Root_Complex::Set_io_flows(std::vector* IO_flows) 74 | { 75 | this->IO_flows = IO_flows; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/host/PCIe_Root_Complex.h: -------------------------------------------------------------------------------- 1 | #ifndef PCIE_ROOT_COMPLEX_H 2 | #define PCIE_ROOT_COMPLEX_H 3 | 4 | #include "../ssd/Host_Interface_Defs.h" 5 | #include "Host_Defs.h" 6 | #include "PCIe_Message.h" 7 | #include "PCIe_Link.h" 8 | #include "Host_IO_Request.h" 9 | #include "IO_Flow_Base.h" 10 | #include "SATA_HBA.h" 11 | 12 | 13 | namespace Host_Components 14 | { 15 | class PCIe_Link; 16 | class IO_Flow_Base; 17 | class SATA_HBA; 18 | class PCIe_Root_Complex 19 | { 20 | public: 21 | PCIe_Root_Complex(PCIe_Link* pcie_link, HostInterface_Types SSD_device_type, SATA_HBA* sata_hba, std::vector* IO_flows); 22 | 23 | void Consume_pcie_message(PCIe_Message* messages)//Modern processors support DDIO, where all writes to memory are going through LLC 24 | { 25 | switch (messages->Type) 26 | { 27 | case PCIe_Message_Type::READ_REQ: 28 | Read_from_memory(messages->Address, (unsigned int)(intptr_t)messages->Payload); 29 | break; 30 | case PCIe_Message_Type::WRITE_REQ: 31 | Write_to_memory(messages->Address, messages->Payload); 32 | break; 33 | default: 34 | break; 35 | } 36 | delete messages; 37 | } 38 | 39 | void Write_to_device(uint64_t address, uint16_t write_value); 40 | void Set_io_flows(std::vector* IO_flows); 41 | private: 42 | PCIe_Link* pcie_link; 43 | HostInterface_Types SSD_device_type; 44 | SATA_HBA * sata_hba; 45 | std::vector* IO_flows; 46 | 47 | void Write_to_memory(const uint64_t address, const void* payload); 48 | void Read_from_memory(const uint64_t address, const unsigned int size); 49 | }; 50 | } 51 | 52 | #endif //!PCIE_ROOT_COMPLEX_H 53 | -------------------------------------------------------------------------------- /src/host/PCIe_Switch.cpp: -------------------------------------------------------------------------------- 1 | #include "PCIe_Switch.h" 2 | 3 | namespace Host_Components 4 | { 5 | PCIe_Switch::PCIe_Switch(PCIe_Link* pcie_link, SSD_Components::Host_Interface_Base* host_interface) : 6 | pcie_link(pcie_link), host_interface(host_interface) 7 | { 8 | } 9 | 10 | void PCIe_Switch::Deliver_to_device(PCIe_Message* message) 11 | { 12 | host_interface->Consume_pcie_message(message); 13 | } 14 | 15 | void PCIe_Switch::Send_to_host(PCIe_Message* message) 16 | { 17 | //pcie_link->Deliver(message); 18 | } 19 | 20 | void PCIe_Switch::Attach_ssd_device(SSD_Components::Host_Interface_Base* host_interface) 21 | { 22 | this->host_interface = host_interface; 23 | } 24 | 25 | bool PCIe_Switch::Is_ssd_connected() 26 | { 27 | return this->host_interface != NULL; 28 | } 29 | 30 | void PCIe_Switch::Notify_request_complete() { 31 | cxl_pcie->Request_completed(); 32 | } 33 | 34 | void PCIe_Switch::Notify_mshr_full() { 35 | cxl_pcie->MSHR_full(); 36 | } 37 | void PCIe_Switch::Notify_mshr_not_full() { 38 | cxl_pcie->MSHR_not_full(); 39 | } 40 | 41 | void PCIe_Switch::Notify_dram_full() { 42 | cxl_pcie->mark_dram_full(); 43 | } 44 | void PCIe_Switch::Notify_dram_avail() { 45 | cxl_pcie->mark_dram_free(); 46 | } 47 | 48 | void PCIe_Switch::Notify_flash_full() { 49 | cxl_pcie->mark_flash_full(); 50 | 51 | } 52 | void PCIe_Switch::Notify_flash_not_full() { 53 | cxl_pcie->mark_flash_free(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/host/PCIe_Switch.h: -------------------------------------------------------------------------------- 1 | #ifndef PCIE_SWITCH_H 2 | #define PCIE_SWITCH_H 3 | 4 | #include "PCIe_Message.h" 5 | #include "PCIe_Link.h" 6 | #include "../ssd/Host_Interface_Base.h" 7 | #include "../cxl/CXL_PCIe.h" 8 | 9 | namespace SSD_Components 10 | { 11 | class Host_Interface_Base; 12 | } 13 | 14 | namespace Host_Components 15 | { 16 | class CXL_PCIe; 17 | class PCIe_Link; 18 | class PCIe_Switch 19 | { 20 | public: 21 | PCIe_Switch(PCIe_Link* pcie_link, SSD_Components::Host_Interface_Base* host_interface);//, SSD_Components::Host_Interface_Base* host_interface 22 | void Deliver_to_device(PCIe_Message*); 23 | void Send_to_host(PCIe_Message*); 24 | void Attach_ssd_device(SSD_Components::Host_Interface_Base* host_interface); 25 | bool Is_ssd_connected(); 26 | 27 | void Notify_request_complete(); 28 | void Notify_mshr_full(); 29 | void Notify_mshr_not_full(); 30 | void Notify_dram_full(); 31 | void Notify_dram_avail(); 32 | void Notify_flash_full(); 33 | void Notify_flash_not_full(); 34 | CXL_PCIe* cxl_pcie{ NULL }; 35 | private: 36 | PCIe_Link* pcie_link; 37 | SSD_Components::Host_Interface_Base* host_interface; 38 | 39 | }; 40 | } 41 | #endif //!PCIE_SWITCH_H 42 | -------------------------------------------------------------------------------- /src/host/SATA_HBA.h: -------------------------------------------------------------------------------- 1 | #ifndef SATA_HBA_H 2 | #define SATA_HBA_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../sim/Sim_Defs.h" 9 | #include "../sim/Sim_Object.h" 10 | #include "Host_IO_Request.h" 11 | #include "IO_Flow_Base.h" 12 | #include "PCIe_Root_Complex.h" 13 | 14 | namespace Host_Components 15 | { 16 | #define SATA_SQ_FULL(Q) (Q.Submission_queue_tail < Q.Submission_queue_size - 1 ? Q.Submission_queue_tail + 1 == Q.Submission_queue_head : Q.Submission_queue_head == 0) 17 | #define SATA_UPDATE_SQ_TAIL(Q) Q.Submission_queue_tail++;\ 18 | if (Q.Submission_queue_tail == Q.Submission_queue_size)\ 19 | Q.Submission_queue_tail = 0; 20 | 21 | struct NCQ_Control_Structure //SATA native command queue 22 | { 23 | uint16_t Submission_queue_head; 24 | uint16_t Submission_queue_tail; 25 | uint16_t Submission_queue_size; 26 | uint64_t Submission_tail_register_address_on_device; 27 | uint64_t Submission_queue_memory_base_address; 28 | uint16_t Completion_queue_head; 29 | uint16_t Completion_queue_tail; 30 | uint16_t Completion_queue_size; 31 | uint64_t Completion_head_register_address_on_device; 32 | uint64_t Completion_queue_memory_base_address; 33 | std::unordered_map queue;//Contains the I/O requests that are enqueued in the NCQ 34 | }; 35 | 36 | enum class HBA_Sim_Events {SUBMIT_IO_REQUEST, CONSUME_IO_REQUEST}; 37 | 38 | class IO_Flow_Base; 39 | class PCIe_Root_Complex; 40 | class SATA_HBA : MQSimEngine::Sim_Object 41 | { 42 | public: 43 | SATA_HBA(sim_object_id_type id, uint16_t ncq_size, sim_time_type hba_processing_delay, PCIe_Root_Complex* pcie_root_complex, std::vector* IO_flows); 44 | ~SATA_HBA(); 45 | void Start_simulation(); 46 | void Validate_simulation_config(); 47 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 48 | void Submit_io_request(Host_IO_Request* request); 49 | void SATA_consume_io_request(Completion_Queue_Entry* cqe); 50 | Submission_Queue_Entry* Read_ncq_entry(uint64_t address); 51 | const NCQ_Control_Structure* Get_sata_ncq_info(); 52 | void Set_io_flows(std::vector* IO_flows); 53 | void Set_root_complex(PCIe_Root_Complex*); 54 | private: 55 | uint16_t ncq_size; 56 | sim_time_type hba_processing_delay;//This estimates the processing delay of the whole SATA software and hardware layers to send/receive a SATA message 57 | PCIe_Root_Complex * pcie_root_complex; 58 | std::vector* IO_flows; 59 | NCQ_Control_Structure sata_ncq; 60 | std::set available_command_ids; 61 | std::vector request_queue_in_memory; 62 | std::list waiting_requests_for_submission;//The I/O requests that are still waiting (since the I/O queue is full) to be enqueued in the I/O queue 63 | void Update_and_submit_ncq_completion_info(); 64 | std::queue consume_requests; 65 | std::queue host_requests; 66 | }; 67 | } 68 | 69 | #endif // !SATA_HBA_H 70 | -------------------------------------------------------------------------------- /src/nvm_chip/NVM_Chip.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_CHIP_H 2 | #define NVM_CHIP_H 3 | 4 | #include "../sim/Sim_Object.h" 5 | #include "NVM_Memory_Address.h" 6 | 7 | namespace NVM 8 | { 9 | class NVM_Chip : public MQSimEngine::Sim_Object 10 | { 11 | public: 12 | NVM_Chip(const sim_object_id_type& id) : Sim_Object(id) {} 13 | virtual void Change_memory_status_preconditioning(const NVM_Memory_Address* address, const void* status_info) = 0; 14 | }; 15 | } 16 | 17 | #endif // !NVM_CHIP_H 18 | -------------------------------------------------------------------------------- /src/nvm_chip/NVM_Memory_Address.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_MEMORY_ADDRESS_H 2 | #define NVM_MEMORY_ADDRESS_H 3 | 4 | namespace NVM 5 | { 6 | class NVM_Memory_Address 7 | { 8 | 9 | }; 10 | } 11 | 12 | #endif // !NVM_MEMORY_ADDRESS_H 13 | -------------------------------------------------------------------------------- /src/nvm_chip/NVM_Types.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TYPES_H 2 | #define NVM_TYPES_H 3 | 4 | #include 5 | 6 | namespace NVM 7 | { 8 | enum class NVM_Type {FLASH}; 9 | typedef uint64_t memory_content_type; 10 | } 11 | 12 | #endif // !NVM_TYPES_H 13 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Block.cpp: -------------------------------------------------------------------------------- 1 | #include "Block.h" 2 | 3 | namespace NVM 4 | { 5 | namespace FlashMemory 6 | { 7 | Block::Block(unsigned int PagesNoPerBlock, flash_block_ID_type BlockID) 8 | { 9 | ID = BlockID; 10 | Pages = new Page[PagesNoPerBlock]; 11 | } 12 | 13 | Block::~Block() 14 | { 15 | delete[] Pages; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Block.h: -------------------------------------------------------------------------------- 1 | #ifndef BLOCK_H 2 | #define BLOCK_H 3 | 4 | #include "FlashTypes.h" 5 | #include "Page.h" 6 | 7 | 8 | namespace NVM 9 | { 10 | namespace FlashMemory 11 | { 12 | class Block 13 | { 14 | public: 15 | Block(unsigned int PagesNoPerBlock, flash_block_ID_type BlockID); 16 | ~Block(); 17 | Page* Pages; //Records the status of each sub-page 18 | flash_block_ID_type ID; //Again this variable is required in list based garbage collections 19 | //BlockMetadata Metadata; 20 | }; 21 | } 22 | } 23 | #endif // ! BLOCK_H 24 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Die.cpp: -------------------------------------------------------------------------------- 1 | #include "Die.h" 2 | 3 | namespace NVM 4 | { 5 | namespace FlashMemory 6 | { 7 | Die::Die(unsigned int PlanesNoPerDie, unsigned int BlocksNoPerPlane, unsigned int PagesNoPerBlock) : 8 | Plane_no(PlanesNoPerDie), 9 | Status(DieStatus::IDLE), CommandFinishEvent(NULL), Expected_finish_time(INVALID_TIME), RemainingSuspendedExecTime(INVALID_TIME), 10 | CurrentCMD(NULL), SuspendedCMD(NULL), Suspended(false), 11 | STAT_TotalProgramTime(0), STAT_TotalReadTime(0), STAT_TotalEraseTime(0), STAT_TotalXferTime(0) 12 | { 13 | Planes = new Plane*[PlanesNoPerDie]; 14 | for (unsigned int i = 0; i < PlanesNoPerDie; i++) { 15 | Planes[i] = new Plane(BlocksNoPerPlane, PagesNoPerBlock); 16 | } 17 | } 18 | 19 | Die::~Die() 20 | { 21 | for (unsigned int planeID = 0; planeID < Plane_no; planeID++) { 22 | delete Planes[planeID]; 23 | } 24 | delete[] Planes; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Die.h: -------------------------------------------------------------------------------- 1 | #ifndef DIE_H 2 | #define DIE_H 3 | 4 | #include "../../sim/Sim_Event.h" 5 | #include "FlashTypes.h" 6 | #include "Plane.h" 7 | 8 | namespace NVM 9 | { 10 | namespace FlashMemory 11 | { 12 | enum class DieStatus { BUSY, IDLE }; 13 | class Die 14 | { 15 | public: 16 | Die(unsigned int PlanesNoPerDie, unsigned int BlocksNoPerPlane, unsigned int PagesNoPerBlock); 17 | ~Die(); 18 | Plane** Planes; 19 | unsigned int Plane_no; 20 | DieStatus Status; 21 | MQSimEngine::Sim_Event* CommandFinishEvent; 22 | sim_time_type Expected_finish_time; 23 | sim_time_type RemainingSuspendedExecTime;//used to support suspend command 24 | Flash_Command* CurrentCMD, *SuspendedCMD; 25 | bool Suspended; 26 | 27 | sim_time_type STAT_TotalProgramTime, STAT_TotalReadTime, STAT_TotalEraseTime, STAT_TotalXferTime; 28 | }; 29 | } 30 | } 31 | #endif // !DIE_H 32 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/FlashTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASH_TYPES_H 2 | #define FLASH_TYPES_H 3 | 4 | #include 5 | #include "../../sim/Sim_Defs.h" 6 | #include "../NVM_Types.h" 7 | 8 | namespace NVM 9 | { 10 | namespace FlashMemory 11 | { 12 | enum class Command_Suspension_Mode { NONE, PROGRAM, PROGRAM_ERASE, ERASE }; 13 | } 14 | } 15 | 16 | typedef uint64_t page_status_type; 17 | #define FULL_PROGRAMMED_PAGE 0xffffffffffffffffULL 18 | typedef uint32_t flash_channel_ID_type; 19 | typedef uint32_t flash_chip_ID_type; 20 | typedef uint32_t flash_die_ID_type; 21 | typedef uint32_t flash_plane_ID_type; 22 | typedef uint32_t flash_block_ID_type; 23 | typedef uint32_t flash_page_ID_type; 24 | typedef uint64_t LPA_type; 25 | typedef uint64_t PPA_type; 26 | typedef uint64_t command_code_type; 27 | 28 | enum class Flash_Technology_Type { SLC = 1, MLC = 2, TLC = 3 }; 29 | 30 | #define FREE_PAGE 0x0000000000000000ULL 31 | #define NO_LPA 0xffffffffffffffffULL 32 | #define NO_STREAM 0xff 33 | #define UNWRITTEN_LOGICAL_PAGE 0x0000000000000000ULL 34 | #define NO_PPA 0xffffffffffffffffULL 35 | #define NO_MPPN 0xffffffffULL 36 | 37 | #endif // !FLASH_TYPES_H 38 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Flash_Command.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASH_COMMAND_H 2 | #define FLASH_COMMAND_H 3 | 4 | #include 5 | #include "FlashTypes.h" 6 | #include "Physical_Page_Address.h" 7 | #include "Page.h" 8 | #include "SubPage.h" 9 | 10 | 11 | #define CMD_READ 0x0030 12 | #define CMD_READ_PAGE 0x0030 13 | #define CMD_READ_PAGE_CACHE_SEQ 0x31 14 | #define CMD_READ_PAGE_CACHE_RANDOM 0x0031 15 | #define CMD_READ_PAGE_MULTIPLANE 0x0032 16 | #define CMD_READ_PAGE_COPYBACK 0x0035 17 | #define CMD_READ_PAGE_COPYBACK_MULTIPLANE 0x00321 //since the codes of multiplane copyback (i.e., 0x0032) and multiplane read (i.e., 0x0032) are identical, we change the code of multiplane copyback 0x0032 to 0x00321 so that we can differentiate copyback multiplane from normal multiplane 18 | #define CMD_PROGRAM 0x8000 19 | #define CMD_PROGRAM_PAGE 0x8010 20 | #define CMD_PROGRAM_PAGE_MULTIPLANE 0x8011 21 | #define CMD_PROGRAM_PAGE_COPYBACK 0x8510 22 | #define CMD_PROGRAM_PAGE_COPYBACK_MULTIPLANE 0x85111 //since the codes of multiplane copyback (i.e., 0x8511) and multiplane program (i.e., 0x8511) are identical, we change the code of multiplane copyback 0x8511 to 0x85111 so that we can differentiate copyback multiplane from normal multiplane 23 | //#define CMD_SUSPEND_PROGRAM 0x86 24 | //#define CMD_RESUME_PROGRAM 0xD1 25 | #define CMD_ERASE 0x6000 26 | #define CMD_ERASE_BLOCK 0x60D0 27 | #define CMD_ERASE_BLOCK_MULTIPLANE 0x60D1 28 | //#define CMD_SUSPEND_ERASE 0x61 29 | //#define CMD_RESUME_ERASE 0xD2 30 | 31 | namespace NVM 32 | { 33 | namespace FlashMemory 34 | { 35 | class Flash_Command 36 | { 37 | public: 38 | command_code_type CommandCode; 39 | std::vector Address; 40 | //std::vector Meta_data; 41 | std::vector Meta_data; 42 | 43 | 44 | std::vector Addresses_subpgs; 45 | std::vector Meta_datas_subpgs; 46 | 47 | }; 48 | } 49 | } 50 | #endif // !FLASH_COMMAND 51 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Page.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGE_H 2 | #define PAGE_H 3 | 4 | #include "FlashTypes.h" 5 | #include "SubPage.h" 6 | 7 | namespace NVM 8 | { 9 | namespace FlashMemory 10 | { 11 | 12 | struct PageMetadata 13 | { 14 | //page_status_type Status; 15 | LPA_type LPA; 16 | }; 17 | 18 | class Page { 19 | public: 20 | Page() 21 | { 22 | 23 | //Metadata.Status = FREE_PAGE; 24 | Metadata.LPA = NO_LPA; 25 | //Metadata.SourceStreamID = NO_STREAM; 26 | 27 | SubPages = new SubPage[ALIGN_UNIT_SIZE]; 28 | 29 | }; 30 | 31 | SubPage* SubPages; 32 | 33 | PageMetadata Metadata; 34 | 35 | void Write_metadata(const PageMetadata& metadata) 36 | { 37 | this->Metadata.LPA = metadata.LPA; 38 | } 39 | 40 | void Read_metadata(PageMetadata& metadata) 41 | { 42 | metadata.LPA = this->Metadata.LPA; 43 | } 44 | }; 45 | } 46 | } 47 | 48 | #endif // !PAGE_H 49 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Physical_Page_Address.cpp: -------------------------------------------------------------------------------- 1 | #include "Physical_Page_Address.h" 2 | 3 | namespace NVM 4 | { 5 | namespace FlashMemory 6 | { 7 | bool Physical_Page_Address::block_address_constraint_for_multiplane = true; 8 | } 9 | } -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Physical_Page_Address.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICAL_PAGE_ADDRESS_H 2 | #define PHYSICAL_PAGE_ADDRESS_H 3 | 4 | #include "../NVM_Memory_Address.h" 5 | #include "FlashTypes.h" 6 | 7 | namespace NVM 8 | { 9 | namespace FlashMemory 10 | { 11 | class Physical_Page_Address : public NVM_Memory_Address 12 | { 13 | private: 14 | static bool block_address_constraint_for_multiplane;//Block address of the commands to neighbor planes must be identical for multiplane command execution 15 | public: 16 | flash_channel_ID_type ChannelID; 17 | flash_chip_ID_type ChipID; //The flashchip ID inside its channel 18 | flash_die_ID_type DieID; 19 | flash_plane_ID_type PlaneID; 20 | flash_block_ID_type BlockID; 21 | flash_page_ID_type PageID; 22 | 23 | flash_page_ID_type subPageID; 24 | bool isPrimaryPage; 25 | 26 | 27 | Physical_Page_Address(const flash_channel_ID_type channel_id = 0, const flash_chip_ID_type chip_id = 0, const flash_die_ID_type die_id = 0, 28 | const flash_plane_ID_type plane_id = 0, const flash_block_ID_type block_id = 0, const flash_page_ID_type page_id = 0) 29 | { 30 | ChannelID = channel_id; 31 | ChipID = chip_id; 32 | DieID = die_id; 33 | PlaneID = plane_id; 34 | BlockID = block_id; 35 | PageID = page_id; 36 | 37 | subPageID = 0; 38 | 39 | } 40 | 41 | Physical_Page_Address(const Physical_Page_Address& addressToCopy) 42 | { 43 | ChannelID = addressToCopy.ChannelID; 44 | ChipID = addressToCopy.ChipID; 45 | DieID = addressToCopy.DieID; 46 | PlaneID = addressToCopy.PlaneID; 47 | BlockID = addressToCopy.BlockID; 48 | PageID = addressToCopy.PageID; 49 | 50 | subPageID = addressToCopy.subPageID; 51 | 52 | } 53 | 54 | static void SetBlockAddressConstraint(const bool BAConstraint) 55 | { 56 | block_address_constraint_for_multiplane = BAConstraint; 57 | } 58 | }; 59 | } 60 | } 61 | #endif // !PageAddress_H 62 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Plane.cpp: -------------------------------------------------------------------------------- 1 | #include "Plane.h" 2 | 3 | namespace NVM 4 | { 5 | namespace FlashMemory 6 | { 7 | Plane::Plane(unsigned int BlocksNoPerPlane, unsigned int PagesNoPerBlock) : 8 | Read_count(0), Progam_count(0), Erase_count(0) 9 | { 10 | Healthy_block_no = BlocksNoPerPlane; 11 | Blocks = new Block*[BlocksNoPerPlane]; 12 | for (unsigned int i = 0; i < BlocksNoPerPlane; i++) { 13 | Blocks[i] = new Block(PagesNoPerBlock, i); 14 | } 15 | Allocated_streams = NULL; 16 | } 17 | 18 | Plane::~Plane() 19 | { 20 | for (unsigned int i = 0; i < Healthy_block_no; i++) { 21 | delete Blocks[i]; 22 | } 23 | delete[] Blocks; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/Plane.h: -------------------------------------------------------------------------------- 1 | #ifndef PLANE_H 2 | #define PLANE_H 3 | 4 | #include "../NVM_Types.h" 5 | #include "FlashTypes.h" 6 | #include "Block.h" 7 | #include "Flash_Command.h" 8 | 9 | namespace NVM 10 | { 11 | namespace FlashMemory 12 | { 13 | class Plane 14 | { 15 | public: 16 | Plane(unsigned int BlocksNoPerPlane, unsigned int PagesNoPerBlock); 17 | ~Plane(); 18 | Block** Blocks; 19 | unsigned int Healthy_block_no; 20 | unsigned long Read_count; //how many read count in the process of workload 21 | unsigned long Progam_count; 22 | unsigned long Erase_count; 23 | stream_id_type* Allocated_streams; 24 | }; 25 | } 26 | } 27 | #endif // !PLANE_H 28 | -------------------------------------------------------------------------------- /src/nvm_chip/flash_memory/SubPage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SUBPAGE_H 3 | #define SUBPAGE_H 4 | 5 | #include "FlashTypes.h" 6 | #include "Page.h" 7 | 8 | namespace NVM 9 | { 10 | namespace FlashMemory 11 | { 12 | 13 | struct SubPageMetadata 14 | { 15 | //page_status_type Status; 16 | LPA_type LPA; 17 | }; 18 | 19 | 20 | class SubPage { 21 | public: 22 | SubPage() 23 | { 24 | //Metadata.Status = FREE_PAGE; 25 | Metadata.LPA = NO_LPA; 26 | //Metadata.SourceStreamID = NO_STREAM; 27 | }; 28 | 29 | SubPageMetadata Metadata; 30 | //PageMetadata Metadata_p; 31 | 32 | void Write_metadata(const SubPageMetadata& metadata) 33 | { 34 | this->Metadata.LPA = metadata.LPA; 35 | } 36 | 37 | /* 38 | void Write_metadata_p(const PageMetadata& metadata_p) 39 | { 40 | this->Metadata.LPA = metadata_p.LPA; 41 | } 42 | 43 | */ 44 | 45 | void Read_metadata(SubPageMetadata& metadata) 46 | { 47 | metadata.LPA = this->Metadata.LPA; 48 | if (this->Metadata.LPA == 283963) { 49 | ////std::cout << "[DEBUG GC-Read_metadata()] read LPA = 283963 from chip "<< std::endl; 50 | } 51 | } 52 | }; 53 | } 54 | } 55 | 56 | #endif // !SUBPAGE_H 57 | -------------------------------------------------------------------------------- /src/sim/Engine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Engine.h" 3 | #include "../utils/Logical_Address_Partitioning_Unit.h" 4 | 5 | namespace MQSimEngine 6 | { 7 | Engine* Engine::_instance = NULL; 8 | 9 | Engine* Engine::Instance() { 10 | if (_instance == 0) { 11 | _instance = new Engine; 12 | } 13 | return _instance; 14 | } 15 | 16 | void Engine::Reset() 17 | { 18 | _EventList->Clear(); 19 | _ObjectList.clear(); 20 | _sim_time = 0; 21 | stop = false; 22 | started = false; 23 | Utils::Logical_Address_Partitioning_Unit::Reset(); 24 | } 25 | 26 | 27 | //Add an object to the simulator object list 28 | void Engine::AddObject(Sim_Object* obj) 29 | { 30 | if (_ObjectList.find(obj->ID()) != _ObjectList.end()) { 31 | throw std::invalid_argument("Duplicate object key: " + obj->ID()); 32 | } 33 | _ObjectList.insert(std::pair(obj->ID(), obj)); 34 | } 35 | 36 | Sim_Object* Engine::GetObject(sim_object_id_type object_id) 37 | { 38 | auto itr = _ObjectList.find(object_id); 39 | if (itr == _ObjectList.end()) { 40 | return NULL; 41 | } 42 | 43 | return (*itr).second; 44 | } 45 | 46 | void Engine::RemoveObject(Sim_Object* obj) 47 | { 48 | std::unordered_map::iterator it = _ObjectList.find(obj->ID()); 49 | if (it == _ObjectList.end()) { 50 | throw std::invalid_argument("Removing an unregistered object."); 51 | } 52 | _ObjectList.erase(it); 53 | } 54 | 55 | /// This is the main method of simulator which starts simulation process. 56 | void Engine::Start_simulation() 57 | { 58 | started = true; 59 | 60 | for(std::unordered_map::iterator obj = _ObjectList.begin(); 61 | obj != _ObjectList.end(); 62 | ++obj) { 63 | if (!obj->second->IsTriggersSetUp()) { 64 | obj->second->Setup_triggers(); 65 | } 66 | } 67 | 68 | for (std::unordered_map::iterator obj = _ObjectList.begin(); 69 | obj != _ObjectList.end(); 70 | ++obj) { 71 | obj->second->Validate_simulation_config(); 72 | } 73 | 74 | for (std::unordered_map::iterator obj = _ObjectList.begin(); 75 | obj != _ObjectList.end(); 76 | ++obj) { 77 | obj->second->Start_simulation(); 78 | } 79 | 80 | Sim_Event* ev = NULL; 81 | while (true) { 82 | if (_EventList->Count == 0 || stop) { 83 | //std::cout << " check" << std::endl; 84 | break; 85 | } 86 | 87 | EventTreeNode* minNode = _EventList->Get_min_node(); 88 | ev = minNode->FirstSimEvent; 89 | 90 | _sim_time = ev->Fire_time; 91 | 92 | while (ev != NULL) { 93 | if(!ev->Ignore) { 94 | ev->Target_sim_object->Execute_simulator_event(ev); 95 | } 96 | Sim_Event* consumed_event = ev; 97 | ev = ev->Next_event; 98 | delete consumed_event; 99 | } 100 | _EventList->Remove(minNode); 101 | } 102 | } 103 | 104 | void Engine::Stop_simulation() 105 | { 106 | stop = true; 107 | } 108 | 109 | bool Engine::Has_started() 110 | { 111 | return started; 112 | } 113 | 114 | sim_time_type Engine::Time() 115 | { 116 | return _sim_time; 117 | } 118 | 119 | Sim_Event* Engine::Register_sim_event(sim_time_type fireTime, Sim_Object* targetObject, void* parameters, int type) 120 | { 121 | Sim_Event* ev = new Sim_Event(fireTime, targetObject, parameters, type); 122 | DEBUG("RegisterEvent " << fireTime << " " << targetObject) 123 | _EventList->Insert_sim_event(ev); 124 | return ev; 125 | } 126 | 127 | void Engine::Ignore_sim_event(Sim_Event* ev) 128 | { 129 | ev->Ignore = true; 130 | } 131 | 132 | bool Engine::Is_integrated_execution_mode() 133 | { 134 | return false; 135 | } 136 | } -------------------------------------------------------------------------------- /src/sim/Engine.h: -------------------------------------------------------------------------------- 1 | #ifndef ENGINE_H 2 | #define ENGINE_H 3 | 4 | #include 5 | #include 6 | #include "Sim_Defs.h" 7 | #include "EventTree.h" 8 | #include "Sim_Object.h" 9 | 10 | 11 | 12 | namespace MQSimEngine { 13 | class Engine 14 | { 15 | friend class EventTree; 16 | public: 17 | Engine() 18 | { 19 | this->_EventList = new EventTree; 20 | started = false; 21 | } 22 | 23 | ~Engine() { 24 | delete _EventList; 25 | } 26 | 27 | static Engine* Instance(); 28 | sim_time_type Time(); 29 | Sim_Event* Register_sim_event(sim_time_type fireTime, Sim_Object* targetObject, void* parameters = NULL, int type = 0); 30 | void Ignore_sim_event(Sim_Event*); 31 | void Reset(); 32 | void AddObject(Sim_Object* obj); 33 | Sim_Object* GetObject(sim_object_id_type object_id); 34 | void RemoveObject(Sim_Object* obj); 35 | void Start_simulation(); 36 | void Stop_simulation(); 37 | bool Has_started(); 38 | bool Is_integrated_execution_mode(); 39 | sim_time_type sim_time_before_PRECOND; 40 | sim_time_type sim_time_before_GC; 41 | private: 42 | sim_time_type _sim_time; 43 | EventTree* _EventList; 44 | std::unordered_map _ObjectList; 45 | bool stop; 46 | bool started; 47 | static Engine* _instance; 48 | }; 49 | } 50 | 51 | #define Simulator MQSimEngine::Engine::Instance() 52 | #endif // !ENGINE_H 53 | -------------------------------------------------------------------------------- /src/sim/EventTree.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_TREE_H 2 | #define EVENT_TREE_H 3 | 4 | #include "Sim_Defs.h" 5 | #include "Sim_Event.h" 6 | 7 | namespace MQSimEngine 8 | { 9 | class EventTreeNode 10 | { 11 | public: 12 | // key provided by the calling class 13 | sim_time_type Key; 14 | // the data or value associated with the key 15 | Sim_Event* FirstSimEvent; 16 | Sim_Event* LastSimEvent; 17 | // color - used to balance the tree 18 | /*RED = 0 , BLACK = 1;*/ 19 | int Color; 20 | // left node 21 | EventTreeNode* Left; 22 | // right node 23 | EventTreeNode* Right; 24 | // parent node 25 | EventTreeNode* Parent; 26 | 27 | EventTreeNode() 28 | { 29 | Color = 0; 30 | Left = NULL; 31 | Right = NULL; 32 | Parent = NULL; 33 | } 34 | }; 35 | 36 | class EventTree 37 | { 38 | public: 39 | EventTree(); 40 | ~EventTree(); 41 | 42 | // the number of nodes contained in the tree 43 | int Count; 44 | // sentinelNode is convenient way of indicating a leaf node. 45 | static EventTreeNode* SentinelNode; 46 | void Add(sim_time_type key, Sim_Event* data); 47 | void RotateLeft(EventTreeNode* x); 48 | void RotateRight(EventTreeNode* x); 49 | Sim_Event* GetData(sim_time_type key); 50 | void Insert_sim_event(Sim_Event* data); 51 | sim_time_type Get_min_key(); 52 | Sim_Event* Get_min_value(); 53 | EventTreeNode* Get_min_node(); 54 | void Remove(sim_time_type key); 55 | void Remove(EventTreeNode* node); 56 | void Remove_min(); 57 | void Clear(); 58 | private: 59 | // the tree 60 | EventTreeNode* rbTree; 61 | // the node that was last found; used to optimize searches 62 | EventTreeNode* lastNodeFound; 63 | void RestoreAfterInsert(EventTreeNode* x); 64 | void Delete(EventTreeNode* z); 65 | void Restore_after_delete(EventTreeNode* x); 66 | }; 67 | } 68 | 69 | #endif // !EVENT_TREE_H 70 | -------------------------------------------------------------------------------- /src/sim/Sim_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFINITIONS_H 2 | #define DEFINITIONS_H 3 | 4 | #define LOG_USER_READ 0 5 | #define LOG_USER_WRITE 0 6 | 7 | #define DEBUG_GC_READ 1 8 | #define PATCH_PRECOND 1 9 | 10 | #define ALIGN_UNIT_SIZE 4 // Flash pand page size / address mapping unit granularity. For example, when nand page size: 16KB and mapping granularity: 4KB, BUFFERING_SCALE_4K should be 4 (16KB/4KB). 11 | #define BUFFERING_SCALE_4K 4 //This value should be same to ALIGN_UNIT_SIZE. 12 | #define try_combine_GCread 1 13 | #define PATCH_SEGMENT_REQ 1 //segment user request into trs 14 | 15 | #define ANLZ_AFTER_PRECOND 1 16 | #define PORTION_PRECOND 2 17 | #define ANLZ_AFTER_GC 1 18 | #define PATCH_SEGMENT_REQ 1 //segment user request into trs 19 | 20 | #define PATCH_ONLINE_CREATE_READ_SUBPG 0 //check online_create_entry_for_reads() 21 | #define STATIC_ALLOC_ONLINE 1 //make read subpg trs in staticaly when first access read (in case no lpa-ppa in table when read) 22 | #define DYNAMIC_ALLOC_ONLINE 0 23 | 24 | #define IGNORE_TIME_STAMP 0// Ignore trace time(request arrival) when use trace-based workload 25 | #define ENQUEUED_REQUEST_NUMBER 1 //When use trace-based, as go up, IOPS go up. 26 | #define DEBUG_GC 0 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | typedef uint64_t sim_time_type; 33 | typedef uint16_t stream_id_type; 34 | typedef sim_time_type data_timestamp_type; 35 | 36 | #define INVALID_TIME 18446744073709551615ULL 37 | #define T0 0 38 | #define INVALID_TIME_STAMP 18446744073709551615ULL 39 | #define MAXIMUM_TIME 18446744073709551615ULL 40 | #define ONE_SECOND 1000000000 41 | typedef std::string sim_object_id_type; 42 | 43 | //__asm int 3;\ exit(1);\ 44 | 45 | #define CurrentTimeStamp Simulator->Time() 46 | #define PRINT_ERROR(MSG) {\ 47 | std::cerr << "ERROR:" ;\ 48 | std::cerr << MSG << std::endl; \ 49 | std::cin.get();\ 50 | while(1);\ 51 | } 52 | #define PRINT_MESSAGE(M) std::cout << M << std::endl; 53 | #define DEBUG(M) //std::cout< 5 | #include "Sim_Event.h" 6 | 7 | namespace MQSimEngine 8 | { 9 | class Sim_Event; 10 | class Sim_Object 11 | { 12 | public: 13 | Sim_Object(const sim_object_id_type &id) 14 | { 15 | _id = id; 16 | _triggersSetUp = false; 17 | } 18 | 19 | sim_object_id_type ID() 20 | { 21 | return this->_id; 22 | } 23 | 24 | bool IsTriggersSetUp() 25 | { 26 | return _triggersSetUp; 27 | } 28 | 29 | //The Start function is invoked at the start phase of simulation to perform initialization 30 | virtual void Start_simulation() = 0; 31 | 32 | //The Validate_simulation_config function is invoked to check if the objected is correctly configured or not. 33 | virtual void Validate_simulation_config() = 0; 34 | 35 | //The object connects its internal functions to the outside triggering events from other objects 36 | virtual void Setup_triggers() 37 | { 38 | _triggersSetUp = true; 39 | } 40 | 41 | virtual void Execute_simulator_event(Sim_Event*) = 0; 42 | 43 | private: 44 | sim_object_id_type _id; 45 | bool _triggersSetUp; 46 | }; 47 | } 48 | 49 | #endif // !SIMULATOR_OBJECT_H 50 | -------------------------------------------------------------------------------- /src/sim/Sim_Reporter.h: -------------------------------------------------------------------------------- 1 | #ifndef SIM_REPORTER_H 2 | #define SIM_REPORTER_H 3 | 4 | #include "../utils/XMLWriter.h" 5 | #include 6 | 7 | namespace MQSimEngine 8 | { 9 | class Sim_Reporter 10 | { 11 | public: 12 | virtual void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter) = 0; 13 | }; 14 | } 15 | 16 | #endif // !SIM_REPORTER_H 17 | -------------------------------------------------------------------------------- /src/ssd/Address_Mapping_Unit_Base.cpp: -------------------------------------------------------------------------------- 1 | #include "FTL.h" 2 | #include "Address_Mapping_Unit_Base.h" 3 | #include "NVM_PHY_ONFI_NVDDR2.h" 4 | #include "Flash_Block_Manager_Base.h" 5 | 6 | namespace SSD_Components 7 | { 8 | Address_Mapping_Unit_Base::Address_Mapping_Unit_Base(const sim_object_id_type& id, FTL* ftl, NVM_PHY_ONFI* flash_controller, Flash_Block_Manager_Base* block_manager, 9 | bool ideal_mapping_table, unsigned int no_of_input_streams, 10 | unsigned int ChannelCount, unsigned int chip_no_per_channel, unsigned int DieNoPerChip, unsigned int PlaneNoPerDie, 11 | unsigned int Block_no_per_plane, unsigned int Page_no_per_block, unsigned int SectorsPerPage, unsigned int PageSizeInBytes, 12 | double Overprovisioning_ratio, CMT_Sharing_Mode sharing_mode, bool fold_large_addresses) 13 | : Sim_Object(id), ftl(ftl), flash_controller(flash_controller), block_manager(block_manager), 14 | ideal_mapping_table(ideal_mapping_table), no_of_input_streams(no_of_input_streams), 15 | channel_count(ChannelCount), chip_no_per_channel(chip_no_per_channel), die_no_per_chip(DieNoPerChip), plane_no_per_die(PlaneNoPerDie), 16 | block_no_per_plane(Block_no_per_plane), pages_no_per_block(Page_no_per_block), sector_no_per_page(SectorsPerPage), page_size_in_byte(PageSizeInBytes), 17 | overprovisioning_ratio(Overprovisioning_ratio), sharing_mode(sharing_mode), fold_large_addresses(fold_large_addresses), 18 | mapping_table_stored_on_flash(false) 19 | { 20 | page_no_per_plane = pages_no_per_block * block_no_per_plane; 21 | page_no_per_die = page_no_per_plane * plane_no_per_die; 22 | page_no_per_chip = page_no_per_die * die_no_per_chip; 23 | page_no_per_channel = page_no_per_chip * chip_no_per_channel; 24 | total_physical_pages_no = page_no_per_channel * ChannelCount; 25 | 26 | total_logical_pages_no = (unsigned int)((double)total_physical_pages_no * (1 - overprovisioning_ratio)); 27 | max_logical_sector_address = (LHA_type)(SectorsPerPage * total_logical_pages_no - 1); 28 | } 29 | 30 | Address_Mapping_Unit_Base::~Address_Mapping_Unit_Base() 31 | { 32 | } 33 | 34 | unsigned int Address_Mapping_Unit_Base::Get_device_physical_pages_count() 35 | { 36 | return total_physical_pages_no; 37 | } 38 | 39 | bool Address_Mapping_Unit_Base::Is_ideal_mapping_table() 40 | { 41 | return ideal_mapping_table; 42 | } 43 | 44 | CMT_Sharing_Mode Address_Mapping_Unit_Base::Get_CMT_sharing_mode() 45 | { 46 | return sharing_mode; 47 | } 48 | } -------------------------------------------------------------------------------- /src/ssd/Address_Mapping_Unit_Hybrid.h: -------------------------------------------------------------------------------- 1 | #ifndef ADDRESS_MAPPING_UNIT_HYBRID_H 2 | #define ADDRESS_MAPPING_UNIT_HYBRID_H 3 | 4 | #include "Address_Mapping_Unit_Base.h" 5 | 6 | namespace SSD_Components 7 | { 8 | class Address_Mapping_Unit_Hybrid : public Address_Mapping_Unit_Base 9 | { 10 | public: 11 | Address_Mapping_Unit_Hybrid(sim_object_id_type id, FTL* ftl, NVM_PHY_ONFI* flash_controller, Flash_Block_Manager_Base* block_manager, 12 | bool ideal_mapping_table, unsigned int ConcurrentStreamNo, 13 | unsigned int ChannelCount, unsigned int chip_no_per_channel, unsigned int DieNoPerChip, unsigned int PlaneNoPerDie, 14 | unsigned int Block_no_per_plane, unsigned int Page_no_per_block, unsigned int SectorsPerPage, unsigned int PageSizeInBytes, 15 | double Overprovisioning_ratio, CMT_Sharing_Mode sharing_mode = CMT_Sharing_Mode::SHARED, bool fold_large_addresses = true); 16 | void Setup_triggers(); 17 | void Start_simulation(); 18 | void Validate_simulation_config(); 19 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 20 | 21 | void Allocate_address_for_preconditioning(const stream_id_type stream_id, std::map& lpa_list, std::vector& steady_state_distribution); 22 | int Bring_to_CMT_for_preconditioning(stream_id_type stream_id, LPA_type lpa); 23 | unsigned int Get_cmt_capacity(); 24 | unsigned int Get_current_cmt_occupancy_for_stream(stream_id_type stream_id); 25 | int Translate_lpa_to_ppa_and_dispatch( std::list& transactionList, User_Request* user_request, unsigned int* back_pressure_buffer_depth); 26 | void Get_data_mapping_info_for_gc(const stream_id_type stream_id, const LPA_type lpa, PPA_type& ppa, page_status_type& page_state); 27 | void Get_translation_mapping_info_for_gc(const stream_id_type stream_id, const MVPN_type mvpn, MPPN_type& mppa, sim_time_type& timestamp); 28 | void Allocate_new_page_for_gc(NVM_Transaction_Flash_WR* transaction, bool is_translation_page); 29 | void Allocate_dummy_pages_for_gc(NVM_Transaction_Flash_WR* transaction, bool is_translation_page, bool align); 30 | 31 | void Store_mapping_table_on_flash_at_start(); 32 | LPA_type Get_logical_pages_count(stream_id_type stream_id); 33 | NVM::FlashMemory::Physical_Page_Address Convert_ppa_to_address(const PPA_type ppa); 34 | void Convert_ppa_to_address(const PPA_type ppn, NVM::FlashMemory::Physical_Page_Address& address); 35 | PPA_type Convert_address_to_ppa(const NVM::FlashMemory::Physical_Page_Address& pageAddress); 36 | 37 | void Set_barrier_for_accessing_physical_block(const NVM::FlashMemory::Physical_Page_Address& block_address); 38 | void Set_barrier_for_accessing_lpa(stream_id_type stream_id, LPA_type lpa); 39 | void Set_barrier_for_accessing_mvpn(stream_id_type stream_id, MVPN_type mpvn); 40 | void Remove_barrier_for_accessing_lpa(stream_id_type stream_id, LPA_type lpa); 41 | void Remove_barrier_for_accessing_mvpn(stream_id_type stream_id, MVPN_type mpvn); 42 | void Start_servicing_writes_for_overfull_plane(const NVM::FlashMemory::Physical_Page_Address plane_address); 43 | int Start_servicing_writes_for_overfull(); 44 | private: 45 | bool query_cmt(NVM_Transaction_Flash* transaction); 46 | PPA_type online_create_entry_for_reads(LPA_type lpa, const stream_id_type stream_id, NVM::FlashMemory::Physical_Page_Address& read_address, uint64_t read_sectors_bitmap); 47 | void manage_user_transaction_facing_barrier(NVM_Transaction_Flash* transaction); 48 | void manage_mapping_transaction_facing_barrier(stream_id_type stream_id, MVPN_type mvpn, bool read); 49 | bool is_lpa_locked_for_gc(stream_id_type stream_id, LPA_type lpa); 50 | bool is_mvpn_locked_for_gc(stream_id_type stream_id, MVPN_type mvpn); 51 | }; 52 | } 53 | 54 | #endif // !ADDRESS_MAPPING_UNIT_HYBRID_H 55 | -------------------------------------------------------------------------------- /src/ssd/Data_Cache_Flash.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_CACHE_FLASH_H 2 | #define DATA_CACHE_FLASH_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../nvm_chip/flash_memory/FlashTypes.h" 8 | #include "SSD_Defs.h" 9 | #include "Data_Cache_Manager_Base.h" 10 | #include "NVM_Transaction_Flash.h" 11 | 12 | namespace SSD_Components 13 | { 14 | enum class Cache_Slot_Status { EMPTY, CLEAN, DIRTY_NO_FLASH_WRITEBACK, DIRTY_FLASH_WRITEBACK }; 15 | struct Data_Cache_Slot_Type 16 | { 17 | unsigned long long State_bitmap_of_existing_sectors; 18 | LPA_type LPA; 19 | data_cache_content_type Content; 20 | data_timestamp_type Timestamp; 21 | Cache_Slot_Status Status; 22 | std::list>::iterator lru_list_ptr;//used for fast implementation of LRU 23 | }; 24 | 25 | enum class Data_Cache_Simulation_Event_Type { 26 | MEMORY_READ_FOR_CACHE_EVICTION_FINISHED, 27 | MEMORY_WRITE_FOR_CACHE_FINISHED, 28 | MEMORY_READ_FOR_USERIO_FINISHED, 29 | MEMORY_WRITE_FOR_USERIO_FINISHED 30 | }; 31 | 32 | struct Memory_Transfer_Info 33 | { 34 | unsigned int Size_in_bytes; 35 | void* Related_request; 36 | Data_Cache_Simulation_Event_Type next_event_type; 37 | stream_id_type Stream_id; 38 | }; 39 | 40 | class Data_Cache_Flash 41 | { 42 | public: 43 | Data_Cache_Flash(unsigned int capacity_in_pages = 0); 44 | ~Data_Cache_Flash(); 45 | bool Exists(const stream_id_type streamID, const LPA_type lpn); 46 | bool Check_free_slot_availability(); 47 | bool Check_free_slot_availability(unsigned int no_of_slots); 48 | bool Empty(); 49 | bool Full(); 50 | Data_Cache_Slot_Type Get_slot(const stream_id_type stream_id, const LPA_type lpn); 51 | Data_Cache_Slot_Type Evict_one_dirty_slot(); 52 | Data_Cache_Slot_Type Evict_one_slot_lru(); 53 | void Change_slot_status_to_writeback(const stream_id_type stream_id, const LPA_type lpn); 54 | void Remove_slot(const stream_id_type stream_id, const LPA_type lpn); 55 | void Insert_read_data(const stream_id_type stream_id, const LPA_type lpn, const data_cache_content_type content, const data_timestamp_type timestamp, const page_status_type state_bitmap_of_read_sectors); 56 | void Insert_write_data(const stream_id_type stream_id, const LPA_type lpn, const data_cache_content_type content, const data_timestamp_type timestamp, const page_status_type state_bitmap_of_write_sectors); 57 | void Update_data(const stream_id_type stream_id, const LPA_type lpn, const data_cache_content_type content, const data_timestamp_type timestamp, const page_status_type state_bitmap_of_write_sectors); 58 | private: 59 | std::unordered_map slots; 60 | std::list> lru_list; 61 | unsigned int capacity_in_pages; 62 | }; 63 | } 64 | 65 | #endif // !DATA_CACHE_FLASH_H 66 | -------------------------------------------------------------------------------- /src/ssd/Data_Cache_Manager_Base.cpp: -------------------------------------------------------------------------------- 1 | #include "Data_Cache_Manager_Base.h" 2 | #include "FTL.h" 3 | 4 | namespace SSD_Components 5 | { 6 | Data_Cache_Manager_Base* Data_Cache_Manager_Base::_my_instance = NULL; 7 | Caching_Mode* Data_Cache_Manager_Base::caching_mode_per_input_stream; 8 | 9 | Data_Cache_Manager_Base::Data_Cache_Manager_Base(const sim_object_id_type& id, Host_Interface_Base* host_interface, NVM_Firmware* nvm_firmware, 10 | unsigned int dram_row_size, unsigned int dram_data_rate, unsigned int dram_busrt_size, sim_time_type dram_tRCD, sim_time_type dram_tCL, sim_time_type dram_tRP, 11 | Caching_Mode* caching_mode_per_input_stream, Cache_Sharing_Mode sharing_mode, unsigned int stream_count) 12 | : MQSimEngine::Sim_Object(id), host_interface(host_interface), nvm_firmware(nvm_firmware), 13 | dram_row_size(dram_row_size), dram_data_rate(dram_data_rate), dram_busrt_size(dram_busrt_size), dram_tRCD(dram_tRCD), dram_tCL(dram_tCL), dram_tRP(dram_tRP), 14 | sharing_mode(sharing_mode), stream_count(stream_count) 15 | { 16 | _my_instance = this; 17 | dram_burst_transfer_time_ddr = (double) ONE_SECOND / (dram_data_rate * 1000 * 1000); 18 | this->caching_mode_per_input_stream = new Caching_Mode[stream_count]; 19 | for (unsigned int i = 0; i < stream_count; i++) { 20 | this->caching_mode_per_input_stream[i] = caching_mode_per_input_stream[i]; 21 | } 22 | } 23 | 24 | Data_Cache_Manager_Base::~Data_Cache_Manager_Base() {} 25 | 26 | void Data_Cache_Manager_Base::Setup_triggers() 27 | { 28 | Sim_Object::Setup_triggers(); 29 | host_interface->Connect_to_user_request_arrived_signal(handle_user_request_arrived_signal); 30 | } 31 | 32 | void Data_Cache_Manager_Base::Start_simulation() {} 33 | 34 | void Data_Cache_Manager_Base::Validate_simulation_config() {} 35 | 36 | void Data_Cache_Manager_Base::Connect_to_user_request_serviced_signal(UserRequestServicedSignalHanderType function) 37 | { 38 | connected_user_request_serviced_signal_handlers.push_back(function); 39 | } 40 | 41 | void Data_Cache_Manager_Base::broadcast_user_request_serviced_signal(User_Request* nvm_transaction) 42 | { 43 | for (std::vector::iterator it = connected_user_request_serviced_signal_handlers.begin(); 44 | it != connected_user_request_serviced_signal_handlers.end(); it++) { 45 | (*it)(nvm_transaction); 46 | } 47 | } 48 | 49 | void Data_Cache_Manager_Base::Connect_to_user_memory_transaction_serviced_signal(MemoryTransactionServicedSignalHanderType function) 50 | { 51 | connected_user_memory_transaction_serviced_signal_handlers.push_back(function); 52 | } 53 | 54 | void Data_Cache_Manager_Base::broadcast_user_memory_transaction_serviced_signal(NVM_Transaction* transaction) 55 | { 56 | for (std::vector::iterator it = connected_user_memory_transaction_serviced_signal_handlers.begin(); 57 | it != connected_user_memory_transaction_serviced_signal_handlers.end(); it++) { 58 | (*it)(transaction); 59 | } 60 | } 61 | 62 | void Data_Cache_Manager_Base::handle_user_request_arrived_signal(User_Request* user_request) 63 | { 64 | _my_instance->process_new_user_request(user_request); 65 | } 66 | 67 | void Data_Cache_Manager_Base::Set_host_interface(Host_Interface_Base* host_interface) 68 | { 69 | this->host_interface = host_interface; 70 | } 71 | 72 | void Data_Cache_Manager_Base::Set_cxl_host_interface(Host_Interface_Base* host_interface) { 73 | this->cxl_host_interface = cxl_host_interface; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/ssd/Data_Cache_Manager_Flash_Advanced.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_CACHE_MANAGER_FLASH_ADVANCED_H 2 | #define DATA_CACHE_MANAGER_FLASH_ADVANCED_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../nvm_chip/flash_memory/FlashTypes.h" 8 | #include "SSD_Defs.h" 9 | #include "Data_Cache_Manager_Base.h" 10 | #include "Data_Cache_Flash.h" 11 | #include "NVM_Transaction_Flash.h" 12 | 13 | namespace SSD_Components 14 | { 15 | /* 16 | Assumed hardware structure: 17 | waiting_user_requests_queue_for_dram_free_slot (a user write request is enqueued into this queue if DRAM is full. For a user read request, there is no need for DRAM free slot and thus no queue.) 18 | | 19 | | 20 | \|/ 21 | dram_execution_queue (the transfer request goes here if DRAM can service it but the memory channel is busy) 22 | | 23 | | 24 | \|/ 25 | --------------------------------------------------|------------------------ 26 | | DRAM Data_Cache_Flash Main Data Space | Back Pressure Space | ---------->To the flash backend 27 | --------------------------------------------------|------------------------ 28 | */ 29 | class Data_Cache_Manager_Flash_Advanced : public Data_Cache_Manager_Base 30 | { 31 | public: 32 | Data_Cache_Manager_Flash_Advanced(const sim_object_id_type& id, Host_Interface_Base* host_interface, NVM_Firmware* firmware, NVM_PHY_ONFI* flash_controller, 33 | unsigned int total_capacity_in_bytes, 34 | unsigned int dram_row_size, unsigned int dram_data_rate, unsigned int dram_busrt_size, sim_time_type dram_tRCD, sim_time_type dram_tCL, sim_time_type dram_tRP, 35 | Caching_Mode* caching_mode_per_input_stream, Cache_Sharing_Mode sharing_mode, 36 | unsigned int stream_count, unsigned int sector_no_per_page, unsigned int back_pressure_buffer_max_depth, unsigned int flush_unit_count); 37 | ~Data_Cache_Manager_Flash_Advanced(); 38 | void Execute_simulator_event(MQSimEngine::Sim_Event* ev); 39 | void Setup_triggers(); 40 | void Do_warmup(std::vector workload_stats); 41 | unsigned int* back_pressure_buffer_depth; 42 | private: 43 | NVM_PHY_ONFI * flash_controller; 44 | unsigned int capacity_in_bytes, capacity_in_pages; 45 | unsigned int sector_no_per_page; 46 | Data_Cache_Flash** per_stream_cache; 47 | bool memory_channel_is_busy; 48 | 49 | void process_new_user_request(User_Request* user_request); 50 | void write_to_destage_buffer(User_Request* user_request);//Used in the WRITE_CACHE and WRITE_READ_CACHE modes in which the DRAM space is used as a destage buffer 51 | std::queue* dram_execution_queue;//The list of DRAM transfers that are waiting to be executed 52 | std::list* waiting_user_requests_queue_for_dram_free_slot;//The list of user requests that are waiting for free space in DRAM 53 | std::list* waiting_writeback_transactions; 54 | 55 | bool shared_dram_request_queue; 56 | int dram_execution_list_turn; 57 | unsigned int back_pressure_buffer_max_depth; 58 | //unsigned int *back_pressure_buffer_depth; 59 | std::set* bloom_filter; 60 | sim_time_type bloom_filter_reset_step = 1000000000; 61 | sim_time_type next_bloom_filter_reset_milestone = 0; 62 | unsigned int flush_unit_count; 63 | static void handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction); 64 | void service_dram_access_request(Memory_Transfer_Info* request_info); 65 | }; 66 | } 67 | 68 | #endif // !DATA_CACHE_MANAGER_FLASH_ADVANCED_H 69 | -------------------------------------------------------------------------------- /src/ssd/Data_Cache_Manager_Flash_Simple.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_CACHE_MANAGER_FLASH_SIMPLE_H 2 | #define DATA_CACHE_MANAGER_FLASH_SIMPLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../nvm_chip/flash_memory/FlashTypes.h" 8 | #include "SSD_Defs.h" 9 | #include "Data_Cache_Manager_Base.h" 10 | #include "Data_Cache_Flash.h" 11 | #include "NVM_Transaction_Flash.h" 12 | 13 | namespace SSD_Components 14 | { 15 | class Data_Cache_Manager_Flash_Simple : public Data_Cache_Manager_Base 16 | { 17 | public: 18 | Data_Cache_Manager_Flash_Simple(const sim_object_id_type& id, Host_Interface_Base* host_interface, NVM_Firmware* firmware, NVM_PHY_ONFI* flash_controller, 19 | unsigned int total_capacity_in_bytes, 20 | unsigned int dram_row_size, unsigned int dram_data_rate, unsigned int dram_busrt_size, sim_time_type dram_tRCD, sim_time_type dram_tCL, sim_time_type dram_tRP, 21 | Caching_Mode* caching_mode_per_input_stream, unsigned int stream_count, unsigned int sector_no_per_page, unsigned int back_pressure_buffer_max_depth); 22 | ~Data_Cache_Manager_Flash_Simple(); 23 | void Execute_simulator_event(MQSimEngine::Sim_Event* ev); 24 | void Setup_triggers(); 25 | void Do_warmup(std::vector workload_stats); 26 | private: 27 | NVM_PHY_ONFI * flash_controller; 28 | unsigned int capacity_in_bytes, capacity_in_pages; 29 | unsigned int sector_no_per_page; 30 | Data_Cache_Flash* data_cache; 31 | 32 | void process_new_user_request(User_Request* user_request); 33 | void write_to_destage_buffer(User_Request* user_request);//Used in the WRITE_CACHE and WRITE_READ_CACHE modes in which the DRAM space is used as a destage buffer 34 | std::queue* dram_execution_queue;//The list of DRAM transfers that are waiting to be executed 35 | std::list* waiting_user_requests_queue_for_dram_free_slot;//The list of user requests that are waiting for free space in DRAM 36 | int request_queue_turn; 37 | unsigned int back_pressure_buffer_max_depth; 38 | unsigned int back_pressure_buffer_depth; 39 | std::set* bloom_filter; 40 | sim_time_type bloom_filter_reset_step = 1000000000; 41 | sim_time_type next_bloom_filter_reset_milestone = 0; 42 | 43 | static void handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction); 44 | void service_dram_access_request(Memory_Transfer_Info* request_info); 45 | }; 46 | } 47 | 48 | #endif // !DATA_CACHE_MANAGER_FLASH_SIMPLE_H 49 | -------------------------------------------------------------------------------- /src/ssd/FTL.h: -------------------------------------------------------------------------------- 1 | #ifndef FTL_H 2 | #define FTL_H 3 | 4 | #include "../sim/Sim_Reporter.h" 5 | #include "../utils/RandomGenerator.h" 6 | #include "NVM_Firmware.h" 7 | #include "TSU_Base.h" 8 | #include "Address_Mapping_Unit_Base.h" 9 | #include "Flash_Block_Manager_Base.h" 10 | #include "GC_and_WL_Unit_Base.h" 11 | #include "NVM_PHY_ONFI.h" 12 | #include "Stats.h" 13 | 14 | namespace SSD_Components 15 | { 16 | enum class SimulationMode { STANDALONE, FULL_SYSTEM }; 17 | 18 | class Flash_Block_Manager_Base; 19 | class Address_Mapping_Unit_Base; 20 | class GC_and_WL_Unit_Base; 21 | class TSU_Base; 22 | 23 | class FTL : public NVM_Firmware 24 | { 25 | public: 26 | FTL(const sim_object_id_type& id, Data_Cache_Manager_Base* data_cache, 27 | unsigned int channel_no, unsigned int chip_no_per_channel, unsigned int die_no_per_chip, unsigned int plane_no_per_die, 28 | unsigned int block_no_per_plane, unsigned int page_no_per_block, unsigned int page_size_in_sectors, 29 | sim_time_type avg_flash_read_latency, sim_time_type avg_flash_program_latency, double over_provisioning_ratio, unsigned int max_allowed_block_erase_count, int seed, unsigned int info); 30 | ~FTL(); 31 | void Perform_precondition(std::vector workload_stats); 32 | void Validate_simulation_config(); 33 | void Start_simulation(); 34 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 35 | LPA_type Convert_host_logical_address_to_device_address(LHA_type lha); 36 | page_status_type Find_NVM_subunit_access_bitmap(LHA_type lha); 37 | Address_Mapping_Unit_Base* Address_Mapping_Unit; 38 | Flash_Block_Manager_Base* BlockManager; 39 | GC_and_WL_Unit_Base* GC_and_WL_Unit; 40 | TSU_Base * TSU; 41 | NVM_PHY_ONFI* PHY; 42 | void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 43 | private: 44 | unsigned int channel_no, chip_no_per_channel, die_no_per_chip, plane_no_per_die; 45 | unsigned int block_no_per_plane, page_no_per_block, page_size_in_sectors; 46 | unsigned int max_allowed_block_erase_count; 47 | int preconditioning_seed; 48 | Utils::RandomGenerator random_generator; 49 | double over_provisioning_ratio; 50 | sim_time_type avg_flash_read_latency; 51 | sim_time_type avg_flash_program_latency; 52 | }; 53 | } 54 | 55 | #endif // !FTL_H 56 | -------------------------------------------------------------------------------- /src/ssd/Flash_Block_Manager.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASH_BLOCK_MANAGER_H 2 | #define FLASH_BLOCK_MANAGER_H 3 | 4 | #include 5 | #include "Flash_Block_Manager_Base.h" 6 | #include "../nvm_chip/flash_memory/FlashTypes.h" 7 | #include "../nvm_chip/flash_memory/Physical_Page_Address.h" 8 | 9 | namespace SSD_Components 10 | { 11 | class Flash_Block_Manager : public Flash_Block_Manager_Base 12 | { 13 | public: 14 | Flash_Block_Manager(GC_and_WL_Unit_Base* gc_and_wl_unit, unsigned int max_allowed_block_erase_count, unsigned int total_concurrent_streams_no, 15 | unsigned int channel_count, unsigned int chip_no_per_channel, unsigned int die_no_per_chip, unsigned int plane_no_per_die, 16 | unsigned int block_no_per_plane, unsigned int page_no_per_block); 17 | ~Flash_Block_Manager(); 18 | void Allocate_block_and_page_in_plane_for_user_write(const stream_id_type stream_id, NVM::FlashMemory::Physical_Page_Address& address); 19 | void Allocate_block_and_page_in_plane_for_gc_write(const stream_id_type stream_id, NVM::FlashMemory::Physical_Page_Address& address); 20 | void Allocate_Pages_in_block_and_invalidate_remaining_for_preconditioning(const stream_id_type stream_id, const NVM::FlashMemory::Physical_Page_Address& plane_address, std::vector& page_addresses); 21 | void Allocate_block_and_page_in_plane_for_translation_write(const stream_id_type stream_id, NVM::FlashMemory::Physical_Page_Address& address, bool is_for_gc); 22 | void Invalidate_page_in_block(const stream_id_type streamID, const NVM::FlashMemory::Physical_Page_Address& address); 23 | void Invalidate_subpage_in_block(const stream_id_type streamID, const NVM::FlashMemory::Physical_Page_Address& address); 24 | void Invalidate_page_in_block_for_preconditioning(const stream_id_type streamID, const NVM::FlashMemory::Physical_Page_Address& address); 25 | void Invalidate_subpage_in_block_for_preconditioning(const stream_id_type streamID, const NVM::FlashMemory::Physical_Page_Address& address); 26 | void Add_erased_block_to_pool(const NVM::FlashMemory::Physical_Page_Address& address); 27 | unsigned int Get_pool_size(const NVM::FlashMemory::Physical_Page_Address& plane_address); 28 | private: 29 | }; 30 | } 31 | 32 | #endif // !FLASH_BLOCK_MANAGER_H 33 | -------------------------------------------------------------------------------- /src/ssd/Flash_Transaction_Queue.cpp: -------------------------------------------------------------------------------- 1 | #include "Flash_Transaction_Queue.h" 2 | 3 | namespace SSD_Components 4 | { 5 | Flash_Transaction_Queue::Flash_Transaction_Queue() {} 6 | 7 | Flash_Transaction_Queue::Flash_Transaction_Queue(std::string id) : id(id) 8 | { 9 | } 10 | 11 | void Flash_Transaction_Queue::Set_id(std::string id) 12 | { 13 | this->id = id; 14 | } 15 | 16 | void Flash_Transaction_Queue::push_back(NVM_Transaction_Flash* const& transaction) 17 | { 18 | RequestQueueProbe.EnqueueRequest(transaction); 19 | return list::push_back(transaction); 20 | } 21 | 22 | void Flash_Transaction_Queue::push_front(NVM_Transaction_Flash* const& transaction) 23 | { 24 | RequestQueueProbe.EnqueueRequest(transaction); 25 | return list::push_front(transaction); 26 | } 27 | 28 | std::list::iterator Flash_Transaction_Queue::insert(list::iterator position, NVM_Transaction_Flash* const& transaction) 29 | { 30 | RequestQueueProbe.EnqueueRequest(transaction); 31 | return list::insert(position, transaction); 32 | } 33 | 34 | void Flash_Transaction_Queue::remove(NVM_Transaction_Flash* const& transaction) 35 | { 36 | RequestQueueProbe.DequeueRequest(transaction); 37 | return list::remove(transaction); 38 | } 39 | 40 | void Flash_Transaction_Queue::remove(std::list::iterator const& itr_pos) 41 | { 42 | RequestQueueProbe.DequeueRequest(*itr_pos); 43 | list::erase(itr_pos); 44 | } 45 | 46 | void Flash_Transaction_Queue::pop_front() 47 | { 48 | RequestQueueProbe.DequeueRequest(this->front()); 49 | list::pop_front(); 50 | } 51 | 52 | void Flash_Transaction_Queue::Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter) 53 | { 54 | std::string tmp = name_prefix; 55 | xmlwriter.Write_start_element_tag(tmp); 56 | 57 | std::string attr = "Name"; 58 | std::string val = id; 59 | xmlwriter.Write_attribute_string_inline(attr, val); 60 | 61 | attr = "No_Of_Transactions_Enqueued"; 62 | val = std::to_string(RequestQueueProbe.NRequests()); 63 | xmlwriter.Write_attribute_string_inline(attr, val); 64 | 65 | attr = "No_Of_Transactions_Dequeued"; 66 | val = std::to_string(RequestQueueProbe.NDepartures()); 67 | xmlwriter.Write_attribute_string_inline(attr, val); 68 | 69 | attr = "Avg_Queue_Length"; 70 | val = std::to_string(RequestQueueProbe.AvgQueueLength()); 71 | xmlwriter.Write_attribute_string_inline(attr, val); 72 | 73 | attr = "Max_Queue_Length"; 74 | val = std::to_string(RequestQueueProbe.MaxQueueLength()); 75 | xmlwriter.Write_attribute_string_inline(attr, val); 76 | 77 | attr = "STDev_Queue_Length"; 78 | val = std::to_string(RequestQueueProbe.STDevQueueLength()); 79 | xmlwriter.Write_attribute_string_inline(attr, val); 80 | 81 | attr = "Avg_Transaction_Waiting_Time"; 82 | val = std::to_string(RequestQueueProbe.AvgWaitingTime()); 83 | xmlwriter.Write_attribute_string_inline(attr, val); 84 | 85 | attr = "Max_Transaction_Waiting_Time"; 86 | val = std::to_string(RequestQueueProbe.MaxWaitingTime()); 87 | xmlwriter.Write_attribute_string_inline(attr, val); 88 | 89 | xmlwriter.Write_end_element_tag(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/ssd/Flash_Transaction_Queue.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASH_TRANSACTION_QUEUE_H 2 | #define FLASH_TRANSACTION_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include "NVM_Transaction_Flash.h" 7 | #include "Queue_Probe.h" 8 | #include "../sim/Sim_Reporter.h" 9 | 10 | namespace SSD_Components 11 | { 12 | class Flash_Transaction_Queue : public std::list, public MQSimEngine::Sim_Reporter 13 | { 14 | public: 15 | Flash_Transaction_Queue(); 16 | Flash_Transaction_Queue(std::string id); 17 | void Set_id(std::string id); 18 | void push_back(NVM_Transaction_Flash* const&); 19 | void push_front(NVM_Transaction_Flash* const&); 20 | std::list::iterator insert(list::iterator position, NVM_Transaction_Flash* const& transaction); 21 | void remove(NVM_Transaction_Flash* const& transaction); 22 | void remove(std::list::iterator const& itr_pos); 23 | void pop_front(); 24 | void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 25 | private: 26 | std::string id; 27 | Queue_Probe RequestQueueProbe; 28 | }; 29 | } 30 | 31 | #endif // !FLASH_TRANSACTION_QUEUE_H 32 | -------------------------------------------------------------------------------- /src/ssd/GC_and_WL_Unit_Page_Level.h: -------------------------------------------------------------------------------- 1 | #ifndef GC_AND_WL_UNIT_PAGE_LEVEL_H 2 | #define GC_AND_WL_UNIT_PAGE_LEVEL_H 3 | 4 | #include "GC_and_WL_Unit_Base.h" 5 | #include "NVM_PHY_ONFI.h" 6 | #include "../utils/RandomGenerator.h" 7 | #include 8 | 9 | 10 | namespace SSD_Components 11 | { 12 | enum class GCStatus{ IDLE, READ_STATE, WRITE_STATE}; 13 | 14 | class GC_and_WL_Unit_Page_Level : public GC_and_WL_Unit_Base 15 | { 16 | public: 17 | GC_and_WL_Unit_Page_Level(const sim_object_id_type& id, 18 | Address_Mapping_Unit_Base* address_mapping_unit, Flash_Block_Manager_Base* block_manager, TSU_Base* tsu, NVM_PHY_ONFI* flash_controller, 19 | GC_Block_Selection_Policy_Type block_selection_policy, double gc_threshold, bool preemptible_gc_enabled, double gc_hard_threshold, 20 | unsigned int channel_count, unsigned int chip_no_per_channel, unsigned int die_no_per_chip, unsigned int plane_no_per_die, 21 | unsigned int block_no_per_plane, unsigned int page_no_per_block, unsigned int sectors_per_page, 22 | bool use_copyback, double rho, unsigned int max_ongoing_gc_reqs_per_plane = 10, 23 | bool dynamic_wearleveling_enabled = true, bool static_wearleveling_enabled = true, unsigned int static_wearleveling_threshold = 100, int seed = 432); 24 | 25 | /*This function is used for implementing preemptible GC execution. If for a flash chip the free block 26 | * pool becomes close to empty, then the GC requests for that flash chip should be prioritized and 27 | * GC should go on in non-preemptible mode.*/ 28 | bool GC_is_in_urgent_mode(const NVM::FlashMemory::Flash_Chip*); 29 | 30 | void Check_gc_required(const unsigned int free_block_pool_size, const NVM::FlashMemory::Physical_Page_Address& plane_address); 31 | bool has_valid_subpg(flash_channel_ID_type ChannelID, flash_chip_ID_type ChipID, flash_die_ID_type DieID, flash_plane_ID_type PlaneID, flash_block_ID_type block_id, flash_page_ID_type page_id); 32 | int count_valid_pages_in_block(const NVM::FlashMemory::Physical_Page_Address& block_address, int page_no_per_block); 33 | 34 | private: 35 | NVM_PHY_ONFI * flash_controller; 36 | GCStatus gc_status; 37 | 38 | static const int weighted_moving_average_N = 5; 39 | int saturation_criteria_count; 40 | double saturation_criteria_delta; 41 | double minimum_mode_difference; 42 | 43 | double weight[weighted_moving_average_N]; 44 | bool is_saturated; 45 | bool prev_saturation_status; 46 | int cumulative_count; 47 | int WAF_transiaction_period; 48 | int saturation_start_index; 49 | 50 | int get_valid_page_count(flash_block_ID_type block_id); 51 | int get_valid_subpage_count(flash_block_ID_type block_id); 52 | int select_victim_block(); 53 | int read_pages(); 54 | int write_pages(); 55 | bool is_WAF_saturated(double& diff); 56 | void select_relief_mode(); 57 | 58 | std::list waiting_submit_transaction; //used for combine transactions (mapping granularity) into big transaction (NAND PAGE granularity) 59 | 60 | }; 61 | } 62 | #endif // !GC_AND_WL_UNIT_PAGE_LEVEL_H 63 | -------------------------------------------------------------------------------- /src/ssd/Host_Interface_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef NVME_DEFINITIONS_H 2 | #define NVME_DEFINITIONS_H 3 | 4 | #include 5 | 6 | enum class IO_Flow_Priority_Class { URGENT = 1, HIGH = 2, MEDIUM = 3, LOW = 4}; 7 | enum class HostInterface_Types { SATA, NVME }; 8 | 9 | #define NVME_FLUSH_OPCODE 0x0000 10 | #define NVME_WRITE_OPCODE 0x0001 11 | #define NVME_READ_OPCODE 0x0002 12 | 13 | #define SATA_WRITE_OPCODE 0x0001 14 | #define SATA_READ_OPCODE 0x0002 15 | 16 | const uint64_t NCQ_SUBMISSION_REGISTER = 0x1000; 17 | const uint64_t NCQ_COMPLETION_REGISTER = 0x1003; 18 | const uint64_t SUBMISSION_QUEUE_REGISTER_0 = 0x1000; 19 | const uint64_t COMPLETION_QUEUE_REGISTER_0 = 0x1003; 20 | const uint64_t SUBMISSION_QUEUE_REGISTER_1 = 0x1010; 21 | const uint64_t COMPLETION_QUEUE_REGISTER_1 = 0x1013; 22 | const uint64_t SUBMISSION_QUEUE_REGISTER_2 = 0x1020; 23 | const uint64_t COMPLETION_QUEUE_REGISTER_2 = 0x1023; 24 | const uint64_t SUBMISSION_QUEUE_REGISTER_3 = 0x1030; 25 | const uint64_t COMPLETION_QUEUE_REGISTER_3 = 0x1033; 26 | const uint64_t SUBMISSION_QUEUE_REGISTER_4 = 0x1040; 27 | const uint64_t COMPLETION_QUEUE_REGISTER_4 = 0x1043; 28 | const uint64_t SUBMISSION_QUEUE_REGISTER_5 = 0x1050; 29 | const uint64_t COMPLETION_QUEUE_REGISTER_5 = 0x1053; 30 | const uint64_t SUBMISSION_QUEUE_REGISTER_6 = 0x1060; 31 | const uint64_t COMPLETION_QUEUE_REGISTER_6 = 0x1063; 32 | const uint64_t SUBMISSION_QUEUE_REGISTER_7 = 0x1070; 33 | const uint64_t COMPLETION_QUEUE_REGISTER_7 = 0x1073; 34 | const uint64_t SUBMISSION_QUEUE_REGISTER_8 = 0x1080; 35 | const uint64_t COMPLETION_QUEUE_REGISTER_8 = 0x1083; 36 | 37 | struct Completion_Queue_Entry 38 | { 39 | uint32_t Command_specific; 40 | uint32_t Reserved; 41 | uint16_t SQ_Head; //SQ Head Pointer, Indicates the current Submission Queue Head pointer for the Submission Queue indicated in the SQ Identifier field 42 | uint16_t SQ_ID;//SQ Identifier, Indicates the Submission Queue to which the associated command was issued to. 43 | uint16_t Command_Identifier;//Command Identifier, Indicates the identifier of the command that is being completed 44 | uint16_t SF_P; //Status Field (SF)+ Phase Tag(P) 45 | //SF: Indicates status for the command that is being completed 46 | //P:Identifies whether a Completion Queue entry is new 47 | }; 48 | 49 | struct Submission_Queue_Entry 50 | { 51 | uint8_t Opcode;//Is it a read or write request 52 | uint8_t PRP_FUSE; 53 | uint16_t Command_Identifier;//The id of the command in the I/O submission queue 54 | uint64_t Namespace_identifier; 55 | uint64_t Reserved; 56 | uint64_t Metadata_pointer_1; 57 | uint64_t PRP_entry_1; 58 | uint64_t PRP_entry_2; 59 | uint32_t Command_specific[6]; 60 | }; 61 | 62 | #endif // !NVME_DEFINISIONS_H 63 | -------------------------------------------------------------------------------- /src/ssd/NVM_Channel_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_CHANNEL_BASE_H 2 | #define NVM_CHANNEL_BASE_H 3 | 4 | namespace SSD_Components 5 | { 6 | enum class BusChannelStatus { BUSY, IDLE }; 7 | class NVM_Channel_Base {}; 8 | } 9 | 10 | #endif // !NVM_CHANNEL_BASE_H 11 | -------------------------------------------------------------------------------- /src/ssd/NVM_Firmware.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_Firmware.h" 2 | 3 | namespace SSD_Components 4 | { 5 | NVM_Firmware::NVM_Firmware(const sim_object_id_type& id, Data_Cache_Manager_Base* data_cache_manager) 6 | : MQSimEngine::Sim_Object(id), Data_cache_manager(data_cache_manager) 7 | { 8 | } 9 | 10 | void NVM_Firmware::Validate_simulation_config() 11 | { 12 | } 13 | } -------------------------------------------------------------------------------- /src/ssd/NVM_Firmware.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_FIRMWARE_H 2 | #define NVM_FIRMWARE_H 3 | 4 | #include 5 | #include "../sim/Sim_Object.h" 6 | #include "../utils/Workload_Statistics.h" 7 | #include "NVM_Transaction.h" 8 | #include "Data_Cache_Manager_Base.h" 9 | 10 | namespace SSD_Components 11 | { 12 | class Data_Cache_Manager_Base; 13 | class NVM_Firmware : public MQSimEngine::Sim_Object 14 | { 15 | public: 16 | NVM_Firmware(const sim_object_id_type& id, Data_Cache_Manager_Base* data_cache_manager); 17 | void Validate_simulation_config(); 18 | Data_Cache_Manager_Base* Data_cache_manager; 19 | virtual LPA_type Convert_host_logical_address_to_device_address(LHA_type lha) = 0; 20 | virtual page_status_type Find_NVM_subunit_access_bitmap(LHA_type lha) = 0;//Returns a bitstring with only one bit in it and determines which subunit (e.g., sub-page in flash memory) is accessed with the target NVM unit (e.g., page in flash memory). If the NVM access unit is B_nvm bytes in size and the LHA_type unit is B_lha bytes in size, then the returned bistream has b bits where b = ceiling(B_nvm / B_lha). 21 | virtual void Perform_precondition(std::vector workload_stats) = 0; 22 | virtual void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter) = 0; 23 | }; 24 | } 25 | 26 | #endif // !NVM_FIRMWARE_H 27 | -------------------------------------------------------------------------------- /src/ssd/NVM_PHY_Base.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_PHY_Base.h" 2 | 3 | namespace SSD_Components 4 | { 5 | NVM_PHY_Base::NVM_PHY_Base(const sim_object_id_type& id) 6 | : MQSimEngine::Sim_Object(id) 7 | { 8 | } 9 | 10 | NVM_PHY_Base::~NVM_PHY_Base() 11 | { 12 | } 13 | } -------------------------------------------------------------------------------- /src/ssd/NVM_PHY_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_PHY_BASE 2 | #define NVM_PHY_BASE 3 | 4 | #include "../sim/Sim_Object.h" 5 | #include "../nvm_chip/NVM_Chip.h" 6 | 7 | namespace SSD_Components 8 | { 9 | class NVM_PHY_Base : public MQSimEngine::Sim_Object 10 | { 11 | public: 12 | NVM_PHY_Base(const sim_object_id_type& id); 13 | ~NVM_PHY_Base(); 14 | virtual void Change_memory_status_preconditioning(const NVM::NVM_Memory_Address* address, const void* status_info) = 0; 15 | }; 16 | } 17 | 18 | #endif // !NVM_PHY_BASE 19 | -------------------------------------------------------------------------------- /src/ssd/NVM_PHY_ONFI.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_PHY_ONFI.h" 2 | 3 | namespace SSD_Components { 4 | void NVM_PHY_ONFI::ConnectToTransactionServicedSignal(TransactionServicedHandlerType function) 5 | { 6 | connectedTransactionServicedHandlers.push_back(function); 7 | } 8 | 9 | /* 10 | * Different FTL components maybe waiting for a transaction to be finished: 11 | * HostInterface: For user reads and writes 12 | * Address_Mapping_Unit: For mapping reads and writes 13 | * TSU: For the reads that must be finished for partial writes (first read non updated parts of page data and then merge and write them into the new page) 14 | * GarbageCollector: For gc reads, writes, and erases 15 | */ 16 | void NVM_PHY_ONFI::broadcastTransactionServicedSignal(NVM_Transaction_Flash* transaction) 17 | { 18 | for (std::vector::iterator it = connectedTransactionServicedHandlers.begin(); 19 | it != connectedTransactionServicedHandlers.end(); it++) { 20 | (*it)(transaction); 21 | } 22 | delete transaction;//This transaction has been consumed and no more needed 23 | } 24 | 25 | void NVM_PHY_ONFI::ConnectToChannelIdleSignal(ChannelIdleHandlerType function) 26 | { 27 | connectedChannelIdleHandlers.push_back(function); 28 | } 29 | 30 | void NVM_PHY_ONFI::broadcastChannelIdleSignal(flash_channel_ID_type channelID) 31 | { 32 | for (std::vector::iterator it = connectedChannelIdleHandlers.begin(); 33 | it != connectedChannelIdleHandlers.end(); it++) { 34 | (*it)(channelID); 35 | } 36 | } 37 | 38 | void NVM_PHY_ONFI::ConnectToChipIdleSignal(ChipIdleHandlerType function) 39 | { 40 | connectedChipIdleHandlers.push_back(function); 41 | } 42 | 43 | void NVM_PHY_ONFI::broadcastChipIdleSignal(NVM::FlashMemory::Flash_Chip* chip) 44 | { 45 | for (std::vector::iterator it = connectedChipIdleHandlers.begin(); 46 | it != connectedChipIdleHandlers.end(); it++) { 47 | (*it)(chip); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/ssd/NVM_PHY_ONFI.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_PHY_ONFI_ONFI_H 2 | #define NVM_PHY_ONFI_ONFI_H 3 | 4 | #include 5 | #include "../nvm_chip/flash_memory/Flash_Command.h" 6 | #include "../nvm_chip/flash_memory/Flash_Chip.h" 7 | #include "NVM_Transaction_Flash.h" 8 | #include "NVM_Transaction_Flash_RD.h" 9 | #include "NVM_Transaction_Flash_WR.h" 10 | #include "NVM_Transaction_Flash_ER.h" 11 | #include "NVM_PHY_Base.h" 12 | #include "ONFI_Channel_Base.h" 13 | 14 | 15 | namespace SSD_Components 16 | { 17 | enum class ChipStatus { IDLE, CMD_IN, CMD_DATA_IN, DATA_OUT, READING, WRITING, ERASING, WAIT_FOR_DATA_OUT, WAIT_FOR_COPYBACK_CMD }; 18 | 19 | class NVM_PHY_ONFI : public NVM_PHY_Base 20 | { 21 | public: 22 | NVM_PHY_ONFI(sim_object_id_type id, 23 | unsigned int ChannelCount, unsigned int chip_no_per_channel, unsigned int DieNoPerChip, unsigned int PlaneNoPerDie) 24 | : NVM_PHY_Base(id), 25 | channel_count(ChannelCount), chip_no_per_channel(chip_no_per_channel), die_no_per_chip(DieNoPerChip), plane_no_per_die(PlaneNoPerDie){} 26 | ~NVM_PHY_ONFI() {}; 27 | 28 | virtual BusChannelStatus Get_channel_status(flash_channel_ID_type) = 0; 29 | virtual NVM::FlashMemory::Flash_Chip* Get_chip(flash_channel_ID_type channel_id, flash_chip_ID_type chip_id) = 0; 30 | virtual LPA_type Get_metadata(flash_channel_ID_type channe_id, flash_chip_ID_type chip_id, flash_die_ID_type die_id, flash_plane_ID_type plane_id, flash_block_ID_type block_id, flash_page_ID_type page_id) = 0;//A simplification to decrease the complexity of GC execution! The GC unit may need to know the metadata of a page to decide if a page is valid or invalid. 31 | virtual bool HasSuspendedCommand(NVM::FlashMemory::Flash_Chip* chip) = 0; 32 | virtual ChipStatus GetChipStatus(NVM::FlashMemory::Flash_Chip* chip) = 0; 33 | virtual sim_time_type Expected_finish_time(NVM::FlashMemory::Flash_Chip* chip) = 0; 34 | /// Provides communication between controller and NVM chips for a simple read/write/erase command. 35 | virtual void Send_command_to_chip(std::list& transactionList) = 0; 36 | virtual void Change_flash_page_status_for_preconditioning(const NVM::FlashMemory::Physical_Page_Address& page_address, const LPA_type lpa) = 0; 37 | 38 | typedef void(*TransactionServicedHandlerType) (NVM_Transaction_Flash*); 39 | void ConnectToTransactionServicedSignal(TransactionServicedHandlerType); 40 | typedef void(*ChannelIdleHandlerType) (flash_channel_ID_type); 41 | void ConnectToChannelIdleSignal(ChannelIdleHandlerType); 42 | typedef void(*ChipIdleHandlerType) (NVM::FlashMemory::Flash_Chip*); 43 | void ConnectToChipIdleSignal(ChipIdleHandlerType); 44 | protected: 45 | unsigned int channel_count; 46 | unsigned int chip_no_per_channel; 47 | unsigned int die_no_per_chip; 48 | unsigned int plane_no_per_die; 49 | std::vector connectedTransactionServicedHandlers; 50 | void broadcastTransactionServicedSignal(NVM_Transaction_Flash* transaction); 51 | std::vector connectedChannelIdleHandlers; 52 | void broadcastChannelIdleSignal(flash_channel_ID_type); 53 | std::vector connectedChipIdleHandlers; 54 | void broadcastChipIdleSignal(NVM::FlashMemory::Flash_Chip* chip); 55 | }; 56 | } 57 | 58 | 59 | #endif // !NVM_PHY_ONFI_ONFI_H 60 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TRANSACTION_H 2 | #define NVM_TRANSACTION_H 3 | 4 | #include 5 | #include "../sim/Sim_Defs.h" 6 | #include "../sim/Engine.h" 7 | #include "User_Request.h" 8 | 9 | namespace SSD_Components 10 | { 11 | class User_Request; 12 | 13 | enum class Transaction_Type { READ, WRITE, ERASE, UNKOWN }; 14 | enum class Transaction_Source_Type { USERIO, CACHE, GC_WL, MAPPING }; 15 | 16 | class NVM_Transaction 17 | { 18 | public: 19 | NVM_Transaction(stream_id_type stream_id, Transaction_Source_Type source, Transaction_Type type, User_Request* user_request) : 20 | Stream_id(stream_id), Source(source), Type(type), UserIORequest(user_request), Issue_time(Simulator->Time()), STAT_execution_time(INVALID_TIME), STAT_transfer_time(INVALID_TIME) {} 21 | stream_id_type Stream_id; 22 | Transaction_Source_Type Source; 23 | Transaction_Type Type; 24 | User_Request* UserIORequest; 25 | //std::list::iterator RelatedNodeInQueue;//Just used for high performance linkedlist insertion/deletion 26 | 27 | sim_time_type Issue_time; 28 | /* Used to calculate service time and transfer time for a normal read/program operation used to respond to the host IORequests. 29 | In other words, these variables are not important if FlashTransactions is used for garbage collection.*/ 30 | sim_time_type STAT_execution_time, STAT_transfer_time; 31 | }; 32 | } 33 | 34 | #endif //!NVM_TRANSACTION_H 35 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_Transaction_Flash.h" 2 | 3 | 4 | namespace SSD_Components 5 | { 6 | NVM_Transaction_Flash::NVM_Transaction_Flash(Transaction_Source_Type source, Transaction_Type type, stream_id_type stream_id, 7 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, User_Request* user_request) : 8 | NVM_Transaction(stream_id, source, type, user_request), 9 | Data_and_metadata_size_in_byte(data_size_in_byte), LPA(lpa), PPA(ppa), Physical_address_determined(false), FLIN_Barrier(false) 10 | { 11 | } 12 | 13 | NVM_Transaction_Flash::NVM_Transaction_Flash(Transaction_Source_Type source, Transaction_Type type, stream_id_type stream_id, 14 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, User_Request* user_request) : 15 | NVM_Transaction(stream_id, source, type, user_request), Data_and_metadata_size_in_byte(data_size_in_byte), LPA(lpa), PPA(ppa), Address(address), Physical_address_determined(false) 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TRANSACTION_FLASH_H 2 | #define NVM_TRANSACTION_FLASH_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../sim/Sim_Defs.h" 8 | #include "../sim/Sim_Event.h" 9 | #include "../sim/Engine.h" 10 | #include "../nvm_chip/flash_memory/FlashTypes.h" 11 | #include "../nvm_chip/flash_memory/Flash_Chip.h" 12 | #include "../nvm_chip/flash_memory/Physical_Page_Address.h" 13 | #include "NVM_Transaction.h" 14 | #include "User_Request.h" 15 | 16 | namespace SSD_Components 17 | { 18 | class User_Request; 19 | 20 | class NVM_Transaction_Flash : public NVM_Transaction 21 | { 22 | public: 23 | NVM_Transaction_Flash(Transaction_Source_Type source, Transaction_Type type, stream_id_type stream_id, 24 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, User_Request* user_request); 25 | NVM_Transaction_Flash(Transaction_Source_Type source, Transaction_Type type, stream_id_type stream_id, 26 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, User_Request* user_request); 27 | NVM::FlashMemory::Physical_Page_Address Address; 28 | unsigned int Data_and_metadata_size_in_byte; //number of bytes contained in the request: bytes in the real page + bytes of metadata 29 | 30 | LPA_type LPA; 31 | PPA_type PPA; 32 | 33 | bool SuspendRequired; 34 | bool Physical_address_determined; 35 | sim_time_type Estimated_alone_waiting_time;//Used in scheduling methods, such as FLIN, where fairness and QoS is considered in scheduling 36 | bool FLIN_Barrier;//Especially used in queue reordering inf FLIN scheduler 37 | private: 38 | 39 | }; 40 | } 41 | 42 | #endif // !FLASH_TRANSACTION_H 43 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_ER.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_Transaction_Flash_ER.h" 2 | 3 | 4 | namespace SSD_Components 5 | { 6 | NVM_Transaction_Flash_ER::NVM_Transaction_Flash_ER(Transaction_Source_Type source, stream_id_type streamID, 7 | const NVM::FlashMemory::Physical_Page_Address& address) : 8 | NVM_Transaction_Flash(source, Transaction_Type::ERASE, streamID, 0, NO_LPA, NO_PPA, address, NULL) 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_ER.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TRANSACTION_FLASH_ER_H 2 | #define NVM_TRANSACTION_FLASH_ER_H 3 | 4 | #include 5 | #include "../nvm_chip/flash_memory/FlashTypes.h" 6 | #include "NVM_Transaction_Flash.h" 7 | #include "NVM_Transaction_Flash_WR.h" 8 | 9 | namespace SSD_Components 10 | { 11 | class NVM_Transaction_Flash_ER : public NVM_Transaction_Flash 12 | { 13 | public: 14 | NVM_Transaction_Flash_ER(Transaction_Source_Type source, stream_id_type streamID, const NVM::FlashMemory::Physical_Page_Address& address); 15 | std::list Page_movement_activities; 16 | }; 17 | } 18 | 19 | #endif // !ERASE_TRANSACTION_H 20 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_RD.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_Transaction_Flash_RD.h" 2 | #include "../nvm_chip/NVM_Types.h" 3 | 4 | namespace SSD_Components 5 | { 6 | NVM_Transaction_Flash_RD::NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 7 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, SSD_Components::User_Request* related_user_IO_request, 8 | NVM::memory_content_type content, NVM_Transaction_Flash_WR* related_write, page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp) : 9 | NVM_Transaction_Flash(source, Transaction_Type::READ, stream_id, data_size_in_byte, lpa, ppa, related_user_IO_request), 10 | Content(content), RelatedWrite(related_write), read_sectors_bitmap(read_sectors_bitmap), DataTimeStamp(data_timestamp) 11 | { 12 | } 13 | 14 | NVM_Transaction_Flash_RD::NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 15 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, 16 | SSD_Components::User_Request* related_user_IO_request, 17 | NVM::memory_content_type content, NVM_Transaction_Flash_WR* related_write, page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp) : 18 | NVM_Transaction_Flash(source, Transaction_Type::READ, stream_id, data_size_in_byte, lpa, ppa, address, related_user_IO_request), 19 | Content(content), RelatedWrite(related_write), read_sectors_bitmap(read_sectors_bitmap), DataTimeStamp(data_timestamp) 20 | { 21 | } 22 | 23 | NVM_Transaction_Flash_RD::NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 24 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, SSD_Components::User_Request* related_user_IO_request, 25 | NVM::memory_content_type content, page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp) : 26 | NVM_Transaction_Flash(source, Transaction_Type::READ, stream_id, data_size_in_byte, lpa, ppa, related_user_IO_request), 27 | Content(content), RelatedWrite(NULL), read_sectors_bitmap(read_sectors_bitmap), DataTimeStamp(data_timestamp) 28 | { 29 | } 30 | } -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_RD.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TRANSACTION_FLASH_RD_H 2 | #define NVM_TRANSACTION_FLASH_RD_H 3 | 4 | #include "../nvm_chip/flash_memory/FlashTypes.h" 5 | #include "NVM_Transaction_Flash.h" 6 | 7 | 8 | namespace SSD_Components 9 | { 10 | class NVM_Transaction_Flash_WR; 11 | class NVM_Transaction_Flash_RD : public NVM_Transaction_Flash 12 | { 13 | public: 14 | NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 15 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, 16 | SSD_Components::User_Request* related_user_IO_request, NVM::memory_content_type content, NVM_Transaction_Flash_WR* related_write, 17 | page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp); 18 | NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 19 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, 20 | SSD_Components::User_Request* related_user_IO_request, NVM::memory_content_type content, NVM_Transaction_Flash_WR* related_write, 21 | page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp); 22 | NVM_Transaction_Flash_RD(Transaction_Source_Type source, stream_id_type stream_id, 23 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, 24 | SSD_Components::User_Request* related_user_IO_request, NVM::memory_content_type content, 25 | page_status_type read_sectors_bitmap, data_timestamp_type data_timestamp); 26 | NVM::memory_content_type Content; //The content of this transaction 27 | NVM_Transaction_Flash_WR* RelatedWrite; //Is this read request related to another write request and provides update data (for partial page write) 28 | 29 | std::vector RelatedRead_SUB; //sub-page trs. 30 | 31 | page_status_type read_sectors_bitmap; 32 | data_timestamp_type DataTimeStamp; 33 | }; 34 | } 35 | 36 | #endif // !NVM_TRANSACTION_FLASH_RD_H 37 | -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_WR.cpp: -------------------------------------------------------------------------------- 1 | #include "NVM_Transaction_Flash_WR.h" 2 | 3 | 4 | namespace SSD_Components 5 | { 6 | NVM_Transaction_Flash_WR::NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 7 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 8 | NVM_Transaction_Flash_RD* related_read, page_status_type written_sectors_bitmap, data_timestamp_type data_timestamp) : 9 | NVM_Transaction_Flash(source, Transaction_Type::WRITE, stream_id, data_size_in_byte, lpa, ppa, address, user_io_request), 10 | Content(content), RelatedRead(related_read), write_sectors_bitmap(written_sectors_bitmap), DataTimeStamp(data_timestamp), 11 | ExecutionMode(WriteExecutionModeType::SIMPLE) 12 | { 13 | } 14 | 15 | NVM_Transaction_Flash_WR::NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 16 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 17 | NVM_Transaction_Flash_RD* related_read, page_status_type written_sectors_bitmap, data_timestamp_type data_timestamp) : 18 | NVM_Transaction_Flash(source, Transaction_Type::WRITE, stream_id, data_size_in_byte, lpa, ppa, user_io_request), 19 | Content(content), RelatedRead(related_read), write_sectors_bitmap(written_sectors_bitmap), DataTimeStamp(data_timestamp), 20 | ExecutionMode(WriteExecutionModeType::SIMPLE) 21 | { 22 | } 23 | 24 | NVM_Transaction_Flash_WR::NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 25 | unsigned int data_size_in_byte, LPA_type lpa, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 26 | page_status_type written_sectors_bitmap, data_timestamp_type data_timestamp) : 27 | NVM_Transaction_Flash(source, Transaction_Type::WRITE, stream_id, data_size_in_byte, lpa, NO_PPA, user_io_request), 28 | Content(content), RelatedRead(NULL), write_sectors_bitmap(written_sectors_bitmap), DataTimeStamp(data_timestamp), 29 | ExecutionMode(WriteExecutionModeType::SIMPLE) 30 | { 31 | } 32 | } -------------------------------------------------------------------------------- /src/ssd/NVM_Transaction_Flash_WR.h: -------------------------------------------------------------------------------- 1 | #ifndef NVM_TRANSACTION_FLASH_WR 2 | #define NVM_TRANSACTION_FLASH_WR 3 | 4 | #include "../nvm_chip/flash_memory/FlashTypes.h" 5 | #include "../nvm_chip/NVM_Types.h" 6 | #include "NVM_Transaction_Flash.h" 7 | #include "NVM_Transaction_Flash_RD.h" 8 | #include "NVM_Transaction_Flash_ER.h" 9 | 10 | namespace SSD_Components 11 | { 12 | class NVM_Transaction_Flash_ER; 13 | enum class WriteExecutionModeType { SIMPLE, COPYBACK }; 14 | 15 | class NVM_Transaction_Flash_WR : public NVM_Transaction_Flash 16 | { 17 | public: 18 | NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 19 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 20 | NVM_Transaction_Flash_RD* related_read, page_status_type write_sectors_bitmap, data_timestamp_type data_timestamp); 21 | NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 22 | unsigned int data_size_in_byte, LPA_type lpa, PPA_type ppa, const NVM::FlashMemory::Physical_Page_Address& address, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 23 | NVM_Transaction_Flash_RD* related_read, page_status_type write_sectors_bitmap, data_timestamp_type data_timestamp); 24 | NVM_Transaction_Flash_WR(Transaction_Source_Type source, stream_id_type stream_id, 25 | unsigned int data_size_in_byte, LPA_type lpa, SSD_Components::User_Request* user_io_request, NVM::memory_content_type content, 26 | page_status_type write_sectors_bitmap, data_timestamp_type data_timestamp); 27 | NVM::memory_content_type Content; //The content of this transaction 28 | NVM_Transaction_Flash_RD* RelatedRead; //If this write request must be preceded by a read (for partial page write), this variable is used to point to the corresponding read request 29 | NVM_Transaction_Flash_ER* RelatedErase; 30 | 31 | std::vector RelatedWrite_SUB; //sub-page. 32 | unsigned int num_of_subpgs; 33 | 34 | page_status_type write_sectors_bitmap; 35 | data_timestamp_type DataTimeStamp; 36 | WriteExecutionModeType ExecutionMode; 37 | }; 38 | } 39 | 40 | #endif // !WRITE_TRANSACTION_H 41 | -------------------------------------------------------------------------------- /src/ssd/ONFI_Channel_Base.cpp: -------------------------------------------------------------------------------- 1 | #include "ONFI_Channel_Base.h" 2 | 3 | 4 | namespace SSD_Components 5 | { 6 | ONFI_Channel_Base::ONFI_Channel_Base(flash_channel_ID_type channelID, unsigned int chipCount, NVM::FlashMemory::Flash_Chip** flashChips, ONFI_Protocol type) 7 | : ChannelID(channelID), status(BusChannelStatus::IDLE), Chips(flashChips), Type(type) 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ssd/ONFI_Channel_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef ONFI_CHANNEL_BASE_H 2 | #define ONFI_CHANNEL_BASE_H 3 | 4 | #include "../nvm_chip/flash_memory/Flash_Chip.h" 5 | #include "NVM_Channel_Base.h" 6 | 7 | namespace SSD_Components 8 | { 9 | enum class ONFI_Protocol {NVDDR2}; 10 | class ONFI_Channel_Base : public NVM_Channel_Base 11 | { 12 | public: 13 | ONFI_Channel_Base(flash_channel_ID_type channelID, unsigned int chipCount, NVM::FlashMemory::Flash_Chip** flashChips, ONFI_Protocol type); 14 | flash_channel_ID_type ChannelID; 15 | NVM::FlashMemory::Flash_Chip** Chips; 16 | ONFI_Protocol Type; 17 | 18 | BusChannelStatus GetStatus() 19 | { 20 | return status; 21 | } 22 | 23 | void SetStatus(BusChannelStatus new_status, NVM::FlashMemory::Flash_Chip* target_chip) 24 | { 25 | if (((status == BusChannelStatus::IDLE && new_status == BusChannelStatus::IDLE) 26 | || (status == BusChannelStatus::BUSY && new_status == BusChannelStatus::BUSY)) 27 | && (current_active_chip != target_chip)) { 28 | PRINT_ERROR("Bus " << ChannelID << ": illegal bus status transition!") 29 | } 30 | 31 | status = new_status; 32 | if (status == BusChannelStatus::BUSY) { 33 | current_active_chip = target_chip; 34 | } else { 35 | current_active_chip = NULL; 36 | } 37 | } 38 | private: 39 | BusChannelStatus status; 40 | NVM::FlashMemory::Flash_Chip* current_active_chip; 41 | }; 42 | } 43 | 44 | #endif // !CHANNEL_H 45 | -------------------------------------------------------------------------------- /src/ssd/ONFI_Channel_NVDDR2.cpp: -------------------------------------------------------------------------------- 1 | #include "ONFI_Channel_NVDDR2.h" 2 | 3 | namespace SSD_Components 4 | { 5 | ONFI_Channel_NVDDR2::ONFI_Channel_NVDDR2(flash_channel_ID_type channelID, unsigned int chipCount, NVM::FlashMemory::Flash_Chip** flashChips, unsigned int ChannelWidth, 6 | sim_time_type t_RC, sim_time_type t_DSC, 7 | sim_time_type t_DBSY, sim_time_type t_CS, sim_time_type t_RR, 8 | sim_time_type t_WB, sim_time_type t_WC, sim_time_type t_ADL, sim_time_type t_CALS, 9 | sim_time_type t_DQSRE, sim_time_type t_RPRE, sim_time_type t_RHW, sim_time_type t_CCS, 10 | sim_time_type t_WPST, sim_time_type t_WPSTH) 11 | : ONFI_Channel_Base(channelID, chipCount, flashChips, ONFI_Protocol::NVDDR2), 12 | ChannelWidth(ChannelWidth), 13 | t_RC(t_RC), t_DSC(t_DSC), t_DBSY(t_DBSY), t_CS(t_CS), t_RR(t_RR), t_WB(t_WB), t_WC(t_WC), t_ADL(t_ADL), 14 | t_CALS(t_CALS), t_DQSRE(t_DQSRE), t_RPRE(t_RPRE), t_RHW(t_RHW), t_CCS(t_CCS), t_WPST(t_WPST), t_WPSTH(t_WPSTH) 15 | { 16 | ReadCommandTime[1] = t_CS + t_WC * 6 + t_WB + t_RR; 17 | ReadCommandTime[2] = t_CS + 6 * t_WC + t_DBSY + 6 * t_WC + t_WB + t_RR; 18 | ReadCommandTime[3] = t_CS + 6 * t_WC + t_DBSY + 6 * t_WC + t_DBSY + 6 * t_WC + t_WB + t_RR; 19 | ReadCommandTime[4] = t_CS + 6 * t_WC + t_DBSY + 6 * t_WC + t_DBSY + 6 * t_WC + t_DBSY + 6 * t_WC + t_WB + t_RR; 20 | ReadDataOutSetupTime = t_RPRE + t_DQSRE; 21 | ReadDataOutSetupTime_TwoPlane = t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE; 22 | ReadDataOutSetupTime_ThreePlane = t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE; 23 | ReadDataOutSetupTime_FourPlane = t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE + t_RHW + 6 * t_WC + t_CCS + t_RPRE + t_DQSRE; 24 | TwoUnitDataInTime = t_RC; 25 | 26 | ProgramCommandTime[1] = t_CS + t_WC * 6 + t_ADL + t_WPST + t_WPSTH + t_WB; 27 | ProgramCommandTime[2] = t_CS + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 6 + t_ADL + t_WPST + t_WPSTH + t_WB); 28 | ProgramCommandTime[3] = t_CS + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 6 + t_ADL + t_WPST + t_WPSTH + t_WB); 29 | ProgramCommandTime[4] = t_CS + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 5 + t_ADL + t_WPST + t_CALS + t_WB) + t_DBSY + (t_WC * 6 + t_ADL + t_WPST + t_WPSTH + t_WB); 30 | TwoUnitDataOutTime = t_DSC; 31 | ProgramSuspendCommandTime = t_CS + t_WC * 3; 32 | 33 | EraseCommandTime[1] = t_CS + t_WC * 4 + t_WB; 34 | EraseCommandTime[2] = t_CS + t_WC * 4 + t_WB + (t_DBSY + t_WC * 4 + t_WB); 35 | EraseCommandTime[3] = t_CS + t_WC * 4 + t_WB + (t_DBSY + t_WC * 4 + t_WB) + (t_DBSY + t_WC * 4 + t_WB); 36 | EraseCommandTime[4] = t_CS + t_WC * 4 + t_WB + (t_DBSY + t_WC * 4 + t_WB) + (t_DBSY + t_WC * 4 + t_WB) + (t_DBSY + t_WC * 4 + t_WB); 37 | EraseSuspendCommandTime = t_CS + t_WC * 3; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ssd/ONFI_Channel_NVDDR2.h: -------------------------------------------------------------------------------- 1 | #ifndef ONFI_CHANNEL_NVDDR2_H 2 | #define ONFI_CHANNEL_NVDDR2_H 3 | 4 | #include "../nvm_chip/flash_memory/FlashTypes.h" 5 | #include "ONFI_Channel_Base.h" 6 | 7 | 8 | #define NVDDR2DataInTransferTime(X,Y) ((X / Y->ChannelWidth / 2) * Y->TwoUnitDataInTime) 9 | #define NVDDR2DataOutTransferTime(X,Y) ((X / Y->ChannelWidth / 2) * Y->TwoUnitDataOutTime) 10 | 11 | 12 | namespace SSD_Components 13 | { 14 | class ONFI_Channel_NVDDR2 : public ONFI_Channel_Base 15 | { 16 | public: 17 | ONFI_Channel_NVDDR2(flash_channel_ID_type channelID, unsigned int chipCount, NVM::FlashMemory::Flash_Chip** flashChips, unsigned int ChannelWidth, 18 | sim_time_type t_RC = 6, sim_time_type t_DSC = 6, 19 | sim_time_type t_DBSY = 500, sim_time_type t_CS = 20, sim_time_type t_RR = 20, 20 | sim_time_type t_WB = 100, sim_time_type t_WC = 25, sim_time_type t_ADL = 70, sim_time_type t_CALS = 15, 21 | sim_time_type t_DQSRE = 15, sim_time_type t_RPRE = 15, sim_time_type t_RHW = 100, sim_time_type t_CCS = 300, 22 | sim_time_type t_WPST = 6, sim_time_type t_WPSTH = 15); 23 | 24 | 25 | sim_time_type TwoUnitDataOutTime; //The DDR delay for two-unit device data out 26 | sim_time_type ReadCommandTime[5];//Read command transfer time for different number of planes 27 | sim_time_type ReadDataOutSetupTime, ReadDataOutSetupTime_TwoPlane, ReadDataOutSetupTime_ThreePlane, ReadDataOutSetupTime_FourPlane; 28 | 29 | sim_time_type TwoUnitDataInTime; //The DDR delay for two-unit device data in 30 | sim_time_type ProgramCommandTime[5];//Program command transfer time for different number of planes 31 | sim_time_type ProgramSuspendCommandTime; 32 | 33 | sim_time_type EraseCommandTime[5]; 34 | sim_time_type EraseSuspendCommandTime; 35 | 36 | unsigned int ChannelWidth; //channel width in bytes 37 | private: 38 | //Data input/ouput timing parameters related to bus frequency 39 | sim_time_type t_RC; //Average RE cycle time, e.g. 6ns 40 | sim_time_type t_DSC; //Average DQS cycle time, e.g. 6ns 41 | 42 | //flash timing parameters 43 | sim_time_type t_DBSY; //Dummy busy time, e.g. 500ns 44 | 45 | //ONFI NVDDR2 command and address protocol timing parameters 46 | sim_time_type t_CS; //CE setup, e.g. 20ns 47 | sim_time_type t_RR; //Ready to data output, e.g. 20ns 48 | sim_time_type t_WB; //CLK HIGH to R/B LOW, e.g. 100ns 49 | sim_time_type t_WC; //WE cycle time, e.g. 25ns 50 | sim_time_type t_ADL; //ALE to data loading time, e.g. 70ns 51 | sim_time_type t_CALS; //ALE, CLE setup with ODT disabled, e.g. 15 52 | 53 | //ONFI NVDDR2 data output protocol timing paramters 54 | sim_time_type t_DQSRE; //Access window of DQS from RE, e.g. 15ns 55 | sim_time_type t_RPRE; //Read preamble, e.g. 15ns 56 | sim_time_type t_RHW; //Data output to command, address, or data input, 100ns 57 | sim_time_type t_CCS; //Change column setup time to data in/out or next command, 300ns 58 | 59 | //ONFI NVDDR2 data input protocol timing paramters 60 | sim_time_type t_WPST; //DQS write postamble, e.g. 6ns 61 | sim_time_type t_WPSTH; //DQS write postamble hold time, e.g. 15ns 62 | }; 63 | } 64 | 65 | #endif // !ONFI_CHANNEL_NVDDR2_H 66 | -------------------------------------------------------------------------------- /src/ssd/Queue_Probe.h: -------------------------------------------------------------------------------- 1 | #ifndef QUEUE_PROBE_H 2 | #define QUEUE_PROBE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../sim/Sim_Defs.h" 8 | #include "NVM_Transaction.h" 9 | #include "../utils/XMLWriter.h" 10 | 11 | namespace SSD_Components 12 | { 13 | class StateStatistics 14 | { 15 | public: 16 | StateStatistics(); 17 | unsigned long nEnterances; 18 | sim_time_type totalTime; 19 | }; 20 | 21 | class Queue_Probe 22 | { 23 | public: 24 | Queue_Probe(); 25 | void EnqueueRequest(NVM_Transaction* transaction); 26 | void DequeueRequest(NVM_Transaction* transaction); 27 | void ResetEpochStatistics(); 28 | void Snapshot(std::string id, Utils::XmlWriter& writer); 29 | unsigned long NRequests(); 30 | unsigned long NDepartures(); 31 | int QueueLength(); 32 | std::vector States(); 33 | unsigned int MaxQueueLength(); 34 | double AvgQueueLength(); 35 | double STDevQueueLength(); 36 | double AvgQueueLengthEpoch(); 37 | sim_time_type MaxWaitingTime(); 38 | sim_time_type AvgWaitingTime(); 39 | sim_time_type AvgWaitingTimeEpoch(); 40 | sim_time_type TotalWaitingTime(); 41 | private: 42 | unsigned int count = 0; 43 | unsigned long nRequests = 0; 44 | unsigned long nDepartures = 0; 45 | sim_time_type totalWaitingTime = 0; 46 | sim_time_type lastCountChange = 0; 47 | sim_time_type lastCountChangeReference = 0; 48 | unsigned long nRequestsEpoch = 0; 49 | unsigned long nDeparturesEpoch = 0; 50 | sim_time_type totalWaitingTimeEpoch = 0; 51 | sim_time_type epochStartTime; 52 | std::vector states; 53 | std::vector statesEpoch; 54 | std::unordered_map currentObjectsInQueue; 55 | unsigned int maxQueueLength = 0; 56 | sim_time_type maxWaitingTime = 0; 57 | void setCount(int val); 58 | }; 59 | 60 | } 61 | 62 | #endif // !QUEUE_PROBE 63 | -------------------------------------------------------------------------------- /src/ssd/SSD_Defs.h: -------------------------------------------------------------------------------- 1 | #ifndef SSD_DEFS_H 2 | #define SSD_DEFS_H 3 | 4 | #include 5 | #include 6 | #include "../sim/Sim_Defs.h" 7 | #include "../nvm_chip/flash_memory/FlashTypes.h" 8 | 9 | //enum class Memory_Type {FLASH}; 10 | 11 | typedef uint32_t host_pointer_type; 12 | typedef uint64_t LHA_type;//Logical Host Address, the addresses unit on the host-side. As of 2018, LHA is mainly a sector (i.e., 512B) but it could be as small as a cache-line (i.e., 64B) in future NVMs. 13 | typedef uint64_t PDA_type;//Physical device address, could be a 1) sector, 2) subpage, or a 3) cacheline 14 | typedef std::string io_request_id_type; 15 | typedef uint64_t data_cache_content_type; 16 | #define SECTOR_SIZE_IN_BYTE 512 17 | #define MAX_SUPPORT_STREAMS 256 //this value shouldn't be increased as some other parameters are set based on the maximum number of 256 18 | 19 | /* Since MQSim supports shared resources, such as DataCache and CMT, 20 | * it needs to make the keys (i.e., LPNs) to access these resources 21 | * unique (i.e., same LPNs from different streams must be treated as 22 | * different keys). To create this unique key, MQSim assumes that 23 | * there are at most 256 concurrent input streams (a typical value 24 | * in modern MQ-SSDs). The value 56 in the below macro is calculated 25 | * as (64 - log_2(256)). 26 | */ 27 | #define LPN_TO_UNIQUE_KEY(STREAM,LPN) ((((LPA_type)STREAM)<<56)|LPN) 28 | #define UNIQUE_KEY_TO_LPN(STREAM,LPN) ((~(((LPA_type)STREAM)<<56))&LPN) 29 | 30 | 31 | inline unsigned int count_sector_no_from_status_bitmap(const page_status_type page_status) 32 | { 33 | unsigned int size = 0; 34 | for (int i = 0; i < 64; i++) { 35 | if ((((page_status_type)1) << i) & page_status) { 36 | size++; 37 | } 38 | } 39 | 40 | return size; 41 | } 42 | 43 | 44 | #endif // !SSD_DEFS_H 45 | -------------------------------------------------------------------------------- /src/ssd/TSU_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef TSU_H 2 | #define TSU_H 3 | 4 | #include 5 | #include "../sim/Sim_Defs.h" 6 | #include "../sim/Sim_Object.h" 7 | #include "../nvm_chip/flash_memory/Flash_Chip.h" 8 | #include "../sim/Sim_Reporter.h" 9 | #include "FTL.h" 10 | #include "NVM_PHY_ONFI_NVDDR2.h" 11 | #include "Flash_Transaction_Queue.h" 12 | 13 | namespace SSD_Components 14 | { 15 | enum class Flash_Scheduling_Type {OUT_OF_ORDER, FLIN}; 16 | class FTL; 17 | class TSU_Base : public MQSimEngine::Sim_Object 18 | { 19 | public: 20 | TSU_Base(const sim_object_id_type& id, FTL* ftl, NVM_PHY_ONFI_NVDDR2* NVMController, Flash_Scheduling_Type Type, 21 | unsigned int Channel_no, unsigned int chip_no_per_channel, unsigned int DieNoPerChip, unsigned int PlaneNoPerDie, 22 | bool EraseSuspensionEnabled, bool ProgramSuspensionEnabled, 23 | sim_time_type WriteReasonableSuspensionTimeForRead, 24 | sim_time_type EraseReasonableSuspensionTimeForRead, 25 | sim_time_type EraseReasonableSuspensionTimeForWrite); 26 | virtual ~TSU_Base(); 27 | void Setup_triggers(); 28 | 29 | 30 | /*When an MQSim needs to send a set of transactions for execution, the following 31 | * three funcitons should be invoked in this order: 32 | * Prepare_for_transaction_submit() 33 | * Submit_transaction(transaction) 34 | * ..... 35 | * Submit_transaction(transaction) 36 | * Schedule() 37 | * 38 | * The above mentioned mechanism helps to exploit die-level and plane-level parallelism. 39 | * More precisely, first the transactions are queued and then, when the Schedule function 40 | * is invoked, the TSU has that opportunity to schedule them together to exploit multiplane 41 | * and die-interleaved execution. 42 | */ 43 | virtual void Prepare_for_transaction_submit() = 0; 44 | virtual void Submit_transaction(NVM_Transaction_Flash* transaction) = 0; 45 | 46 | /* Shedules the transactions currently stored in inputTransactionSlots. The transactions could 47 | * be mixes of reads, writes, and erases. 48 | */ 49 | virtual void Schedule() = 0; 50 | virtual void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 51 | protected: 52 | FTL* ftl; 53 | NVM_PHY_ONFI_NVDDR2* _NVMController; 54 | Flash_Scheduling_Type type; 55 | unsigned int channel_count; 56 | unsigned int chip_no_per_channel; 57 | unsigned int die_no_per_chip; 58 | unsigned int plane_no_per_die; 59 | bool eraseSuspensionEnabled, programSuspensionEnabled; 60 | sim_time_type writeReasonableSuspensionTimeForRead; 61 | sim_time_type eraseReasonableSuspensionTimeForRead;//the time period 62 | sim_time_type eraseReasonableSuspensionTimeForWrite; 63 | flash_chip_ID_type* Round_robin_turn_of_channel;//Used for round-robin service of the chips in channels 64 | 65 | static TSU_Base* _my_instance; 66 | std::list transaction_receive_slots;//Stores the transactions that are received for sheduling 67 | std::list transaction_dispatch_slots;//Used to submit transactions to the channel controller 68 | virtual bool service_read_transaction(NVM::FlashMemory::Flash_Chip* chip) = 0; 69 | virtual bool service_write_transaction(NVM::FlashMemory::Flash_Chip* chip) = 0; 70 | virtual bool service_erase_transaction(NVM::FlashMemory::Flash_Chip* chip) = 0; 71 | static void handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction); 72 | static void handle_channel_idle_signal(flash_channel_ID_type); 73 | static void handle_chip_idle_signal(NVM::FlashMemory::Flash_Chip* chip); 74 | 75 | int opened_scheduling_reqs; 76 | }; 77 | } 78 | 79 | #endif //TSU_H 80 | -------------------------------------------------------------------------------- /src/ssd/TSU_OutofOrder.h: -------------------------------------------------------------------------------- 1 | #ifndef TSU_OUTOFORDER_H 2 | #define TSU_OUTOFORDER_H 3 | 4 | #include 5 | #include "TSU_Base.h" 6 | #include "NVM_Transaction_Flash.h" 7 | #include "NVM_PHY_ONFI_NVDDR2.h" 8 | #include "FTL.h" 9 | 10 | namespace SSD_Components 11 | { 12 | class FTL; 13 | 14 | /* 15 | * This class implements a transaction scheduling unit which supports: 16 | * 1. Out-of-order execution of flash transactions, similar to the Sprinkler proposal 17 | * described in "Jung et al., Sprinkler: Maximizing resource utilization in many-chip 18 | * solid state disks, HPCA, 2014". 19 | * 2. Program and erase suspension, similar to the proposal described in "G. Wu and X. He, 20 | * Reducing SSD read latency via NAND flash program and erase suspension, FAST 2012". 21 | */ 22 | class TSU_OutOfOrder : public TSU_Base 23 | { 24 | public: 25 | TSU_OutOfOrder(const sim_object_id_type& id, FTL* ftl, NVM_PHY_ONFI_NVDDR2* NVMController, unsigned int Channel_no, unsigned int chip_no_per_channel, 26 | unsigned int DieNoPerChip, unsigned int PlaneNoPerDie, 27 | sim_time_type WriteReasonableSuspensionTimeForRead, 28 | sim_time_type EraseReasonableSuspensionTimeForRead, 29 | sim_time_type EraseReasonableSuspensionTimeForWrite, 30 | bool EraseSuspensionEnabled, bool ProgramSuspensionEnabled); 31 | ~TSU_OutOfOrder(); 32 | void Prepare_for_transaction_submit(); 33 | void Submit_transaction(NVM_Transaction_Flash* transaction); 34 | void Schedule(); 35 | 36 | void Start_simulation(); 37 | void Validate_simulation_config(); 38 | void Execute_simulator_event(MQSimEngine::Sim_Event*); 39 | void Report_results_in_XML(std::string name_prefix, Utils::XmlWriter& xmlwriter); 40 | private: 41 | Flash_Transaction_Queue** UserReadTRQueue; 42 | Flash_Transaction_Queue** UserWriteTRQueue; 43 | Flash_Transaction_Queue** GCReadTRQueue; 44 | Flash_Transaction_Queue** GCWriteTRQueue; 45 | Flash_Transaction_Queue** GCEraseTRQueue; 46 | Flash_Transaction_Queue** MappingReadTRQueue; 47 | Flash_Transaction_Queue** MappingWriteTRQueue; 48 | 49 | bool service_read_transaction(NVM::FlashMemory::Flash_Chip* chip); 50 | bool service_write_transaction(NVM::FlashMemory::Flash_Chip* chip); 51 | bool service_erase_transaction(NVM::FlashMemory::Flash_Chip* chip); 52 | }; 53 | } 54 | 55 | #endif // TSU_OUTOFORDER_H 56 | -------------------------------------------------------------------------------- /src/ssd/User_Request.cpp: -------------------------------------------------------------------------------- 1 | #include "User_Request.h" 2 | 3 | namespace SSD_Components 4 | { 5 | unsigned int User_Request::lastId = 0; 6 | 7 | User_Request::User_Request() : Sectors_serviced_from_cache(0) 8 | { 9 | ID = "" + std::to_string(lastId++); 10 | ToBeIgnored = false; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ssd/User_Request.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_REQUEST_H 2 | #define USER_REQUEST_H 3 | 4 | #include 5 | #include 6 | #include "SSD_Defs.h" 7 | #include "../sim/Sim_Defs.h" 8 | #include "Host_Interface_Defs.h" 9 | #include "NVM_Transaction.h" 10 | 11 | namespace SSD_Components 12 | { 13 | enum class UserRequestType { READ, WRITE }; 14 | class NVM_Transaction; 15 | class User_Request 16 | { 17 | public: 18 | User_Request(); 19 | IO_Flow_Priority_Class Priority_class; 20 | io_request_id_type ID; 21 | LHA_type Start_LBA; 22 | 23 | sim_time_type STAT_InitiationTime; 24 | sim_time_type STAT_ResponseTime; 25 | std::list Transaction_list; 26 | unsigned int Sectors_serviced_from_cache; 27 | 28 | unsigned int Size_in_byte; 29 | unsigned int SizeInSectors; 30 | UserRequestType Type; 31 | stream_id_type Stream_id; 32 | bool ToBeIgnored; 33 | void* IO_command_info;//used to store host I/O command info 34 | void* Data; 35 | private: 36 | static unsigned int lastId; 37 | }; 38 | } 39 | 40 | #endif // !USER_REQUEST_H 41 | -------------------------------------------------------------------------------- /src/utils/CMRRandomGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "CMRRandomGenerator.h" 2 | 3 | namespace Utils 4 | { 5 | double CMRRandomGenerator::norm = 2.328306549295728e-10; 6 | double CMRRandomGenerator::m1 = 4294967087.0; 7 | double CMRRandomGenerator::m2 = 4294944443.0; 8 | double CMRRandomGenerator::a12 = 1403580.0; 9 | double CMRRandomGenerator::a13 = -810728.0; 10 | double CMRRandomGenerator::a21 = 527612.0; 11 | double CMRRandomGenerator::a23 = -1370589.0; 12 | 13 | double CMRRandomGenerator::a[2][3][3] = { {{0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {a13, a12, 0.0}}, 14 | {{0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {a23, 0.0, a21}} }; 15 | 16 | double CMRRandomGenerator::m[2] = { m1, m2 }; 17 | double CMRRandomGenerator::init_s[2][3] = { {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0} }; 18 | 19 | CMRRandomGenerator::CMRRandomGenerator(int64_t n, int32_t e) 20 | { 21 | for (int i = 0; i <= 1; i++) { 22 | for (int j = 0; j <= 2; j++) { 23 | s[i][j] = init_s[i][j]; 24 | } 25 | } 26 | Advance(n, e); 27 | } 28 | 29 | void CMRRandomGenerator::Advance(int64_t n, int32_t e) 30 | { 31 | int64_t B[2][3][3]; 32 | 33 | int64_t S[2][3]; 34 | int64_t M[2]; 35 | 36 | for (int i = 0; i <= 1; i++) { 37 | m_ftoi(a[i], B[i], m[i]); 38 | v_ftoi(s[i], S[i], m[i]); 39 | M[i] = (int64_t)(m[i]); 40 | } 41 | 42 | while (e-- != 0) { 43 | for (int i = 0; i <= 1; i++) { 44 | mm_mul(B[i], B[i], B[i], M[i]); 45 | } 46 | } 47 | 48 | while (n != 0) { 49 | if ((n & 1) != 0) { 50 | for (int i = 0; i <= 1; i++) { 51 | mv_mul(B[i], S[i], S[i], M[i]); 52 | } 53 | } 54 | n >>= 1; 55 | if (n != 0) { 56 | for (int i = 0; i <= 1; i++) { 57 | mm_mul(B[i], B[i], B[i], M[i]); 58 | } 59 | } 60 | } 61 | 62 | for (int i = 0; i <= 1; i++) { 63 | v_itof(S[i], s[i], M[i]); 64 | } 65 | } 66 | 67 | double CMRRandomGenerator::NextDouble() 68 | { 69 | double p1 = mod(a12 * s[0][1] + a13 * s[0][0], m1); 70 | s[0][0] = s[0][1]; 71 | s[0][1] = s[0][2]; 72 | s[0][2] = p1; 73 | double p2 = mod(a21 * s[1][2] + a23 * s[1][0], m2); 74 | s[1][0] = s[1][1]; 75 | s[1][1] = s[1][2]; 76 | s[1][2] = p2; 77 | double p = p1 - p2; 78 | if (p < 0.0) { 79 | p += m1; 80 | } 81 | 82 | return (p + 1) * norm; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/utils/CMRRandomGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef CMR_RANDOM_GENERATOR_H 2 | #define CMR_RANDOM_GENERATOR_H 3 | 4 | #include 5 | 6 | namespace Utils 7 | { 8 | class CMRRandomGenerator 9 | { 10 | public: 11 | CMRRandomGenerator(int64_t n, int e); 12 | void Advance(int64_t n, int e); 13 | double NextDouble(); 14 | private: 15 | double s[2][3]; 16 | static double norm, m1, m2, a12, a13, a21, a23; 17 | static double a[2][3][3]; 18 | static double m[2]; 19 | static double init_s[2][3]; 20 | 21 | 22 | static double mod(double x, double m) 23 | { 24 | int64_t k = (int64_t)(x / m); 25 | x -= (double)k * m; 26 | if (x < 0.0) { 27 | x += m; 28 | } 29 | return x; 30 | } 31 | 32 | /* 33 | * Advance CMRG one step and return next number 34 | */ 35 | static int64_t ftoi(double x, double m) 36 | { 37 | if (x >= 0.0) { 38 | return (int64_t)(x); 39 | } 40 | else { 41 | return (int64_t)((double)x + (double)m); 42 | } 43 | } 44 | 45 | static double itof(int64_t i, int64_t m) 46 | { 47 | return (double)i; 48 | } 49 | 50 | static void v_ftoi(double* u, int64_t* v, double m) 51 | { 52 | for (int i = 0; i <= 2; i++) { 53 | v[i] = ftoi(u[i], m); 54 | } 55 | } 56 | 57 | static void v_itof(int64_t* u, double* v, int64_t m) 58 | { 59 | for (int i = 0; i <= 2; i++) { 60 | v[i] = itof((int64_t)u[i], m); 61 | } 62 | } 63 | 64 | static void v_copy(int64_t* u, int64_t* v) 65 | { 66 | for (int i = 0; i <= 2; i++) { 67 | v[i] = u[i]; 68 | } 69 | } 70 | 71 | static void m_ftoi(double a[][3], int64_t b[][3], double m) 72 | { 73 | for (int i = 0; i <= 2; i++) { 74 | for (int j = 0; j <= 2; j++) { 75 | b[i][j] = ftoi(a[i][j], m); 76 | } 77 | } 78 | } 79 | 80 | static void m_copy(int64_t a[][3], int64_t b[][3]) 81 | { 82 | for (int i = 0; i <= 2; i++) { 83 | for (int j = 0; j <= 2; j++) { 84 | b[i][j] = a[i][j]; 85 | } 86 | } 87 | } 88 | 89 | static void mv_mul(int64_t a[][3], int64_t* u, int64_t* v, int64_t m) 90 | { 91 | int64_t w[3]; 92 | for (int i = 0; i <= 2; i++) { 93 | w[i] = 0; 94 | for (int j = 0; j <= 2; j++) { 95 | w[i] = (a[i][j] * u[j] + w[i]) % m; 96 | } 97 | } 98 | v_copy(w, v); 99 | } 100 | 101 | static void mm_mul(int64_t a[][3], int64_t b[][3], int64_t c[][3], int64_t m) 102 | { 103 | int64_t d [3][3]; 104 | 105 | for (int i = 0; i <= 2; i++) { 106 | for (int j = 0; j <= 2; j++) { 107 | d[i][j] = 0; 108 | for (int k = 0; k <= 2; k++) { 109 | d[i][j] = (a[i][k] * b[k][j] + d[i][j]) % m; 110 | } 111 | } 112 | } 113 | m_copy(d, c); 114 | } 115 | }; 116 | } 117 | 118 | #endif // !CMR_RANDOM_GENERATOR_H 119 | -------------------------------------------------------------------------------- /src/utils/DistributionTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef DISTRIBUTION_TYPES 2 | #define DISTRIBUTION_TYPES 3 | 4 | namespace Utils 5 | { 6 | enum class Address_Distribution_Type { MIXED_STREAMING_RANDOM, STREAMING, RANDOM_UNIFORM, RANDOM_HOTCOLD }; 7 | enum class Request_Size_Distribution_Type { FIXED, NORMAL }; 8 | enum class Workload_Type { SYNTHETIC, TRACE_BASED }; 9 | enum class Request_Generator_Type { BANDWIDTH, QUEUE_DEPTH };//Time_INTERVAL: general requests based on the arrival rate definitions, DEMAND_BASED: just generate a request, every time that there is a demand 10 | } 11 | 12 | #endif // !DISTRIBUTION_TYPES 13 | -------------------------------------------------------------------------------- /src/utils/Helper_Functions.cpp: -------------------------------------------------------------------------------- 1 | #include "Helper_Functions.h" 2 | #include 3 | 4 | namespace Utils 5 | { 6 | double Combination_count(double n, double k) 7 | { 8 | if (k > n) { 9 | return 0; 10 | } 11 | 12 | if (k * 2 > n) { 13 | k = n - k; 14 | } 15 | 16 | if (k == 0) { 17 | return 1; 18 | } 19 | 20 | double result = n; 21 | for (int i = 2; i <= k; ++i) { 22 | result *= (n - i + 1); 23 | result /= i; 24 | } 25 | 26 | return result; 27 | } 28 | 29 | double Combination_count(unsigned int n, unsigned int k) 30 | { 31 | return Combination_count(double(n), double(k)); 32 | } 33 | 34 | 35 | void Euler_estimation(std::vector& mu, unsigned int b, double rho, int d, double h, double max_diff, int itr_max) 36 | { 37 | std::vector w_0, w; 38 | for (int i = 0; i <= mu.size(); i++) { 39 | if (i == 0) { 40 | w_0.push_back(1); 41 | w.push_back(1); 42 | } else { 43 | w_0.push_back(0); 44 | w.push_back(0); 45 | for (int j = i; j < mu.size(); j++) 46 | w_0[i] += mu[j]; 47 | } 48 | } 49 | 50 | double t = h; 51 | int itr = 0; 52 | double diff = 100000000000000; 53 | while (itr < itr_max && diff > max_diff) { 54 | double sigma = 0; 55 | for (unsigned int j = 1; j <= b; j++) { 56 | sigma += std::pow(w_0[j], d); 57 | } 58 | 59 | for (unsigned int i = 1; i < b; i++) { 60 | w[i] = w_0[i] + h * (1 - std::pow(w_0[i], d) - (b - sigma) * ((i * (w_0[i] - w_0[i + 1])) / (b * rho))); 61 | } 62 | 63 | diff = std::abs(w[0] - w_0[0]); 64 | for (unsigned int i = 1; i <= b; i++) { 65 | if (std::abs(w[i] - w_0[i]) > diff) { 66 | diff = std::abs(w[i] - w_0[i]); 67 | } 68 | } 69 | 70 | for (int i = 1; i < w_0.size(); i++) { 71 | w_0[i] = w[i]; 72 | } 73 | 74 | t += h; 75 | itr++; 76 | } 77 | 78 | for (unsigned int i = 0; i <= b; i++) { 79 | mu[i] = w_0[i] - w_0[i + 1]; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/utils/Helper_Functions.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPER_FUNCTIONS_H 2 | #define HELPER_FUNCTIONS_H 3 | #include 4 | 5 | namespace Utils 6 | { 7 | double Combination_count(double n, double k); 8 | double Combination_count(unsigned int n, unsigned int k); 9 | void Euler_estimation(std::vector& mu, unsigned int b, double rho, int d, double h, double max_diff, int itr_max); 10 | 11 | class Helper_Functions 12 | { 13 | public: 14 | }; 15 | } 16 | 17 | #endif // !HELPER_FUNCTIONS_H 18 | -------------------------------------------------------------------------------- /src/utils/Logical_Address_Partitioning_Unit.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGICAL_ADDRESS_PARTITIONING_UNIT_H 2 | #define LOGICAL_ADDRESS_PARTITIONING_UNIT_H 3 | 4 | #include 5 | #include "../ssd/SSD_Defs.h" 6 | #include "../ssd/Host_Interface_Defs.h" 7 | 8 | /* MQSim requires the logical address space of the SSD device to be partitioned among the concurrent flows. 9 | In fact, two different storage traces may access the same logical address, but this logical address 10 | should not be assumed to be identical when the traces are executed together. 11 | */ 12 | 13 | namespace Utils 14 | { 15 | class Logical_Address_Partitioning_Unit 16 | { 17 | public: 18 | static void Reset(); 19 | static void Allocate_logical_address_for_flows(HostInterface_Types hostinterface_type, unsigned int concurrent_stream_no, 20 | unsigned int channel_count, unsigned int chip_no_per_channel, unsigned int die_no_per_chip, unsigned int plane_no_per_die, 21 | std::vector> stream_channel_ids, std::vector> stream_chip_ids, 22 | std::vector> stream_die_ids, std::vector> stream_plane_ids, 23 | unsigned int block_no_per_plane, unsigned int page_no_per_block, unsigned int sector_no_per_page, double overprovisioning_ratio); 24 | static LHA_type Start_lha_available_to_flow(stream_id_type stream_id); 25 | static LHA_type End_lha_available_to_flow(stream_id_type stream_id); 26 | static LHA_type LHA_count_allocate_to_flow_from_host_view(stream_id_type stream_id); 27 | static LHA_type LHA_count_allocate_to_flow_from_device_view(stream_id_type stream_id); 28 | static PDA_type PDA_count_allocate_to_flow(stream_id_type stream_id); 29 | static double Get_share_of_physcial_pages_in_plane(flash_channel_ID_type channel_id, flash_chip_ID_type chip_id, flash_die_ID_type die_id, flash_plane_ID_type plane_id); 30 | static LHA_type Get_total_device_lha_count(); 31 | private: 32 | static HostInterface_Types hostinterface_type; 33 | static int****resource_list; 34 | static std::vector> stream_channel_ids; 35 | static std::vector> stream_chip_ids; 36 | static std::vector> stream_die_ids; 37 | static std::vector> stream_plane_ids; 38 | static bool initialized; 39 | static std::vector pdas_per_flow; 40 | static std::vector start_lhas_per_flow; 41 | static std::vector end_lhas_per_flow; 42 | static LHA_type total_pda_no; 43 | static LHA_type total_lha_no; 44 | static unsigned int channel_count; 45 | static unsigned int chip_no_per_channel; 46 | static unsigned int die_no_per_chip; 47 | static unsigned int plane_no_per_die; 48 | }; 49 | } 50 | 51 | #endif // !LOGICAL_ADDRESS_PARTITIONING_UNIT_H 52 | -------------------------------------------------------------------------------- /src/utils/RandomGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_GENERATOR 2 | #define RANDOM_GENERATOR 3 | 4 | #include 5 | #include "CMRRandomGenerator.h" 6 | 7 | namespace Utils 8 | { 9 | class RandomGenerator 10 | { 11 | public: 12 | RandomGenerator(int); 13 | uint32_t Get_uint(uint32_t max_value); 14 | int32_t Get_int(int32_t max_value); 15 | double FloatRandom(); 16 | double Uniform(double a, double b); 17 | uint32_t Uniform_uint(uint32_t m, uint32_t n); 18 | int64_t Uniform_long(int64_t m, int64_t n); 19 | uint64_t Uniform_ulong(uint64_t m, uint64_t n); 20 | double Exponential(double mean); 21 | double Erlang(double x, double s); 22 | double HyperExponential(double x, double s); 23 | double Normal(double x, double s); 24 | double LogNormal(double x, double s); 25 | int64_t Geometric0(double x); 26 | int64_t Geometric1(double x); 27 | double Hyper_geometric(double x, double s); 28 | int64_t Binomial(int64_t n, double u); 29 | int64_t Poisson(double x); 30 | double Weibull(double alpha, double beta); 31 | double Pareto(double alpha, double beta); 32 | double Inverse(double min, double max); 33 | double Triangular(double min, double middle, double max); 34 | private: 35 | CMRRandomGenerator* rand; 36 | int seed; 37 | double Normal_z2; 38 | }; 39 | } 40 | 41 | #endif // !RANDOM_GENERATOR 42 | -------------------------------------------------------------------------------- /src/utils/StringTools.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "StringTools.h" 4 | 5 | namespace Utils 6 | { 7 | } -------------------------------------------------------------------------------- /src/utils/StringTools.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_TOOLS_H 2 | #define STRING_TOOLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Utils 9 | { 10 | class Helper_Functions 11 | { 12 | public: 13 | static std::string Path_separator() 14 | { 15 | #ifdef _WIN32 16 | return "\\"; 17 | #else 18 | return "/"; 19 | #endif 20 | } 21 | static void Tokenize(const std::string& str, char delimiter, std::vector& output_tokens_list) 22 | { 23 | int size = (int) str.size(); 24 | int start = 0, end = 0; 25 | while (end < size) { 26 | if (str[end] == delimiter && start <= end) { 27 | output_tokens_list.push_back(std::string(str.substr(start, end - start + 1))); 28 | start = end + 1; 29 | } 30 | end++; 31 | } 32 | if (str[end - 1] != delimiter) { 33 | output_tokens_list.push_back(std::string(str.substr(start, end - start))); 34 | } 35 | } 36 | 37 | static void Remove_cr(std::string& str)//remove carriage return in linux 38 | { 39 | if (str[str.size() - 1] == '\r') { 40 | str.erase(str.size() - 1, 1); 41 | } 42 | } 43 | }; 44 | } 45 | 46 | #endif -------------------------------------------------------------------------------- /src/utils/Workload_Statistics.h: -------------------------------------------------------------------------------- 1 | #ifndef WORKLOAD_STATISTICS_H 2 | #define WORKLOAD_STATISTICS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../sim/Sim_Defs.h" 9 | #include "../ssd/SSD_Defs.h" 10 | #include "../utils/DistributionTypes.h" 11 | 12 | namespace Utils 13 | { 14 | #define MAX_REQSIZE_HISTOGRAM_ITEMS 1024 15 | #define MAX_ARRIVAL_TIME_HISTOGRAM (1000000) 16 | #define MIN_HOT_REGION_TRAFFIC_RATIO 0.5 17 | #define HOT_REGION_METRIC 2.5 18 | #define STATISTICALLY_SUFFICIENT_WRITES_FOR_PRECONDITIONING 10000 19 | 20 | struct Address_Histogram_Unit 21 | { 22 | int Access_count; 23 | uint64_t Accessed_sub_units; 24 | }; 25 | 26 | //Parameters defined in: B. Van Houdt, "On the necessity of hot and cold data identification to reduce the write amplification in flash-based SSDs", Perf. Eval., 2014. 27 | struct Workload_Statistics 28 | { 29 | Utils::Workload_Type Type; 30 | stream_id_type Stream_id; 31 | double Initial_occupancy_ratio;//Ratio of the logical storage space that is fill with data in steady-state 32 | unsigned int Replay_no; 33 | unsigned int Total_generated_reqeusts; 34 | 35 | int random_request_type_generator_seed; 36 | double Read_ratio; 37 | std::vector Write_arrival_time, Read_arrival_time;//Histogram with 1us resolution 38 | 39 | Utils::Address_Distribution_Type Address_distribution_type; 40 | double Working_set_ratio; 41 | unsigned int Total_accessed_lbas; 42 | /*Rosenblum hot/cold model: 43 | - M. Rosenblum and J. K. Ousterhout, "The design and implementation of a log-structured file system", ACM CSUR, 1992. 44 | A fraction f of the complete address space corresponds to hot data and the remaining fraction to cold data. The fraction 45 | of write operations to the hot data is denoted as r*/ 46 | double Ratio_of_hot_addresses_to_whole_working_set;//The f parameter in the Rosenblum hot/cold model 47 | double Ratio_of_traffic_accessing_hot_region;//The r parameter in the Rosenblum hot/cold model 48 | int random_address_generator_seed; 49 | int random_hot_cold_generator_seed; 50 | int random_hot_address_generator_seed; 51 | std::map Write_address_access_pattern, Read_address_access_pattern; 52 | std::set Write_read_shared_addresses; 53 | LHA_type First_Accessed_Address, Last_Accessed_Address, Min_LHA, Max_LHA; 54 | LHA_type hot_region_end_lsa; 55 | LHA_type streaming_next_address; 56 | bool generate_aligned_addresses; 57 | unsigned int alignment_value;; 58 | 59 | Utils::Request_Generator_Type generator_type; 60 | unsigned int Request_queue_depth; 61 | int random_time_interval_generator_seed; 62 | sim_time_type Average_inter_arrival_time_nano_sec; 63 | 64 | Utils::Request_Size_Distribution_Type Request_size_distribution_type; 65 | int random_request_size_generator_seed; 66 | unsigned int Average_request_size_sector; 67 | unsigned int STDEV_reuqest_size; 68 | std::vector Write_size_histogram, Read_size_histogram;//Histogram with 1 sector resolution 69 | }; 70 | } 71 | 72 | #endif// !WORKLOAD_STATISTICS_H 73 | -------------------------------------------------------------------------------- /src/utils/XMLWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "XMLWriter.h" 2 | #include "../sim/Engine.h" 3 | 4 | namespace Utils 5 | { 6 | bool XmlWriter::exists(const std::string fileName) { 7 | std::fstream checkFile(fileName); 8 | return checkFile.is_open(); 9 | } 10 | 11 | bool XmlWriter::Open(const std::string strFile) { 12 | 13 | outFile.open(strFile); 14 | if (outFile.is_open()) { 15 | outFile << "\n"; 16 | indent = 0; 17 | openTags = 0; 18 | openElements = 0; 19 | 20 | return true; 21 | } 22 | 23 | return false; 24 | } 25 | 26 | void XmlWriter::Close() 27 | { 28 | if (outFile.is_open()) { 29 | outFile.close(); 30 | } 31 | } 32 | 33 | void XmlWriter::Write_open_tag(const std::string openTag) { 34 | if (outFile.is_open()) { 35 | for (int i = 0; i < indent; i++) { 36 | outFile << "\t"; 37 | } 38 | tempOpenTag.resize(openTags + 1); 39 | outFile << "<" << openTag << ">\n"; 40 | tempOpenTag[openTags] = openTag; 41 | indent += 1; 42 | openTags += 1; 43 | } else { 44 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 45 | } 46 | } 47 | 48 | void XmlWriter::Write_attribute_string(const std::string attribute_name, const std::string attribute_value) 49 | { 50 | if (outFile.is_open()) { 51 | for (int i = 0; i < indent + 1; i++) { 52 | outFile << "\t"; 53 | } 54 | 55 | outFile << " <" << attribute_name + ">" + attribute_value + "\n"; 56 | } else { 57 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 58 | } 59 | } 60 | 61 | void XmlWriter::Write_close_tag() { 62 | if (outFile.is_open()) { 63 | indent -= 1; 64 | for (int i = 0; i < indent; i++) { 65 | outFile << "\t"; 66 | } 67 | outFile << "\n"; 68 | tempOpenTag.resize(openTags - 1); 69 | openTags -= 1; 70 | } else { 71 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 72 | } 73 | } 74 | 75 | void XmlWriter::Write_start_element_tag(const std::string elementTag) { 76 | if (outFile.is_open()) { 77 | for (int i = 0; i < indent; i++) { 78 | outFile << "\t"; 79 | } 80 | tempElementTag.resize(openElements + 1); 81 | tempElementTag[openElements] = elementTag; 82 | openElements += 1; 83 | outFile << "<" << elementTag; 84 | } else { 85 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 86 | } 87 | } 88 | 89 | void XmlWriter::Write_end_element_tag() 90 | { 91 | if (outFile.is_open()) { 92 | outFile << "/>\n"; 93 | tempElementTag.resize(openElements - 1); 94 | openElements -= 1; 95 | } else { 96 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 97 | } 98 | } 99 | 100 | void XmlWriter::Write_attribute(const std::string outAttribute) 101 | { 102 | if (outFile.is_open()) { 103 | outFile << " " << outAttribute; 104 | } else { 105 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 106 | } 107 | } 108 | 109 | void XmlWriter::Write_attribute_string_inline(const std::string attribute_name, const std::string attribute_value) 110 | { 111 | if (outFile.is_open()) { 112 | outFile << " "; 113 | outFile << attribute_name + "=\"" + attribute_value + "\""; 114 | } else { 115 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 116 | } 117 | } 118 | 119 | void XmlWriter::Write_string(const std::string outString) 120 | { 121 | if (outFile.is_open()) { 122 | outFile << ">" << outString; 123 | } else { 124 | PRINT_ERROR("The XML output file is closed. Unable to write to file"); 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /src/utils/XMLWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef XMLWRITE_H 2 | #define XMLWRITE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Utils 10 | { 11 | class XmlWriter { 12 | public: 13 | bool Open(const std::string); 14 | void Close(); 15 | bool exists(const std::string); 16 | void Write_open_tag(const std::string); 17 | void Write_close_tag(); 18 | void Write_start_element_tag(const std::string); 19 | void Write_end_element_tag(); 20 | void Write_attribute(const std::string); 21 | void Write_string(const std::string); 22 | void Write_attribute_string(const std::string attribute_name, const std::string attribute_value); 23 | void Write_attribute_string_inline(const std::string attribute_name, const std::string attribute_value); 24 | private: 25 | std::ofstream outFile; 26 | int indent; 27 | int openTags; 28 | int openElements; 29 | std::vector tempOpenTag; 30 | std::vector tempElementTag; 31 | }; 32 | } 33 | 34 | #endif // !XMLWRITE_H 35 | -------------------------------------------------------------------------------- /src/utils/rapidxml/license.txt: -------------------------------------------------------------------------------- 1 | Use of this software is granted under one of the following two licenses, 2 | to be chosen freely by the user. 3 | 4 | 1. Boost Software License - Version 1.0 - August 17th, 2003 5 | =============================================================================== 6 | 7 | Copyright (c) 2006, 2007 Marcin Kalicinski 8 | 9 | Permission is hereby granted, free of charge, to any person or organization 10 | obtaining a copy of the software and accompanying documentation covered by 11 | this license (the "Software") to use, reproduce, display, distribute, 12 | execute, and transmit the Software, and to prepare derivative works of the 13 | Software, and to permit third-parties to whom the Software is furnished to 14 | do so, all subject to the following: 15 | 16 | The copyright notices in the Software and this entire statement, including 17 | the above license grant, this restriction and the following disclaimer, 18 | must be included in all copies of the Software, in whole or in part, and 19 | all derivative works of the Software, unless such copies or derivative 20 | works are solely in the form of machine-executable object code generated by 21 | a source language processor. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 26 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 27 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 28 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | DEALINGS IN THE SOFTWARE. 30 | 31 | 2. The MIT License 32 | =============================================================================== 33 | 34 | Copyright (c) 2006, 2007 Marcin Kalicinski 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 40 | of the Software, and to permit persons to whom the Software is furnished to do so, 41 | subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 49 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 52 | IN THE SOFTWARE. 53 | -------------------------------------------------------------------------------- /src/utils/rapidxml/rapidxml_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAPIDXML_UTILS_HPP_INCLUDED 2 | #define RAPIDXML_UTILS_HPP_INCLUDED 3 | 4 | // Copyright (C) 2006, 2009 Marcin Kalicinski 5 | // Version 1.13 6 | // Revision $DateTime: 2009/05/13 01:46:17 $ 7 | //! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful 8 | //! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. 9 | 10 | #include "rapidxml.hpp" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace rapidxml 17 | { 18 | 19 | //! Represents data loaded from a file 20 | template 21 | class file 22 | { 23 | 24 | public: 25 | 26 | //! Loads file into the memory. Data will be automatically destroyed by the destructor. 27 | //! \param filename Filename to load. 28 | file(const char *filename) 29 | { 30 | using namespace std; 31 | 32 | // Open stream 33 | basic_ifstream stream(filename, ios::binary); 34 | if (!stream) 35 | throw runtime_error(string("cannot open file ") + filename); 36 | stream.unsetf(ios::skipws); 37 | 38 | // Determine stream size 39 | stream.seekg(0, ios::end); 40 | size_t size = stream.tellg(); 41 | stream.seekg(0); 42 | 43 | // Load data and add terminating 0 44 | m_data.resize(size + 1); 45 | stream.read(&m_data.front(), static_cast(size)); 46 | m_data[size] = 0; 47 | } 48 | 49 | //! Loads file into the memory. Data will be automatically destroyed by the destructor 50 | //! \param stream Stream to load from 51 | file(std::basic_istream &stream) 52 | { 53 | using namespace std; 54 | 55 | // Load data and add terminating 0 56 | stream.unsetf(ios::skipws); 57 | m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); 58 | if (stream.fail() || stream.bad()) 59 | throw runtime_error("error reading stream"); 60 | m_data.push_back(0); 61 | } 62 | 63 | //! Gets file data. 64 | //! \return Pointer to data of file. 65 | Ch *data() 66 | { 67 | return &m_data.front(); 68 | } 69 | 70 | //! Gets file data. 71 | //! \return Pointer to data of file. 72 | const Ch *data() const 73 | { 74 | return &m_data.front(); 75 | } 76 | 77 | //! Gets file data size. 78 | //! \return Size of file data, in characters. 79 | std::size_t size() const 80 | { 81 | return m_data.size(); 82 | } 83 | 84 | private: 85 | 86 | std::vector m_data; // File data 87 | 88 | }; 89 | 90 | //! Counts children of node. Time complexity is O(n). 91 | //! \return Number of children of node 92 | template 93 | inline std::size_t count_children(xml_node *node) 94 | { 95 | xml_node *child = node->first_node(); 96 | std::size_t count = 0; 97 | while (child) 98 | { 99 | ++count; 100 | child = child->next_sibling(); 101 | } 102 | return count; 103 | } 104 | 105 | //! Counts attributes of node. Time complexity is O(n). 106 | //! \return Number of attributes of node 107 | template 108 | inline std::size_t count_attributes(xml_node *node) 109 | { 110 | xml_attribute *attr = node->first_attribute(); 111 | std::size_t count = 0; 112 | while (attr) 113 | { 114 | ++count; 115 | attr = attr->next_attribute(); 116 | } 117 | return count; 118 | } 119 | 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /ssdconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.00000 5 | 4 6 | 400000 7 | false 8 | 1000000 9 | 10 | 11 | 321 12 | false 13 | FLASH 14 | NVME 15 | 65535 16 | 512 17 | ADVANCED 18 | SHARED 19 | 16777216 20 | 8192 21 | 1600 22 | 1 23 | 13 24 | 13 25 | 13 26 | PAGE_LEVEL 27 | true 28 | 268435456 29 | SHARED 30 | PCWD 31 | OUT_OF_ORDER 32 | 0.127 33 | 0.01000 34 | GREEDY 35 | false 36 | true 37 | 0.001000 38 | false 39 | false 40 | 200 41 | 100000 42 | 10000 43 | 20000 44 | 8 45 | 1 46 | 1200 47 | 8 48 | NVDDR2 49 | 50 | SLC 51 | ERASE 52 | 3000 53 | 3000 54 | 3000 55 | 100000 56 | 100000 57 | 100000 58 | 1000000 59 | 10000 60 | 100000 61 | 20000 62 | 1 63 | 4 64 | 512 65 | 512 66 | 16384 67 | 448 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /workload.IO_Flow.No_0.log_read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spypaul/MQSim_CXL/357ed7bde9c780c75418122c2a87a9f5c12cf61d/workload.IO_Flow.No_0.log_read -------------------------------------------------------------------------------- /workload.IO_Flow.No_0.log_write: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spypaul/MQSim_CXL/357ed7bde9c780c75418122c2a87a9f5c12cf61d/workload.IO_Flow.No_0.log_write -------------------------------------------------------------------------------- /workload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | TURNED_OFF 7 | 0,1,2,3,4,5,6,7 8 | 0,1,2,3,4,5,6,7 9 | 0 10 | 0,1,2,3 11 | 30 12 | traces/synthetic_stride_p.trace 13 | 100 14 | 1 15 | NANOSECOND 16 | 17 | 18 | -------------------------------------------------------------------------------- /workload_settings/workload_for_synthetic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | WRITE_CACHE 7 | 0,1,2,3 8 | 0 9 | 0 10 | 0,1,2,3 11 | 70 12 | 100 13 | QUEUE_DEPTH 14 | 50 15 | RANDOM_UNIFORM 16 | 0 17 | true 18 | 1 19 | FIXED 20 | 8 21 | 0 22 | 798 23 | 32 24 | 4096 25 | 0 26 | 400000000 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /workload_settings/workload_for_trace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | WRITE_CACHE 7 | 0,1,2,3 8 | 0 9 | 0 10 | 0,1,2,3 11 | 70 12 | traces/ 13 | 100 14 | 1 15 | NANOSECOND 16 | 17 | 18 | -------------------------------------------------------------------------------- /workload_syntheic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HIGH 6 | WRITE_CACHE 7 | 0,1,2,3 8 | 0 9 | 0 10 | 0,1,2,3 11 | 70 12 | 100 13 | QUEUE_DEPTH 14 | 50 15 | RANDOM_UNIFORM 16 | 0 17 | true 18 | 1 19 | FIXED 20 | 8 21 | 0 22 | 798 23 | 32 24 | 4096 25 | 0 26 | 400000000 27 | 28 | 29 | 30 | --------------------------------------------------------------------------------