/* * Copyright (c) 2021, RPTU Kaiserslautern-Landau * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: * Derek Christ * Marco Mörz */ #include #include #include #include #include #include #include #include #include using namespace DRAMSys::Config; class ConfigurationTest : public ::testing::Test { protected: ConfigurationTest() : memSpec(createMemSpec()), tracePlayer(createTracePlayer()), traceGeneratorOneState(createTraceGeneratorOneState()), traceGeneratorMultipleStates(createTraceGeneratorMultipleStates()), traceHammer(createTraceHammer()) { } static DRAMUtils::MemSpec::MemSpecVariant createMemSpec(); static DRAMSys::Config::TracePlayer createTracePlayer(); static DRAMSys::Config::TrafficGenerator createTraceGeneratorOneState(); static DRAMSys::Config::TrafficGeneratorStateMachine createTraceGeneratorMultipleStates(); static DRAMSys::Config::RowHammer createTraceHammer(); static std::vector addressMapBitVector(std::initializer_list> bits) { auto result = std::vector(); for (const auto& bit : bits) { result.push_back(DRAMSys::Config::AddressMapping::BitEntry({bit.begin(), bit.end()})); } return result; }; static std::vector addressMapBitVector(std::vector bits) { return {bits.begin(), bits.end()}; }; DRAMSys::Config::AddressMapping addressMapping{ addressMapBitVector({0, 1}), addressMapBitVector({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}), addressMapBitVector({16}), addressMapBitVector({13, 14, 15}), addressMapBitVector({17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}), addressMapBitVector({33}), std::nullopt, std::nullopt, std::nullopt}; DRAMSys::Config::McConfig mcConfig{PagePolicyType::Open, SchedulerType::FrFcfs, 0, 0, SchedulerBufferType::Bankwise, 8, std::nullopt, std::nullopt, CmdMuxType::Oldest, RespQueueType::Fifo, RefreshPolicyType::AllBank, 0, 0, PowerDownPolicyType::NoPowerDown, ArbiterType::Simple, 128, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}; DRAMSys::Config::SimConfig simConfig{0, false, true, false, false, false, {"ddr5"}, true, DRAMSys::Config::StoreModeType::NoStorage, false, false, 1000, 1e-3, std::nullopt}; DRAMUtils::MemSpec::MemSpecVariant memSpec; DRAMSys::Config::TracePlayer tracePlayer; DRAMSys::Config::TrafficGenerator traceGeneratorOneState; DRAMSys::Config::TrafficGeneratorStateMachine traceGeneratorMultipleStates; DRAMSys::Config::RowHammer traceHammer; std::vector traceSetup{ { DRAMSys::Config::Initiator{tracePlayer}, DRAMSys::Config::Initiator{traceGeneratorOneState}, DRAMSys::Config::Initiator{traceGeneratorMultipleStates}, DRAMSys::Config::Initiator{traceHammer} } }; DRAMSys::Config::Configuration configuration{ addressMapping, mcConfig, memSpec, simConfig, "std::string_simulationId", traceSetup}; }; DRAMUtils::MemSpec::MemSpecVariant ConfigurationTest::createMemSpec() { DRAMUtils::MemSpec::MemArchitectureSpecTypeDDR5 memArchitectureSpec { 2, // nbrOfChannels 8, // nbrOfDevices 1, // nbrOfRanks 1, // nbrOfDIMMRanks 1, // nbrOfPhysicalRanks 1, // nbrOfLogicalRanks 16, // nbrOfBanks 8, // nbrOfBankGroups 65536, // nbrOfRows 2048, // nbrOfColumns 16, // burstLength 2, // dataRate 4, // width DRAMUtils::MemSpec::RefModeTypeDDR5::REF_MODE_1, // RefMode 16, // maxBurstLength 1, // cmdMode 32, // RAAIMT 96, // RAAMMT 1 // RAADEC }; DRAMUtils::MemSpec::MemTimingSpecTypeDDR5 memTimingSpec { 625, // tCK 52, // RAS 22, // RCD 12, // RTP 20, // WL 48, // WR 22, // RP 2, // PPD 22, // RL 1, // RPRE 0, // RPST 0, // RDDQS 2, // WPRE 0, // WPST 8, // CCD_L_slr 32, // CCD_L_WR_slr 16, // CCD_L_WR2_slr 8, // CCD_M_slr 32, // CCD_M_WR_slr 8, // CCD_S_slr 8, // CCD_S_WR_slr 0, // CCD_dlr 0, // CCD_WR_dlr 0, // CCD_WR_dpr 8, // RRD_L_slr 8, // RRD_S_slr 0, // RRD_dlr 32, // FAW_slr 0, // FAW_dlr 16, // WTR_L 16, // WTR_M 4, // WTR_S 312, // RFC1_slr 208, // RFC2_slr 0, // RFC1_dlr 0, // RFC2_dlr 0, // RFC1_dpr 0, // RFC2_dpr 184, // RFCsb_slr 0, // RFCsb_dlr 6240, // REFI1 3120, // REFI2 1560, // REFISB 48, // REFSBRD_slr 0, // REFSBRD_dlr 2, // RTRS 8, // CPDED 12, // PD 12, // XP 2, // ACTPDEN 2, // PRPDEN 2 // REFPDEN }; DRAMUtils::MemSpec::MemImpedanceSpecTypeDDR5 memImpedanceSpec { true, // ck_termination 1e6, // ck_R_eq 1e-12, // ck_dyn_E true, // ca_termination 1e6, // ca_R_eq 1e-12, // ca_dyn_E true, // rdq_termination 1e6, // rdq_R_eq 1e-12, // rdq_dyn_E true, // wdq_termination 1e6, // wdq_R_eq 1e-12, // wdq_dyn_E true, // rdqs_termination 1e6, // rdqs_R_eq 1e-12, // rdqs_dyn_E true, // wdqs_termination 1e6, // wdqs_R_eq 1e-12 // wdqs_dyn_E }; DRAMUtils::MemSpec::MemPowerSpecTypeDDR5 memPowerSpec { 0, // vdd 0, // idd0 0, // idd2n 0, // idd3n 0, // idd4r 0, // idd4w 0, // idd5c 0, // idd6n 0, // idd2p 0, // idd3p 0, // vpp 0, // ipp0 0, // ipp2n 0, // ipp3n 0, // ipp4r 0, // ipp4w 0, // ipp5c 0, // ipp6n 0, // ipp2p 0, // ipp3p 0, // idd5b // RefModeTypeDDR5::REF_MODE_1 0, // idd5f // RefModeTypeDDR5::REF_MODE_2 0, // ipp5b // RefModeTypeDDR5::REF_MODE_1 0, // ipp5f // RefModeTypeDDR5::REF_MODE_2 0, // vddq 0, // iBeta_vdd 0 // iBeta_vpp }; DRAMUtils::MemSpec::MemSpecVariant variant; DRAMUtils::MemSpec::MemSpecDDR5 memspec { DRAMUtils::MemSpec::BaseMemSpec{}, // base "JEDEC_2x8x2Gbx4_DDR5-3200A", // memoryId memArchitectureSpec, // memarchitecturespec memPowerSpec, // mempowerspec memTimingSpec, // memtimingspec std::nullopt, // bankwisespec memImpedanceSpec, // memimpedancespec std::nullopt // dataratespec }; variant.setVariant(memspec); return variant; } DRAMSys::Config::TracePlayer ConfigurationTest::createTracePlayer() { DRAMSys::Config::TracePlayer player; player.clkMhz = 100; player.dataLength = 64; player.name = "mytrace.stl"; return player; } DRAMSys::Config::TrafficGenerator ConfigurationTest::createTraceGeneratorOneState() { DRAMSys::Config::TrafficGenerator gen; gen.clkMhz = 100; gen.dataLength = 64; gen.name = "MyTestGen"; gen.numRequests = 1000; gen.rwRatio = 0.5; gen.addressDistribution = DRAMSys::Config::AddressDistribution::Random; gen.addressIncrement = {}; gen.minAddress = {}; gen.maxAddress = {}; return gen; } DRAMSys::Config::TrafficGeneratorStateMachine ConfigurationTest::createTraceGeneratorMultipleStates() { DRAMSys::Config::TrafficGeneratorStateMachine gen; gen.clkMhz = 100; gen.dataLength = 64; gen.name = "MyTestGen"; gen.maxPendingReadRequests = 8; DRAMSys::Config::TrafficGeneratorActiveState state0; state0.numRequests = 1000; state0.rwRatio = 0.5; state0.addressDistribution = DRAMSys::Config::AddressDistribution::Sequential; state0.addressIncrement = 256; state0.minAddress = {}; state0.maxAddress = 1024; state0.id = 0; DRAMSys::Config::TrafficGeneratorActiveState state1; state1.numRequests = 100; state1.rwRatio = 0.75; state1.addressDistribution = DRAMSys::Config::AddressDistribution::Sequential; state1.addressIncrement = 512; state1.minAddress = 1024; state1.maxAddress = 2048; state1.id = 1; gen.states.push_back(state0); gen.states.push_back(state1); DRAMSys::Config::TrafficGeneratorStateTransition transistion0{0, 1, 1.0}; gen.transitions.push_back(transistion0); return gen; } DRAMSys::Config::RowHammer ConfigurationTest::createTraceHammer() { DRAMSys::Config::RowHammer hammer; hammer.clkMhz = 100; hammer.dataLength = 64; hammer.name = "MyTestHammer"; hammer.numRequests = 4000; hammer.rowIncrement = 2097152; return hammer; } TEST_F(ConfigurationTest, ToJson) { json_t config_json; config_json["simulation"] = configuration; std::ifstream file("reference.json"); ASSERT_TRUE(file.is_open()); json_t reference_json = json_t::parse(file); std::cout << reference_json.dump(4) << std::endl; EXPECT_EQ(config_json, reference_json); } TEST(Configuration, FromToJson) { std::ifstream file("reference.json"); ASSERT_TRUE(file.is_open()); json_t reference_json = json_t::parse(file); DRAMSys::Config::Configuration reference_configuration = reference_json["simulation"].get(); json_t new_json; new_json["simulation"] = reference_configuration; EXPECT_EQ(new_json, reference_json); } TEST_F(ConfigurationTest, DumpConfiguration) { // This test does not test anything. It just dumps the configuration to stdout for manual // inspection. json_t json; json["simulation"] = configuration; std::cout << json.dump(4) << std::endl; } TEST(Configuration, FromPath) { // Test should not throw exceptions Configuration config = from_path("reference.json"); } TEST(RefreshPolicyType, BackwardsCompatibility) { // Deserializing EXPECT_EQ(json_t("Rankwise").get(), RefreshPolicyType::AllBank); EXPECT_EQ(json_t("Bankwise").get(), RefreshPolicyType::PerBank); EXPECT_EQ(json_t("Groupwise").get(), RefreshPolicyType::SameBank); // Serializing EXPECT_EQ(json_t(RefreshPolicyType::AllBank).get(), "AllBank"); EXPECT_EQ(json_t(RefreshPolicyType::PerBank).get(), "PerBank"); EXPECT_EQ(json_t(RefreshPolicyType::SameBank).get(), "SameBank"); } TEST_F(ConfigurationTest, SimConfig) { std::string_view simconfig_string = R"( { "simconfig": { "AddressOffset": 0, "CheckTLM2Protocol": false, "DatabaseRecording": true, "Debug": false, "EnableWindowing": false, "PowerAnalysis": false, "SimulationName": "ddr5", "SimulationProgressBar": true, "StoreMode": "NoStorage", "ThermalSimulation": false, "UseMalloc": false, "WindowSize": 1000, "SimulationTime": 1e-3 } } )"; json_t simconfig_reference = json_t::parse(simconfig_string); json_t simconfig_test; simconfig_test[SimConfig::KEY] = simConfig; EXPECT_EQ(simconfig_test, simconfig_reference); } TEST_F(ConfigurationTest, McConfig) { std::string_view mcconfig_string = R"( { "mcconfig": { "Arbiter": "Simple", "CmdMux": "Oldest", "HighWatermark": 0, "LowWatermark": 0, "MaxActiveTransactions": 128, "PagePolicy": "Open", "PowerDownPolicy": "NoPowerDown", "RefreshMaxPostponed": 0, "RefreshMaxPulledin": 0, "RefreshPolicy": "AllBank", "RequestBufferSize": 8, "RespQueue": "Fifo", "Scheduler": "FrFcfs", "SchedulerBuffer": "Bankwise" } } )"; json_t mcconfig_reference = json_t::parse(mcconfig_string); json_t mcconfig_test; mcconfig_test[McConfig::KEY] = mcConfig; EXPECT_EQ(mcconfig_test, mcconfig_reference); } TEST_F(ConfigurationTest, MemSpec) { std::string_view memspec_string = R"( { "memspec": { "memarchitecturespec": { "RAADEC": 1, "RAAIMT": 32, "RAAMMT": 96, "burstLength": 16, "cmdMode": 1, "dataRate": 2, "maxBurstLength": 16, "nbrOfBankGroups": 8, "nbrOfBanks": 16, "nbrOfChannels": 2, "nbrOfColumns": 2048, "nbrOfDIMMRanks": 1, "nbrOfDevices": 8, "nbrOfLogicalRanks": 1, "nbrOfPhysicalRanks": 1, "nbrOfRanks": 1, "nbrOfRows": 65536, "RefMode": 1, "width": 4 }, "memimpedancespec": { "ck_termination": true, "ck_R_eq": 1e6, "ck_dyn_E": 1e-12, "ca_termination": true, "ca_R_eq": 1e6, "ca_dyn_E": 1e-12, "rdq_termination": true, "rdq_R_eq": 1e6, "rdq_dyn_E": 1e-12, "wdq_termination": true, "wdq_R_eq": 1e6, "wdq_dyn_E": 1e-12, "wdqs_termination": true, "wdqs_R_eq": 1e6, "wdqs_dyn_E": 1e-12, "rdqs_termination": true, "rdqs_R_eq": 1e6, "rdqs_dyn_E": 1e-12 }, "memoryId": "JEDEC_2x8x2Gbx4_DDR5-3200A", "memoryType": "DDR5", "mempowerspec": { "vdd": 0.0, "idd0": 0.0, "idd2n": 0.0, "idd3n": 0.0, "idd4r": 0.0, "idd4w": 0.0, "idd5c": 0.0, "idd6n": 0.0, "idd2p": 0.0, "idd3p": 0.0, "vpp": 0.0, "ipp0": 0.0, "ipp2n": 0.0, "ipp3n": 0.0, "ipp4r": 0.0, "ipp4w": 0.0, "ipp5c": 0.0, "ipp6n": 0.0, "ipp2p": 0.0, "ipp3p": 0.0, "idd5b": 0.0, "idd5f": 0.0, "ipp5b": 0.0, "ipp5f": 0.0, "vddq": 0.0, "iBeta_vdd": 0.0, "iBeta_vpp": 0.0 }, "memtimingspec": { "RCD": 22, "PPD": 2, "RP": 22, "RAS": 52, "RL": 22, "RTP": 12, "RPRE": 1, "RPST": 0, "RDDQS": 0, "WL": 20, "WPRE": 2, "WPST": 0, "WR": 48, "CCD_L_slr": 8, "CCD_L_WR_slr": 32, "CCD_L_WR2_slr": 16, "CCD_M_slr": 8, "CCD_M_WR_slr": 32, "CCD_S_slr": 8, "CCD_S_WR_slr": 8, "CCD_dlr": 0, "CCD_WR_dlr": 0, "CCD_WR_dpr": 0, "RRD_L_slr": 8, "RRD_S_slr": 8, "RRD_dlr": 0, "FAW_slr": 32, "FAW_dlr": 0, "WTR_L": 16, "WTR_M": 16, "WTR_S": 4, "RFC1_slr": 312, "RFC2_slr": 208, "RFC1_dlr": 0, "RFC2_dlr": 0, "RFC1_dpr": 0, "RFC2_dpr": 0, "RFCsb_slr": 184, "RFCsb_dlr": 0, "REFI1": 6240, "REFI2": 3120, "REFISB": 1560, "REFSBRD_slr": 48, "REFSBRD_dlr": 0, "RTRS": 2, "CPDED": 8, "PD": 12, "XP": 12, "ACTPDEN": 2, "PRPDEN": 2, "REFPDEN": 2, "tCK": 625 } } } )"; json_t memspec_reference = json_t::parse(memspec_string); json_t memspec_test; memspec_test[MemSpecConstants::KEY] = memSpec; EXPECT_EQ(memspec_test, memspec_reference); } TEST_F(ConfigurationTest, AddressMapping) { std::string_view addressmapping_string = R"( { "addressmapping": { "BANKGROUP_BIT": [ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ], "BANK_BIT": [ 13, 14, 15 ], "BYTE_BIT": [ 0, 1 ], "COLUMN_BIT": [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "RANK_BIT": [ 33 ], "ROW_BIT": [ 16 ] } } )"; json_t addressmapping_reference = json_t::parse(addressmapping_string); json_t addressmapping_test; addressmapping_test[AddressMapping::KEY] = addressMapping; EXPECT_EQ(addressmapping_test, addressmapping_reference); } TEST_F(ConfigurationTest, TraceSetup) { std::string_view tracesetup_string = R"( { "tracesetup": [ { "type": "player", "clkMhz": 100, "dataLength": 64, "name": "mytrace.stl" }, { "type": "generator", "addressDistribution": "random", "clkMhz": 100, "dataLength": 64, "name": "MyTestGen", "numRequests": 1000, "rwRatio": 0.5 }, { "type": "statemachine", "clkMhz": 100, "dataLength": 64, "maxPendingReadRequests": 8, "name": "MyTestGen", "states": [ { "addressDistribution": "sequential", "addressIncrement": 256, "id": 0, "maxAddress": 1024, "numRequests": 1000, "rwRatio": 0.5 }, { "addressDistribution": "sequential", "addressIncrement": 512, "id": 1, "maxAddress": 2048, "minAddress": 1024, "numRequests": 100, "rwRatio": 0.75 } ], "transitions": [ { "from": 0, "probability": 1.0, "to": 1 } ] }, { "type": "rowhammer", "clkMhz": 100, "dataLength": 64, "name": "MyTestHammer", "numRequests": 4000, "rowIncrement": 2097152 } ] } )"; json_t tracesetup_reference = json_t::parse(tracesetup_string); json_t tracesetup_test; tracesetup_test[TraceSetupConstants::KEY] = traceSetup; EXPECT_EQ(tracesetup_test, tracesetup_reference); }