586 lines
20 KiB
C++
586 lines
20 KiB
C++
/*
|
|
* 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
|
|
*/
|
|
|
|
#include <DRAMSys/config/DRAMSysConfiguration.h>
|
|
#include <DRAMSys/util/json.h>
|
|
|
|
#include <fstream>
|
|
#include <gtest/gtest.h>
|
|
#include <iostream>
|
|
#include <unordered_map>
|
|
|
|
using namespace DRAMSys::Config;
|
|
|
|
class ConfigurationTest : public ::testing::Test
|
|
{
|
|
protected:
|
|
ConfigurationTest() :
|
|
memSpec(createMemSpec()),
|
|
tracePlayer(createTracePlayer()),
|
|
traceGeneratorOneState(createTraceGeneratorOneState()),
|
|
traceGeneratorMultipleStates(createTraceGeneratorMultipleStates()),
|
|
traceHammer(createTraceHammer())
|
|
{
|
|
}
|
|
|
|
static DRAMSys::Config::MemSpec createMemSpec();
|
|
|
|
static DRAMSys::Config::TracePlayer createTracePlayer();
|
|
static DRAMSys::Config::TrafficGenerator createTraceGeneratorOneState();
|
|
static DRAMSys::Config::TrafficGeneratorStateMachine createTraceGeneratorMultipleStates();
|
|
static DRAMSys::Config::RowHammer createTraceHammer();
|
|
|
|
static std::vector<DRAMSys::Config::AddressMapping::BitEntry>
|
|
addressMapBitVector(std::vector<unsigned> 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};
|
|
|
|
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,
|
|
{"error.csv"},
|
|
42,
|
|
false,
|
|
{"ddr5"},
|
|
true,
|
|
DRAMSys::Config::StoreModeType::NoStorage,
|
|
false,
|
|
false,
|
|
1000};
|
|
|
|
DRAMSys::Config::MemSpec memSpec;
|
|
|
|
DRAMSys::Config::TracePlayer tracePlayer;
|
|
DRAMSys::Config::TrafficGenerator traceGeneratorOneState;
|
|
DRAMSys::Config::TrafficGeneratorStateMachine traceGeneratorMultipleStates;
|
|
DRAMSys::Config::RowHammer traceHammer;
|
|
std::vector<DRAMSys::Config::Initiator> traceSetup{
|
|
{tracePlayer, traceGeneratorOneState, traceGeneratorMultipleStates, traceHammer}};
|
|
|
|
DRAMSys::Config::Configuration configuration{
|
|
addressMapping, mcConfig, memSpec, simConfig, "std::string_simulationId", traceSetup};
|
|
};
|
|
|
|
DRAMSys::Config::MemSpec ConfigurationTest::createMemSpec()
|
|
{
|
|
MemArchitectureSpecType memArchitectureSpec{{{"burstLength", 16},
|
|
{"dataRate", 2},
|
|
{"nbrOfBankGroups", 8},
|
|
{"nbrOfBanks", 16},
|
|
{"nbrOfColumns", 2048},
|
|
{"nbrOfRanks", 1},
|
|
{"nbrOfDIMMRanks", 1},
|
|
{"nbrOfPhysicalRanks", 1},
|
|
{"nbrOfLogicalRanks", 1},
|
|
{"nbrOfRows", 65536},
|
|
{"width", 4},
|
|
{"nbrOfDevices", 8},
|
|
{"nbrOfChannels", 2},
|
|
{"cmdMode", 1},
|
|
{"refMode", 1},
|
|
{"RAAIMT", 32},
|
|
{"RAAMMT", 96},
|
|
{"RAADEC", 1}}};
|
|
|
|
MemTimingSpecType 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_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_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},
|
|
{"clkMhz", 1600},
|
|
}}};
|
|
|
|
return {memArchitectureSpec, "JEDEC_2x8x2Gbx4_DDR5-3200A", "DDR5", memTimingSpec, {}};
|
|
}
|
|
|
|
DRAMSys::Config::TracePlayer ConfigurationTest::createTracePlayer()
|
|
{
|
|
DRAMSys::Config::TracePlayer player;
|
|
player.clkMhz = 100;
|
|
player.name = "mytrace.stl";
|
|
|
|
return player;
|
|
}
|
|
|
|
DRAMSys::Config::TrafficGenerator ConfigurationTest::createTraceGeneratorOneState()
|
|
{
|
|
DRAMSys::Config::TrafficGenerator gen;
|
|
gen.clkMhz = 100;
|
|
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.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.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<DRAMSys::Config::Configuration>();
|
|
|
|
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, ResourceDirectory)
|
|
{
|
|
// Test should not throw exceptions
|
|
Configuration config = from_path("resources/ddr5-example.json", "resources");
|
|
}
|
|
|
|
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>(), RefreshPolicyType::AllBank);
|
|
EXPECT_EQ(json_t("Bankwise").get<RefreshPolicyType>(), RefreshPolicyType::PerBank);
|
|
EXPECT_EQ(json_t("Groupwise").get<RefreshPolicyType>(), RefreshPolicyType::SameBank);
|
|
|
|
// Serializing
|
|
EXPECT_EQ(json_t(RefreshPolicyType::AllBank).get<std::string>(), "AllBank");
|
|
EXPECT_EQ(json_t(RefreshPolicyType::PerBank).get<std::string>(), "PerBank");
|
|
EXPECT_EQ(json_t(RefreshPolicyType::SameBank).get<std::string>(), "SameBank");
|
|
}
|
|
|
|
TEST_F(ConfigurationTest, SimConfig)
|
|
{
|
|
std::string_view simconfig_string = R"(
|
|
{
|
|
"simconfig": {
|
|
"AddressOffset": 0,
|
|
"CheckTLM2Protocol": false,
|
|
"DatabaseRecording": true,
|
|
"Debug": false,
|
|
"EnableWindowing": false,
|
|
"ErrorCSVFile": "error.csv",
|
|
"ErrorChipSeed": 42,
|
|
"PowerAnalysis": false,
|
|
"SimulationName": "ddr5",
|
|
"SimulationProgressBar": true,
|
|
"StoreMode": "NoStorage",
|
|
"ThermalSimulation": false,
|
|
"UseMalloc": false,
|
|
"WindowSize": 1000
|
|
}
|
|
}
|
|
)";
|
|
|
|
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,
|
|
"nbrOfBankGroups": 8,
|
|
"nbrOfBanks": 16,
|
|
"nbrOfChannels": 2,
|
|
"nbrOfColumns": 2048,
|
|
"nbrOfDIMMRanks": 1,
|
|
"nbrOfDevices": 8,
|
|
"nbrOfLogicalRanks": 1,
|
|
"nbrOfPhysicalRanks": 1,
|
|
"nbrOfRanks": 1,
|
|
"nbrOfRows": 65536,
|
|
"refMode": 1,
|
|
"width": 4
|
|
},
|
|
"memoryId": "JEDEC_2x8x2Gbx4_DDR5-3200A",
|
|
"memoryType": "DDR5",
|
|
"memtimingspec": {
|
|
"ACTPDEN": 2,
|
|
"CCD_L_WR2_slr": 16,
|
|
"CCD_L_WR_slr": 32,
|
|
"CCD_L_slr": 8,
|
|
"CCD_S_WR_slr": 8,
|
|
"CCD_S_slr": 8,
|
|
"CCD_WR_dlr": 0,
|
|
"CCD_WR_dpr": 0,
|
|
"CCD_dlr": 0,
|
|
"CPDED": 8,
|
|
"FAW_dlr": 0,
|
|
"FAW_slr": 32,
|
|
"PD": 12,
|
|
"PPD": 2,
|
|
"PRPDEN": 2,
|
|
"RAS": 52,
|
|
"RCD": 22,
|
|
"RDDQS": 0,
|
|
"REFI1": 6240,
|
|
"REFI2": 3120,
|
|
"REFISB": 1560,
|
|
"REFPDEN": 2,
|
|
"REFSBRD_dlr": 0,
|
|
"REFSBRD_slr": 48,
|
|
"RFC1_dlr": 0,
|
|
"RFC1_dpr": 0,
|
|
"RFC1_slr": 312,
|
|
"RFC2_dlr": 0,
|
|
"RFC2_dpr": 0,
|
|
"RFC2_slr": 208,
|
|
"RFCsb_dlr": 0,
|
|
"RFCsb_slr": 184,
|
|
"RL": 22,
|
|
"RP": 22,
|
|
"RPRE": 1,
|
|
"RPST": 0,
|
|
"RRD_L_slr": 8,
|
|
"RRD_S_slr": 8,
|
|
"RRD_dlr": 0,
|
|
"RTP": 12,
|
|
"RTRS": 2,
|
|
"WL": 20,
|
|
"WPRE": 2,
|
|
"WPST": 0,
|
|
"WR": 48,
|
|
"WTR_L": 16,
|
|
"WTR_S": 4,
|
|
"XP": 12,
|
|
"clkMhz": 1600
|
|
}
|
|
}
|
|
}
|
|
)";
|
|
|
|
json_t memspec_reference = json_t::parse(memspec_string);
|
|
json_t memspec_test;
|
|
memspec_test[MemSpec::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": [
|
|
{
|
|
"clkMhz": 100,
|
|
"name": "mytrace.stl"
|
|
},
|
|
{
|
|
"addressDistribution": "random",
|
|
"clkMhz": 100,
|
|
"name": "MyTestGen",
|
|
"numRequests": 1000,
|
|
"rwRatio": 0.5
|
|
},
|
|
{
|
|
"clkMhz": 100,
|
|
"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
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"clkMhz": 100,
|
|
"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);
|
|
}
|