From 4a662590afb2a49cc508709e115f6ee00b14cf21 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Thu, 23 Sep 2021 10:25:11 -0400 Subject: [PATCH 01/17] Add ideal memory flag --- src/configuration.cc | 2 +- src/configuration.h | 4 +++- src/dram_system.cc | 1 + src/memory_system.cc | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/configuration.cc b/src/configuration.cc index 297692db..fc96fb07 100644 --- a/src/configuration.cc +++ b/src/configuration.cc @@ -68,7 +68,7 @@ DRAMProtocol Config::GetDRAMProtocol(std::string protocol_str) { {"GDDR5", DRAMProtocol::GDDR5}, {"GDDR5X", DRAMProtocol::GDDR5X}, {"GDDR6", DRAMProtocol::GDDR6}, {"LPDDR", DRAMProtocol::LPDDR}, {"LPDDR3", DRAMProtocol::LPDDR3}, {"LPDDR4", DRAMProtocol::LPDDR4}, {"HBM", DRAMProtocol::HBM}, - {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}}; + {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}, {"IDEAL", DRAMProtocol::IDEAL}}; if (protocol_pairs.find(protocol_str) == protocol_pairs.end()) { std::cout << "Unkwown/Unsupported DRAM Protocol: " << protocol_str diff --git a/src/configuration.h b/src/configuration.h index 44dae776..439b8c51 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -21,7 +21,8 @@ enum class DRAMProtocol { HBM, HBM2, HMC, - SIZE + SIZE, + IDEAL }; enum class RefreshPolicy { @@ -155,6 +156,7 @@ class Config { return (protocol == DRAMProtocol::HBM || protocol == DRAMProtocol::HBM2); } + bool IsIdeal() const { return (protocol == DRAMProtocol::IDEAL); } bool IsHMC() const { return (protocol == DRAMProtocol::HMC); } // yzy: add another function bool IsDDR4() const { return (protocol == DRAMProtocol::DDR4); } diff --git a/src/dram_system.cc b/src/dram_system.cc index 86f35f84..c277b88a 100644 --- a/src/dram_system.cc +++ b/src/dram_system.cc @@ -185,6 +185,7 @@ bool IdealDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { } void IdealDRAMSystem::ClockTick() { + printf("%d", latency_); for (auto trans_it = infinite_buffer_q_.begin(); trans_it != infinite_buffer_q_.end();) { if (clk_ - trans_it->added_cycle >= static_cast(latency_)) { diff --git a/src/memory_system.cc b/src/memory_system.cc index 739ea1af..482e4e50 100644 --- a/src/memory_system.cc +++ b/src/memory_system.cc @@ -10,6 +10,9 @@ MemorySystem::MemorySystem(const std::string &config_file, if (config_->IsHMC()) { dram_system_ = new HMCMemorySystem(*config_, output_dir, read_callback, write_callback); + } else if (config_->IsIdeal()) { + dram_system_ = new IdealDRAMSystem(*config_, output_dir, read_callback, + write_callback); } else { dram_system_ = new JedecDRAMSystem(*config_, output_dir, read_callback, write_callback); From 32ae39fbec975f9ad7ccd76c4e5f5a07bd51afc5 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Mon, 27 Sep 2021 15:29:46 -0400 Subject: [PATCH 02/17] Add model swap memory system --- configs/DDR3_8Gb_x16_1866_model_swap.ini | 68 +++++++++++++++++++++++ src/configuration.cc | 2 +- src/configuration.h | 4 +- src/dram_system.cc | 70 +++++++++++++++++++++++- src/dram_system.h | 16 ++++++ src/memory_system.cc | 4 +- 6 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 configs/DDR3_8Gb_x16_1866_model_swap.ini diff --git a/configs/DDR3_8Gb_x16_1866_model_swap.ini b/configs/DDR3_8Gb_x16_1866_model_swap.ini new file mode 100644 index 00000000..7512ddd7 --- /dev/null +++ b/configs/DDR3_8Gb_x16_1866_model_swap.ini @@ -0,0 +1,68 @@ +[dram_structure] +protocol = MODEL_SWAP +bankgroups = 1 +banks_per_group = 8 +rows = 65536 +columns = 1024 +device_width = 16 +BL = 8 + +[timing] +tCK = 1.07 +AL = 0 +CL = 13 +CWL = 9 +tRCD = 13 +tRP = 13 +tRAS = 32 +tRFC = 328 +tRFC2 = 328 +tRFC4 = 328 +REFI = 7290 +tRPRE = 0 +tWPRE = 0 +tRRD_S = 6 +tRRD_L = +tWTR_S = 7 +tWTR_L = 7 +tFAW = 33 +tWR = 15 +tWR2 = 15 +tRTP = 7 +tCCD_S = 4 +tCCD_L = 4 +tCKE = 5 +tCKESR = 6 +tXS = 338 +tXP = 6 +tRTRS = 1 +ideal_memory_latency = 20 + +[power] +VDD = 1.35 +IDD0 = 69 +IPP0 = 0.0 +IDD2P = 11 +IDD2N = 38 +IDD3P = 38 +IDD3N = 53 +IDD4W = 195 +IDD4R = 195 +IDD5AB = 275 +IDD6x = 24 + +[system] +channel_size = 8192 +channels = 1 +bus_width = 64 +address_mapping = rochrababgco +queue_structure = PER_BANK +refresh_policy = RANK_LEVEL_STAGGERED +row_buf_policy = OPEN_PAGE +cmd_queue_size = 8 +trans_queue_size = 32 + +[other] +epoch_period = 934579 +output_level = 1 + diff --git a/src/configuration.cc b/src/configuration.cc index fc96fb07..ea4a09ed 100644 --- a/src/configuration.cc +++ b/src/configuration.cc @@ -68,7 +68,7 @@ DRAMProtocol Config::GetDRAMProtocol(std::string protocol_str) { {"GDDR5", DRAMProtocol::GDDR5}, {"GDDR5X", DRAMProtocol::GDDR5X}, {"GDDR6", DRAMProtocol::GDDR6}, {"LPDDR", DRAMProtocol::LPDDR}, {"LPDDR3", DRAMProtocol::LPDDR3}, {"LPDDR4", DRAMProtocol::LPDDR4}, {"HBM", DRAMProtocol::HBM}, - {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}, {"IDEAL", DRAMProtocol::IDEAL}}; + {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}, {"MODEL_SWAP", DRAMProtocol::MODEL_SWAP}}; if (protocol_pairs.find(protocol_str) == protocol_pairs.end()) { std::cout << "Unkwown/Unsupported DRAM Protocol: " << protocol_str diff --git a/src/configuration.h b/src/configuration.h index 439b8c51..3c0f13dc 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -22,7 +22,7 @@ enum class DRAMProtocol { HBM2, HMC, SIZE, - IDEAL + MODEL_SWAP }; enum class RefreshPolicy { @@ -156,7 +156,7 @@ class Config { return (protocol == DRAMProtocol::HBM || protocol == DRAMProtocol::HBM2); } - bool IsIdeal() const { return (protocol == DRAMProtocol::IDEAL); } + bool IsModelSwap() const { return (protocol == DRAMProtocol::MODEL_SWAP); } bool IsHMC() const { return (protocol == DRAMProtocol::HMC); } // yzy: add another function bool IsDDR4() const { return (protocol == DRAMProtocol::DDR4); } diff --git a/src/dram_system.cc b/src/dram_system.cc index c277b88a..b9444d12 100644 --- a/src/dram_system.cc +++ b/src/dram_system.cc @@ -185,7 +185,6 @@ bool IdealDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { } void IdealDRAMSystem::ClockTick() { - printf("%d", latency_); for (auto trans_it = infinite_buffer_q_.begin(); trans_it != infinite_buffer_q_.end();) { if (clk_ - trans_it->added_cycle >= static_cast(latency_)) { @@ -205,4 +204,73 @@ void IdealDRAMSystem::ClockTick() { return; } +ModelSwapDRAMSystem::ModelSwapDRAMSystem(Config &config, const std::string &output_dir, + std::function read_callback, + std::function write_callback) + : BaseDRAMSystem(config, output_dir, read_callback, write_callback), + latency_(config_.ideal_memory_latency) { + if (config_.IsModelSwap()) { + std::cerr << "Initialized a memory system with online model swapping!" + << std::endl; + } + + ctrls_.reserve(config_.channels); + + for (auto i = 0; i < config_.channels; i++) { + ctrls_.push_back(new Controller(i, config_, timing_)); + } +} + +ModelSwapDRAMSystem::~ModelSwapDRAMSystem() { + for (auto it = ctrls_.begin(); it != ctrls_.end(); it++) { + delete (*it); + } +} + +bool ModelSwapDRAMSystem::WillAcceptTransaction(uint64_t hex_addr, + bool is_write) const { + int channel = GetChannel(hex_addr); + return ctrls_[channel]->WillAcceptTransaction(hex_addr, is_write); +} + +bool ModelSwapDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { + int channel = GetChannel(hex_addr); + bool ok = ctrls_[channel]->WillAcceptTransaction(hex_addr, is_write); + assert(ok); + if (ok) { + Transaction trans = Transaction(hex_addr, is_write); + trans.added_cycle = clk_; + trans.complete_cycle = clk_ + latency_; + printf("%d %d %d\n", trans.added_cycle, trans.complete_cycle, clk_); + ctrls_[channel]->AddTransaction(trans); + } + last_req_clk_ = clk_; + return ok; +} + +void ModelSwapDRAMSystem::ClockTick() { + for (size_t i = 0; i < ctrls_.size(); i++) { + // look ahead and return earlier + while (true) { + auto pair = ctrls_[i]->ReturnDoneTrans(clk_); + if (pair.second == 1) { + write_callback_(pair.first); + } else if (pair.second == 0) { + read_callback_(pair.first); + } else { + break; + } + } + } + for (size_t i = 0; i < ctrls_.size(); i++) { + ctrls_[i]->ClockTick(); + } + clk_++; + + if (clk_ % config_.epoch_period == 0) { + PrintEpochStats(); + } + return; +} + } // namespace dramsim3 diff --git a/src/dram_system.h b/src/dram_system.h index 7864b2cf..4a4a73b6 100644 --- a/src/dram_system.h +++ b/src/dram_system.h @@ -90,5 +90,21 @@ class IdealDRAMSystem : public BaseDRAMSystem { std::vector infinite_buffer_q_; }; +// DRAM system used for online model swapping +class ModelSwapDRAMSystem : public BaseDRAMSystem { + public: + ModelSwapDRAMSystem(Config &config, const std::string &output_dir, + std::function read_callback, + std::function write_callback); + ~ModelSwapDRAMSystem(); + bool WillAcceptTransaction(uint64_t hex_addr, bool is_write) const override; + bool AddTransaction(uint64_t hex_addr, bool is_write) override; + void ClockTick() override; + + private: + int latency_; + std::vector infinite_buffer_q_; +}; + } // namespace dramsim3 #endif // __DRAM_SYSTEM_H diff --git a/src/memory_system.cc b/src/memory_system.cc index 482e4e50..33d0ef89 100644 --- a/src/memory_system.cc +++ b/src/memory_system.cc @@ -10,8 +10,8 @@ MemorySystem::MemorySystem(const std::string &config_file, if (config_->IsHMC()) { dram_system_ = new HMCMemorySystem(*config_, output_dir, read_callback, write_callback); - } else if (config_->IsIdeal()) { - dram_system_ = new IdealDRAMSystem(*config_, output_dir, read_callback, + } else if (config_->IsModelSwap()) { + dram_system_ = new ModelSwapDRAMSystem(*config_, output_dir, read_callback, write_callback); } else { dram_system_ = new JedecDRAMSystem(*config_, output_dir, read_callback, From 4ad41b85641575b2820be1450e7979761956d9d5 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Wed, 29 Sep 2021 16:20:51 -0400 Subject: [PATCH 03/17] Add ability to perform multiple transactions per controller --- .gitignore | 4 ++++ src/controller.cc | 23 +++++++++++++++++++++++ src/controller.h | 1 + src/dram_system.cc | 18 ++++++++---------- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index c749ab0d..1fadcd08 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,7 @@ release # IDEs / Editors .vscode/ + +# Temporary traces +dramsim3.json +dramsim3.txt \ No newline at end of file diff --git a/src/controller.cc b/src/controller.cc index a582dcc2..ac1c501f 100644 --- a/src/controller.cc +++ b/src/controller.cc @@ -42,6 +42,29 @@ Controller::Controller(int channel, const Config &config, const Timing &timing) #endif // CMD_TRACE } +std::vector> Controller::ReturnAllDoneTrans(uint64_t clk) { + std::vector> completed_transactions; + + auto it = return_queue_.begin(); + while (it != return_queue_.end()) { + if (clk >= it->complete_cycle) { + if (it->is_write) { + simple_stats_.Increment("num_writes_done"); + } else { + simple_stats_.Increment("num_reads_done"); + simple_stats_.AddValue("read_latency", clk_ - it->added_cycle); + } + auto pair = std::make_pair(it->addr, it->is_write); + it = return_queue_.erase(it); + completed_transactions.push_back(pair); + } else { + ++it; + } + } + + return completed_transactions; +} + std::pair Controller::ReturnDoneTrans(uint64_t clk) { auto it = return_queue_.begin(); while (it != return_queue_.end()) { diff --git a/src/controller.h b/src/controller.h index 77bd6afd..23dd4ffa 100644 --- a/src/controller.h +++ b/src/controller.h @@ -35,6 +35,7 @@ class Controller { void PrintEpochStats(); void PrintFinalStats(); void ResetStats() { simple_stats_.Reset(); } + std::vector> ReturnAllDoneTrans(uint64_t clock); std::pair ReturnDoneTrans(uint64_t clock); int channel_id_; diff --git a/src/dram_system.cc b/src/dram_system.cc index b9444d12..22352776 100644 --- a/src/dram_system.cc +++ b/src/dram_system.cc @@ -241,7 +241,6 @@ bool ModelSwapDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { Transaction trans = Transaction(hex_addr, is_write); trans.added_cycle = clk_; trans.complete_cycle = clk_ + latency_; - printf("%d %d %d\n", trans.added_cycle, trans.complete_cycle, clk_); ctrls_[channel]->AddTransaction(trans); } last_req_clk_ = clk_; @@ -250,21 +249,20 @@ bool ModelSwapDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { void ModelSwapDRAMSystem::ClockTick() { for (size_t i = 0; i < ctrls_.size(); i++) { - // look ahead and return earlier - while (true) { - auto pair = ctrls_[i]->ReturnDoneTrans(clk_); - if (pair.second == 1) { - write_callback_(pair.first); - } else if (pair.second == 0) { - read_callback_(pair.first); - } else { - break; + auto completed_transactions = ctrls_[i]->ReturnAllDoneTrans(clk_); + for (auto it = completed_transactions.begin(); it != completed_transactions.end(); it++) { + if (it->second == 1) { + write_callback_(it->first); + } else if (it->second == 0) { + read_callback_(it->first); } } } + for (size_t i = 0; i < ctrls_.size(); i++) { ctrls_[i]->ClockTick(); } + clk_++; if (clk_ % config_.epoch_period == 0) { From afea3b8d9b33121604c5ccc6f1ab0024abf7cc9d Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 21 Oct 2021 12:08:03 -0400 Subject: [PATCH 04/17] added gitattributes and phase test driver class now in c++ --- .gitattributes | 3 ++ scripts/heatmap.py | 0 scripts/plot_stats.py | 0 scripts/trace_gen.py | 0 scripts/validation.py | 0 src/phase_test_driver.cpp | 94 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 .gitattributes mode change 100755 => 100644 scripts/heatmap.py mode change 100755 => 100644 scripts/plot_stats.py mode change 100755 => 100644 scripts/trace_gen.py mode change 100755 => 100644 scripts/validation.py create mode 100644 src/phase_test_driver.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..314766e9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf diff --git a/scripts/heatmap.py b/scripts/heatmap.py old mode 100755 new mode 100644 diff --git a/scripts/plot_stats.py b/scripts/plot_stats.py old mode 100755 new mode 100644 diff --git a/scripts/trace_gen.py b/scripts/trace_gen.py old mode 100755 new mode 100644 diff --git a/scripts/validation.py b/scripts/validation.py old mode 100755 new mode 100644 diff --git a/src/phase_test_driver.cpp b/src/phase_test_driver.cpp new file mode 100644 index 00000000..73aef1e3 --- /dev/null +++ b/src/phase_test_driver.cpp @@ -0,0 +1,94 @@ +// # Copyright (c) 2021, Georgia Institute of Technology +// # +// # SPDX-License-Identifier: Apache-2.0 +// # +// # Licensed under the Apache License, Version 2.0 (the "License"); +// # you may not use this file except in compliance with the License. +// # You may obtain a copy of the License at +// # +// # http://www.apache.org/licenses/LICENSE-2.0 +// # +// # Unless required by applicable law or agreed to in writing, software +// # distributed under the License is distributed on an "AS IS" BASIS, +// # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// # See the License for the specific language governing permissions and +// # limitations under the License. + +// Ryan Thomas Lynch +// Georgia Institute of Technology +// ryan.lynch@gatech.edu +// CRNCH Lab + +#include +#include "./../ext/headers/args.hxx" +#include "cpu.h" + + +using namespace dramsim3; + +int main(int argc, const char **argv) { + args::ArgumentParser parser( + "DRAM Simulator.", + "Examples: \n." + "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -c 100 -t " + "sample_trace.txt\n" + "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -s random -c 100"); + args::HelpFlag help(parser, "help", "Display the help menu", {'h', "help"}); + args::ValueFlag num_cycles_arg(parser, "num_cycles", + "Number of cycles to simulate", + {'c', "cycles"}, 100000); + args::ValueFlag output_dir_arg( + parser, "output_dir", "Output directory for stats files", + {'o', "output-dir"}, "."); + args::ValueFlag stream_arg( + parser, "stream_type", "address stream generator - (random), stream", + {'s', "stream"}, ""); + args::ValueFlag trace_file_arg( + parser, "trace", + "Trace file, setting this option will ignore -s option", + {'t', "trace"}); + args::Positional config_arg( + parser, "config", "The config file name (mandatory)"); + + try { + parser.ParseCLI(argc, argv); + } catch (args::Help) { + std::cout << parser; + return 0; + } catch (args::ParseError e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return 1; + } + + std::string config_file = args::get(config_arg); + if (config_file.empty()) { + std::cerr << parser; + return 1; + } + + uint64_t cycles = args::get(num_cycles_arg); + std::string output_dir = args::get(output_dir_arg); + std::string trace_file = args::get(trace_file_arg); + std::string stream_type = args::get(stream_arg); + + CPU *cpu; + if (!trace_file.empty()) { + cpu = new TraceBasedCPU(config_file, output_dir, trace_file); + } else { + if (stream_type == "stream" || stream_type == "s") { + cpu = new StreamCPU(config_file, output_dir); + } else { + cpu = new RandomCPU(config_file, output_dir); + } + } + + for (uint64_t clk = 0; clk < cycles; clk++) { + cpu->ClockTick(); + } + cpu->PrintStats(); + + delete cpu; + + return 0; +} From 88edf982c8b884eca3621ecb117d0be09d2d40ab Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 21 Oct 2021 12:34:16 -0400 Subject: [PATCH 05/17] removed test driver going to change where this goes lol --- src/phase_test_driver.cpp | 94 --------------------------------------- 1 file changed, 94 deletions(-) delete mode 100644 src/phase_test_driver.cpp diff --git a/src/phase_test_driver.cpp b/src/phase_test_driver.cpp deleted file mode 100644 index 73aef1e3..00000000 --- a/src/phase_test_driver.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// # Copyright (c) 2021, Georgia Institute of Technology -// # -// # SPDX-License-Identifier: Apache-2.0 -// # -// # Licensed under the Apache License, Version 2.0 (the "License"); -// # you may not use this file except in compliance with the License. -// # You may obtain a copy of the License at -// # -// # http://www.apache.org/licenses/LICENSE-2.0 -// # -// # Unless required by applicable law or agreed to in writing, software -// # distributed under the License is distributed on an "AS IS" BASIS, -// # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// # See the License for the specific language governing permissions and -// # limitations under the License. - -// Ryan Thomas Lynch -// Georgia Institute of Technology -// ryan.lynch@gatech.edu -// CRNCH Lab - -#include -#include "./../ext/headers/args.hxx" -#include "cpu.h" - - -using namespace dramsim3; - -int main(int argc, const char **argv) { - args::ArgumentParser parser( - "DRAM Simulator.", - "Examples: \n." - "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -c 100 -t " - "sample_trace.txt\n" - "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -s random -c 100"); - args::HelpFlag help(parser, "help", "Display the help menu", {'h', "help"}); - args::ValueFlag num_cycles_arg(parser, "num_cycles", - "Number of cycles to simulate", - {'c', "cycles"}, 100000); - args::ValueFlag output_dir_arg( - parser, "output_dir", "Output directory for stats files", - {'o', "output-dir"}, "."); - args::ValueFlag stream_arg( - parser, "stream_type", "address stream generator - (random), stream", - {'s', "stream"}, ""); - args::ValueFlag trace_file_arg( - parser, "trace", - "Trace file, setting this option will ignore -s option", - {'t', "trace"}); - args::Positional config_arg( - parser, "config", "The config file name (mandatory)"); - - try { - parser.ParseCLI(argc, argv); - } catch (args::Help) { - std::cout << parser; - return 0; - } catch (args::ParseError e) { - std::cerr << e.what() << std::endl; - std::cerr << parser; - return 1; - } - - std::string config_file = args::get(config_arg); - if (config_file.empty()) { - std::cerr << parser; - return 1; - } - - uint64_t cycles = args::get(num_cycles_arg); - std::string output_dir = args::get(output_dir_arg); - std::string trace_file = args::get(trace_file_arg); - std::string stream_type = args::get(stream_arg); - - CPU *cpu; - if (!trace_file.empty()) { - cpu = new TraceBasedCPU(config_file, output_dir, trace_file); - } else { - if (stream_type == "stream" || stream_type == "s") { - cpu = new StreamCPU(config_file, output_dir); - } else { - cpu = new RandomCPU(config_file, output_dir); - } - } - - for (uint64_t clk = 0; clk < cycles; clk++) { - cpu->ClockTick(); - } - cpu->PrintStats(); - - delete cpu; - - return 0; -} From 33d9854ac3cca2f01aaee385afce704acbe261e8 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 21 Oct 2021 14:53:30 -0400 Subject: [PATCH 06/17] add OnlineCPU class hmmm --- src/cpu.cc | 19 +++++++++++++++++++ src/cpu.h | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/cpu.cc b/src/cpu.cc index 175955fd..c7233844 100644 --- a/src/cpu.cc +++ b/src/cpu.cc @@ -89,4 +89,23 @@ void TraceBasedCPU::ClockTick() { return; } +void OnlineCPU::ClockTick() { + memory_system_.ClockTick(); + clk_++; + if (canSend) { + memory_system_.AddTransaction(curr_addr, curr_is_write); + } + canSend = false; + return; +} + +bool OnlineCPU::canSendTransaction(uint64_t addr, bool is_write) { + canSend = memory_system_.WillAcceptTransaction(addr, is_write); + if (canSend) { + curr_addr = addr; + curr_is_write = is_write; + } + return canSend; +} + } // namespace dramsim3 diff --git a/src/cpu.h b/src/cpu.h index 9ec28e74..c3aa19e5 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -67,5 +67,19 @@ class TraceBasedCPU : public CPU { bool get_next_ = true; }; + +class OnlineCPU : public CPU { + + public: + using CPU::CPU; + void ClockTick() override; + bool canSendTransaction(uint64_t addr, bool is_write); + + private: + bool canSend = true; + uint64_t curr_addr; + bool curr_is_write; +}; + } // namespace dramsim3 #endif From 86f12cc0ff9323d45ebf6909b76a1a7485b73d92 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 21 Oct 2021 14:56:46 -0400 Subject: [PATCH 07/17] add resetstats method to CPU --- src/cpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpu.h b/src/cpu.h index c3aa19e5..7fffd56b 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -21,6 +21,7 @@ class CPU { void ReadCallBack(uint64_t addr) { return; } void WriteCallBack(uint64_t addr) { return; } void PrintStats() { memory_system_.PrintStats(); } + void ResetStats() { memory_system_.ResetStats(); } protected: MemorySystem memory_system_; From 2bbc29ccc6ddf0b597931d913034abfc711cf7d4 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 28 Oct 2021 12:56:37 -0400 Subject: [PATCH 08/17] added registering callbacks to onlinecpu for testing for sure --- src/cpu.cc | 4 ++++ src/cpu.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/cpu.cc b/src/cpu.cc index c7233844..0abe2224 100644 --- a/src/cpu.cc +++ b/src/cpu.cc @@ -108,4 +108,8 @@ bool OnlineCPU::canSendTransaction(uint64_t addr, bool is_write) { return canSend; } +void OnlineCPU::RegisterCallbacks(std::function read_callback, std::function write_callback) { + memory_system_.RegisterCallbacks(read_callback, write_callback); +} + } // namespace dramsim3 diff --git a/src/cpu.h b/src/cpu.h index 7fffd56b..9145a63f 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -75,6 +75,8 @@ class OnlineCPU : public CPU { using CPU::CPU; void ClockTick() override; bool canSendTransaction(uint64_t addr, bool is_write); + void RegisterCallbacks(std::function read_callback, + std::function write_callback); private: bool canSend = true; From 73871066a71e8078e285160803b4a9807d52efc4 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 28 Oct 2021 13:46:20 -0400 Subject: [PATCH 09/17] update .gitignore to ignore cmake output duh --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1fadcd08..9104c128 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,11 @@ release # Temporary traces dramsim3.json -dramsim3.txt \ No newline at end of file +dramsim3.txt + + +# CMake stuff +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +Makefile \ No newline at end of file From 125bc9d0d50a80e15fbb1cf4a66410394120a2a7 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Thu, 28 Oct 2021 18:28:59 -0400 Subject: [PATCH 10/17] Add ideal memory configuration --- .vscode/tasks.json | 25 +- configs/DDR3_8Gb_x16_1866_ideal.ini | 68 ++++ scripts/heatmap.py | 222 ---------- scripts/validation.py | 604 ---------------------------- src/configuration.cc | 3 +- src/configuration.h | 4 +- src/dram_system.cc | 7 +- src/memory_system.cc | 3 + 8 files changed, 102 insertions(+), 834 deletions(-) create mode 100644 configs/DDR3_8Gb_x16_1866_ideal.ini delete mode 100755 scripts/heatmap.py delete mode 100755 scripts/validation.py diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d7501528..6e574964 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,12 +1,27 @@ { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format - "version": "0.1.0", + "version": "2.0.0", "command": "make", - "isShellCommand": true, - "args": ["-j5"], - "showOutput": "always", + "args": [ + "-j5" + ], "options": { "cwd": "${workspaceRoot}/build" - } + }, + "tasks": [ + { + "label": "make", + "type": "shell", + "command": "make", + "args": [ + "-j5" + ], + "problemMatcher": [], + "group": { + "_id": "build", + "isDefault": false + } + } + ] } \ No newline at end of file diff --git a/configs/DDR3_8Gb_x16_1866_ideal.ini b/configs/DDR3_8Gb_x16_1866_ideal.ini new file mode 100644 index 00000000..929ee386 --- /dev/null +++ b/configs/DDR3_8Gb_x16_1866_ideal.ini @@ -0,0 +1,68 @@ +[dram_structure] +protocol = IDEAL +bankgroups = 1 +banks_per_group = 8 +rows = 65536 +columns = 1024 +device_width = 16 +BL = 8 + +[timing] +tCK = 1.07 +AL = 0 +CL = 13 +CWL = 9 +tRCD = 13 +tRP = 13 +tRAS = 32 +tRFC = 328 +tRFC2 = 328 +tRFC4 = 328 +REFI = 7290 +tRPRE = 0 +tWPRE = 0 +tRRD_S = 6 +tRRD_L = +tWTR_S = 7 +tWTR_L = 7 +tFAW = 33 +tWR = 15 +tWR2 = 15 +tRTP = 7 +tCCD_S = 4 +tCCD_L = 4 +tCKE = 5 +tCKESR = 6 +tXS = 338 +tXP = 6 +tRTRS = 1 +ideal_memory_latency = 20 + +[power] +VDD = 1.35 +IDD0 = 69 +IPP0 = 0.0 +IDD2P = 11 +IDD2N = 38 +IDD3P = 38 +IDD3N = 53 +IDD4W = 195 +IDD4R = 195 +IDD5AB = 275 +IDD6x = 24 + +[system] +channel_size = 8192 +channels = 1 +bus_width = 64 +address_mapping = rochrababgco +queue_structure = PER_BANK +refresh_policy = RANK_LEVEL_STAGGERED +row_buf_policy = OPEN_PAGE +cmd_queue_size = 8 +trans_queue_size = 32 + +[other] +epoch_period = 934579 +output_level = 1 + diff --git a/scripts/heatmap.py b/scripts/heatmap.py deleted file mode 100755 index e48aa990..00000000 --- a/scripts/heatmap.py +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import os -import sys -from collections import OrderedDict - -try: - import numpy as np - import pandas as pd - import matplotlib -except: - print("please install numpy, matplotlib and pandas") - raise - -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import matplotlib.patches as patches - - - -def construct_mesh(df, val_key, xkey="x", ykey="y"): - """ - to construct mesh data structure to be used for plotting later - this should be as generic as possible - the 3 keys in the args are used to locate data in the dataframe - return a dict that can be used by pcolor/pcolormesh functions - """ - x = df[xkey] - y = df[ykey] - t = df[val_key] - xx, yy = np.meshgrid(x.unique(), y.unique()) - zz = [] - y_groups = df.groupby(ykey) - for i in y.unique(): - group = y_groups.get_group(i) - z = group[val_key] - zz.append(z) - zz = np.array(zz) - res = {"x":xx, "y":yy, "val":zz} - return res - - -def plot_heatmap(x, y, t, title, save_to=""): - """ - quick access to single heatmap - """ - fig = plt.figure() - ax = fig.add_subplot(111) - pcm = ax.pcolormesh(x, y, t, cmap="coolwarm") - fig.colorbar(pcm, ax=ax, extend="max") - fig.savefig("heatmap.png") - - -def plot_sub_heatmap(fig, ax, x, y, t, title): - pcm = ax.pcolormesh(x, y, t, cmap="coolwarm") - ax.set_title(title) - # no offset used since temperature should be straightforward - c_bar_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False) - cbar = fig.colorbar(pcm, ax=ax, extend="max", format=c_bar_formatter) - return fig, ax - -def prep_fig_axes(num_plots): - """ - so for each z dimension we plot 1 fig and if - there are multiple channels plot them as subplots - returns a dict with fig as keys and axes list as values - """ - fig = plt.figure(tight_layout=True) - if num_plots == 1: - n_rows = 1 - n_cols = 1 - elif num_plots == 2: - n_rows = 1 - n_cols = 2 - elif num_plots == 4: - n_rows = 2 - n_cols = 2 - elif num_plots ==8: - n_rows = 2 - n_cols = 4 - elif num_plots == 16: - n_rows = 4 - n_cols = 4 - elif num_plots == 32: - n_rows = 4 - n_cols = 8 - elif num_plots == 64: - n_rows = 8 - n_cols = 8 - else: - n_rows = 1 - n_cols = 1 - # create axes in subplot - plot_num = 1 - for i in range(num_plots): - # args in add_subplot start from 1 - ax = fig.add_subplot(n_rows, n_cols, plot_num) - plot_num += 1 - return fig, fig.get_axes() - - -def plot_multi_rank_heatmap(multi_rank_data, save_to=""): - """ - this should also be a generic plot function - return figs and axes so that we can process it later - """ - num_plots = len(multi_rank_data) - fig, axes = prep_fig_axes(num_plots) - plot_num = 0 - for ax in axes: - data = multi_rank_data[plot_num] - plot_sub_heatmap(fig, ax, data["x"], data["y"], data["val"], data["title"]) - plot_num += 1 - return fig, axes - - -def plot_bank_patch(bank_line_data, fig_axes, show_num=True): - z = bank_line_data["z"] - fig = fig_axes[z]["fig"] - axes = fig_axes[z]["axes"] - x_len = bank_line_data["end_x"] - bank_line_data["start_x"] - y_len = bank_line_data["end_y"] - bank_line_data["start_y"] - starting_coord = (bank_line_data["start_x"], bank_line_data["start_y"]) - for ax in axes: - ax.add_patch( - patches.Rectangle( - starting_coord, - x_len, - y_len, - fill=False, - edgecolor=None, # default - linewidth=None # default - ) - ) - if show_num: - ax.text( - starting_coord[0] + 2, - starting_coord[1] + 2, - "B" + str(bank_line_data["bank_id"]), - fontsize=8, - color="white" - ) - - return - - -def save_figs(figs, prefix, img_format="png"): - for i, fig_axes in enumerate(figs): - fig = fig_axes["fig"] - fig_name = prefix + str(i) + "." + img_format - print("generating ",fig_name) - fig.savefig(fig_name) - - -def plot_simulation(stats_csv_file, bank_pos_file): - """ - so for each z dimension we plot 1 fig and if - there are multiple channels plot them as subplots - """ - frame = pd.read_csv(stats_csv_file) - die_frames = frame.groupby("z") - power_data = [] - temp_data = [] - for z, z_frame in die_frames: - rank_frames = z_frame.groupby("rank_channel_index") - z_power_data = [] - z_temp_data = [] - for rank, rank_frame in rank_frames: - rank_power_data = construct_mesh(rank_frame, "power", "x", "y") - rank_power_data["title"] = "die_" + str(z) + "_channel_rank_" + str(rank) + "_power" - rank_temp_data = construct_mesh(rank_frame, "temperature", "x", "y") - rank_temp_data["title"] = "die_" + str(z) + "_channel_rank_" + str(rank) + "_temperature" - z_power_data.append(rank_power_data) - z_temp_data.append(rank_temp_data) - power_data.append(z_power_data) - temp_data.append(z_temp_data) - - num_figs = len(power_data) - power_figs = [] - temp_figs = [] - for i in range(num_figs): - fig, axes = plot_multi_rank_heatmap(power_data[i]) - power_figs.append({"fig":fig, "axes":axes}) - fig, axes = plot_multi_rank_heatmap(temp_data[i]) - temp_figs.append({"fig":fig, "axes":axes}) - - bank_pos_frame = pd.read_csv(bank_pos_file) - - bank_pos = [] - for index, row in bank_pos_frame.iterrows(): - plot_bank_patch(row, power_figs) - plot_bank_patch(row, temp_figs) - return power_figs, temp_figs - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Plot power and temperature heatmap") - parser.add_argument("-p", "--prefix", help="prefix of the simulation," - "if this is provided then no need for other arguments", - default = "") - parser.add_argument("-s", "--stats-csv", help="temp and power stats csv file") - parser.add_argument("-b", "--bank-csv", help="bank postion csv file") - args = parser.parse_args() - prefix = args.prefix - if prefix: - csv_file = prefix + "final_power_temperature.csv" - bank_pos_file = prefix + "bank_position.csv" - else: - if args.stats_csv: - print(args.stats_csv) - csv_file = args.stats_csv - else: - print("need stats csv file for temp and power!") - exit(1) - if args.bank_csv: - print(args.bank_csv) - bank_pos_file = args.bank_csv - else: - print("need bank position file!") - exit(1) - p_figs, t_figs = plot_simulation(csv_file, bank_pos_file) - save_figs(p_figs, prefix + "fig_power_") - save_figs(t_figs, prefix + "fig_temp_") diff --git a/scripts/validation.py b/scripts/validation.py deleted file mode 100755 index 81889e41..00000000 --- a/scripts/validation.py +++ /dev/null @@ -1,604 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import parse_config - -class Command(object): - """ - providing a data structure to - conveniently convert the format from simulator output to the verilog format - """ - def __init__(self, line): - elements = line.split() - assert len(elements) == 8, "each line has to be in the format of "\ - "clk cmd chan rank bankgroup bank row col" - self.clk = int(elements[0]) - self.cmd = elements[1] - self.chan = int(elements[2]) - self.rank = int(elements[3]) - self.bankgroup = int(elements[4]) - self.bank = int(elements[5]) - self.row = int(elements[6], 16) - self.col = int(elements[7], 16) - - def get_ddr4_str(self): - """ - get a command line for verilog model workbench - """ - if self.cmd == "activate": - return "activate(.bg(%d), .ba(%d), .row(%d));\n" % (self.bankgroup, self.bank, self.row) - elif self.cmd == "read": # ap=0 no auto precharge, bc=1 NO burst chop, weird... - return "read(.bg(%d), .ba(%d), .col(%d), .ap(0), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "read_p": - return "read(.bg(%d), .ba(%d), .col(%d), .ap(1), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "write": - return "write(.bg(%d), .ba(%d), .col(%d), .ap(0), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "write_p": - return "write(.bg(%d), .ba(%d), .col(%d), .ap(1), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "precharge": - return "precharge(.bg(%d), .ba(%d), .ap(0));\n" % \ - (self.bankgroup, self.bank) - elif self.cmd == "refresh" or self.cmd == "refresh_bank": - return "refresh();\n" # currently the verilog model doesnt do bank refresh - return - - def get_ddr3_str(self): - """ - get a command line for verilog model workbench - """ - if self.cmd == "activate": - return "activate(%d, %d);\n" % (self.bank, self.row) - elif self.cmd == "read": - return "read(%d, %d, %d, %d);\n" % (self.bank, self.col, 0, 1) - elif self.cmd == "read_p": - return "read(%d, %d, %d, %d);\n" % (self.bank, self.col, 1, 1) - elif self.cmd == "write": - return "write(%d, %d, %d, %d, %d, %d);\n" % (self.bank, self.col, 0, 1, 0, 0xdeadbeaf) - elif self.cmd == "write_p": - return "write(%d, %d, %d, %d, %d, %d);\n" % (self.bank, self.col, 1, 1, 0, 0xdeadbeaf) - elif self.cmd == "refresh": - return "refresh;\n" - elif self.cmd == "precharge": - return "precharge(%d, %d);\n" % (self.bank, 0) - - def get_drampower_str(self, config): - """ - translate to generate command trace that DRAMPower can take as input - to validate power calculation, but - we need to know the config in order to calculate bank number - """ - str_map = { - "activate": "ACT", - "read": "RD", - "read_p": "RDA", - "write": "WR", - "write_p": "WRA", - "precharge": "PRE", - "refresh": "REF" - } - cmd_str = str_map[self.cmd] - bank_num = self.bankgroup * config["dram_structure"]["banks_per_group"] + self.bank - return "%d,%s,%d\n" % (self.clk, cmd_str, bank_num) - -def calculate_megs_per_device(config): - """ - given config dict, calculate device density in Mbits - """ - rows = config["dram_structure"]["rows"] - cols = config["dram_structure"]["columns"] - width = config["dram_structure"]["device_width"] - bgs = config["dram_structure"]["bankgroups"] - banks_per_group = config["dram_structure"]["banks_per_group"] - banks = bgs * banks_per_group - bytes_per_bank = rows * cols * width - mega_bytes_per_device = bytes_per_bank * banks / 1024 /1024 - return mega_bytes_per_device - - -class DRAMValidation(object): - """ - Base class for validation - """ - def __init__(self, config_file_name, trace_file_name, script_name="", verilog_output=""): - """ - Need to specify config ini file and trace file upon creation - """ - if (not os.path.exists(config_file_name)) or \ - (not os.path.exists(trace_file_name)): - print("config file or path file does not exist!") - exit(1) - - if verilog_output: - self.verilog_out = verilog_output - else: - self.verilog_out = trace_file_name + ".vh" - - if script_name: - self.script_out = script_name - else: - self.script_out = "" - - self.drampower_out = self.verilog_out[:-3] + ".power.trc" - - self.configs = parse_config.get_dict(config_file_name) - - trace_in = open(trace_file_name, "r") - - self.commands = trace_in.readlines() - - def get_prefix_str(self): - pass - - def get_postfix_str(self): - postfix_str = """ - test_done; - end - """ - return postfix_str - - def generate_modelsim_script(self, script_name=""): - pass - - def generate_verilog_bench(self, bench_name=""): - pass - - def generate_drampower_trace(self): - with open(self.drampower_out, "w") as fp: - for cmd_str in self.commands: - cmd = Command(cmd_str) - fp.write(cmd.get_drampower_str(self.configs)) - return - - - def validation(self): - self.generate_modelsim_script(self.script_out) - self.generate_verilog_bench(self.verilog_out) - self.generate_drampower_trace() - - -class DDR3Validation(DRAMValidation): - - def get_prefix_str(self): - """ - setting up the workbench initialization - """ - al = self.configs["timing"]["al"] - cl = self.configs["timing"]["cl"] - - if al == 0: - mod_1_str = "b0000000110" - elif al == (cl - 1): - mod_1_str = "b0000001110" - elif al == (cl - 2): - mod_1_str = "b0000010110" - else: - mod_1_str = "b0000000110" - print("Invalid AL/CL values!") - exit(1) - - prefix_str = """ - initial begin : test - parameter [31:0] REP = DQ_BITS/8.0; - reg [BA_BITS-1:0] r_bank; - reg [ROW_BITS-1:0] r_row; - reg [COL_BITS-1:0] r_col; - reg [BL_MAX*DQ_BITS-1:0] r_data; - integer r_i, r_j; - real original_tck; - reg [8*DQ_BITS-1:0] d0, d1, d2, d3; - d0 = { - {REP{8'h07}}, {REP{8'h06}}, {REP{8'h05}}, {REP{8'h04}}, - {REP{8'h03}}, {REP{8'h02}}, {REP{8'h01}}, {REP{8'h00}} - }; - d1 = { - {REP{8'h17}}, {REP{8'h16}}, {REP{8'h15}}, {REP{8'h14}}, - {REP{8'h13}}, {REP{8'h12}}, {REP{8'h11}}, {REP{8'h10}} - }; - d2 = { - {REP{8'h27}}, {REP{8'h26}}, {REP{8'h25}}, {REP{8'h24}}, - {REP{8'h23}}, {REP{8'h22}}, {REP{8'h21}}, {REP{8'h20}} - }; - d3 = { - {REP{8'h37}}, {REP{8'h36}}, {REP{8'h35}}, {REP{8'h34}}, - {REP{8'h33}}, {REP{8'h32}}, {REP{8'h31}}, {REP{8'h30}} - }; - rst_n <= 1'b0; - cke <= 1'b0; - cs_n <= 1'b1; - ras_n <= 1'b1; - cas_n <= 1'b1; - we_n <= 1'b1; - ba <= {BA_BITS{1'bz}}; - a <= {ADDR_BITS{1'bz}}; - odt_out <= 1'b0; - dq_en <= 1'b0; - dqs_en <= 1'b0; - // POWERUP SECTION - power_up; - // INITIALIZE SECTION - zq_calibration (1); // perform Long ZQ Calibration - load_mode (3, 14'b00000000000000); // Extended Mode Register (3) - nop (tmrd-1); - load_mode (2, {14'b00001000_000_000} | mr_cwl<<3); // Extended Mode Register 2 with DCC Disable - nop (tmrd-1); - load_mode (1, 14'%s); // Extended Mode Register with DLL Enable - nop (tmrd-1); - load_mode (0, {14'b0_1_000_1_0_000_1_0_00} | mr_wr<<9 | mr_cl<<2); // Mode Register with DLL Reset - nop (683); // make sure tDLLK and tZQINIT satisify - odt_out <= 0; // turn off odt, making life much easier... - nop (7); - """ % (mod_1_str) - return prefix_str - - def generate_modelsim_script(self, script_name=""): - if not self.script_out: - self.script_out = "run_modelsim_ddr3.sh" - - megs = calculate_megs_per_device(self.configs) - if megs == 1024: - density = "den1024Mb" - elif megs == 2048: - density = "den2048Mb" - elif megs == 4096: - density = "den4096Mb" - elif megs == 8192: - density = "den8192Mb" - else: - print("unknown device density: %d! MBs" % (megs)) - exit(1) - width = self.configs["dram_structure"]["device_width"] - tck = self.configs["timing"]["tck"] - speed_table = { # based on 1Gb device - 0.938: "sg093", # 2133 - 1.07 : "sg107", # 1866 - 1.25 : "sg125", # 1600 - 1.50 : "sg15", # 1333J, there is also sg15E - 1.875: "sg187", # 1066G, there is also sg187E - 2.5: "sg25", # 800, there is also sg25E - } - if tck not in speed_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR3:" +\ - str([k for k in speed_table])) - speed = speed_table[tck] - - # generate script to run modelsim simulation in command line mode - # note this will generate a run_modelsim.sh script file - # also a v_out.log file after running the script - cmd_str = \ - """ - vlib work - vlog -quiet -suppress 2597 +define+%s +define+x%d +define+%s tb.v ddr3.v - vsim -quiet -nostdout -c -l v_out.log -novopt tb -do "run -all" - - """ % (density, width, speed) - - with open(self.script_out, "w") as fp: - fp.write(cmd_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "nop(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr3_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -class DDR4Validation(DRAMValidation): - - def get_prefix_str(self): - """ - this is necessary for setting up a verilog workbench - depending on the config, some of the values in this string will change correspondingly - """ - ts_table = { # tCK -> [min_ts, nominal_ts, max_ts] - 1.875: ["TS_1875", "TS_1875", "TS_1875"], # 1066MHz - 1.500: ["TS_1500", "TS_1500", "TS_1875"], # 1333MHz - 1.250: ["TS_1250", "TS_1250", "TS_1500"], # 1600MHz - 1.072: ["TS_1072", "TS_1072", "TS_1250"], # 1866MHz - 0.938: ["TS_938", "TS_938", "TS_1072"], # 2133MHz - 0.833: ["TS_833", "TS_833", "TS_938"], # 2400MHz - 0.750: ["TS_750", "TS_750", "TS_833"], # 2667MHz - 0.682: ["TS_682", "TS_682", "TS_750"], # 2934MHz - 0.625: ["TS_625", "TS_625", "TS_682"] # 3200MHz - } - ts = self.configs["timing"]["tck"] - if ts not in ts_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR4:" +\ - str([k for k in ts_table])) - ddr4_prefix_str = """ - initial begin : test - UTYPE_TS min_ts, nominal_ts, max_ts; - reg [MAX_BURST_LEN*MAX_DQ_BITS-1:0] b0to7, b8tof, b7to0, bfto8; - reg [MODEREG_BITS-1:0] mode_regs[MAX_MODEREGS]; - UTYPE_DutModeConfig dut_mode_config; - bit failure; - min_ts = %s; - nominal_ts = %s; - max_ts = %s; - b0to7 = { {MAX_DQ_BITS/4{4'h7}}, {MAX_DQ_BITS/4{4'h6}}, {MAX_DQ_BITS/4{4'h5}}, {MAX_DQ_BITS/4{4'h4}}, - {MAX_DQ_BITS/4{4'h3}}, {MAX_DQ_BITS/4{4'h2}}, {MAX_DQ_BITS/4{4'h1}}, {MAX_DQ_BITS/4{4'h0}} }; - b8tof = { {MAX_DQ_BITS/4{4'hf}}, {MAX_DQ_BITS/4{4'he}}, {MAX_DQ_BITS/4{4'hd}}, {MAX_DQ_BITS/4{4'hc}}, - {MAX_DQ_BITS/4{4'hb}}, {MAX_DQ_BITS/4{4'ha}}, {MAX_DQ_BITS/4{4'h9}}, {MAX_DQ_BITS/4{4'h8}} }; - b7to0 = { {MAX_DQ_BITS/4{4'h0}}, {MAX_DQ_BITS/4{4'h1}}, {MAX_DQ_BITS/4{4'h2}}, {MAX_DQ_BITS/4{4'h3}}, - {MAX_DQ_BITS/4{4'h4}}, {MAX_DQ_BITS/4{4'h5}}, {MAX_DQ_BITS/4{4'h6}}, {MAX_DQ_BITS/4{4'h7}} }; - bfto8 = { {MAX_DQ_BITS/4{4'h8}}, {MAX_DQ_BITS/4{4'h9}}, {MAX_DQ_BITS/4{4'ha}}, {MAX_DQ_BITS/4{4'hb}}, - {MAX_DQ_BITS/4{4'hc}}, {MAX_DQ_BITS/4{4'hd}}, {MAX_DQ_BITS/4{4'he}}, {MAX_DQ_BITS/4{4'hf}} }; - iDDR4.RESET_n <= 1'b1; - iDDR4.CKE <= 1'b0; - iDDR4.CS_n <= 1'b1; - iDDR4.ACT_n <= 1'b1; - iDDR4.RAS_n_A16 <= 1'b1; - iDDR4.CAS_n_A15 <= 1'b1; - iDDR4.WE_n_A14 <= 1'b1; - iDDR4.BG <= '1; - iDDR4.BA <= '1; - iDDR4.ADDR <= '1; - iDDR4.ADDR_17 <= '0; - iDDR4.ODT <= 1'b0; - iDDR4.PARITY <= 0; - iDDR4.ALERT_n <= 1; - iDDR4.PWR <= 0; - iDDR4.TEN <= 0; - iDDR4.VREF_CA <= 0; - iDDR4.VREF_DQ <= 0; - iDDR4.ZQ <= 0; - dq_en <= 1'b0; - dqs_en <= 1'b0; - default_period(nominal_ts); - // POWERUP SECTION - power_up(); - // Reset DLL - dut_mode_config = _state.DefaultDutModeConfig(.cl(%d), - .write_recovery(%d), - .qoff(0), - .cwl(%d), - .rd_preamble_clocks(%d), - .wr_preamble_clocks(%d), - .read_dbi(0), - .write_dbi(0), - .bl_reg(rBL8), - .dll_enable(1), - .dll_reset(1), - .dm_enable(0)); - dut_mode_config.AL = 0; - dut_mode_config.BL = 8; - _state.ModeToAddrDecode(dut_mode_config, mode_regs); - load_mode(.bg(0), .ba(1), .addr(mode_regs[1])); - deselect(timing.tDLLKc); - dut_mode_config.DLL_reset = 0; - _state.ModeToAddrDecode(dut_mode_config, mode_regs); - load_mode(.bg(0), .ba(3), .addr(mode_regs[3])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(2), .addr(mode_regs[6])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(1), .addr(mode_regs[5])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(0), .addr(mode_regs[4])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(2), .addr(mode_regs[2])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(1), .addr(mode_regs[1])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(0), .addr(mode_regs[0])); - deselect(timing.tMOD/timing.tCK); - zq_cl(); - deselect(timing.tZQinitc); - odt_out <= 0; // turn off odt - - golden_model.SetDutModeConfig(dut_mode_config); - golden_model.set_timing_parameter_lock(.locked(1), .recalculate_params(1), .non_spec_tck(%s)); // Prevent tCK changes from changing the loaded timeset. - """ % (ts_table[ts][0], # min_ts, not used - ts_table[ts][1], - ts_table[ts][2], # max_ts, not used - self.configs["timing"]["cl"], - self.configs["timing"]["twr"] + 1, # have to + 1 to make verilog model happy.. - self.configs["timing"]["cwl"], - self.configs["timing"]["trpre"], - self.configs["timing"]["twpre"], - ts_table[ts][1][3:], # non_spec_tck, throw away TS_ and only leaves clock - ) - return ddr4_prefix_str - - def generate_modelsim_script(self, script_name=""): - """ - This function should: - - generate a verilog file for the validation workbench - - generate the command based on the config file - """ - if not self.script_out: - self.script_out = "run_modelsim_ddr4.sh" - - dev_str = "DDR4_" - megs = calculate_megs_per_device(self.configs) - if megs == 4096: - density = "4G" - elif megs == 8192: - density = "8G" - elif megs == 16384: - density = "16G" - else: - print("unknown device density: %d! MBs" % (megs)) - exit(1) - - width = self.configs["dram_structure"]["device_width"] - - dev_str = dev_str + density + "_X" + str(width) # should be something like DDR4_8G_X8 - - vlib_str = "vlib work\n" - cmd_str = "vlog -quiet -suppress 2597 -work work +acc -l vcs.log -novopt -sv "\ - "+define+%s arch_package.sv proj_package.sv " \ - "interface.sv StateTable.svp MemoryArray.svp ddr4_model.svp tb.sv \n" % dev_str - vsim_str = "vsim -quiet -nostdout -c -l v_out.log -novopt tb -do \"run -all\"\n" - - with open(self.script_out, "w") as fp: - fp.write(vlib_str) - fp.write(cmd_str) - fp.write(vsim_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "deselect(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr4_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -class LPDDRValidtion(DRAMValidation): - - def get_prefix_str(self): - cl = self.configs["timing"]["cl"] - bl = self.configs["dram_structure"]["bl"] - - if bl == 2: - bl_bits = "001" - elif bl == 4: - bl_bits = "010" - elif bl == 8: - bl_bits = "011" - else: # BL=16 - bl_bits = "100" - - if cl == 2: - cl_bits = "10" - else: - cl_bits = "11" - - prefix = """ - initial begin:test - //ck <= 1'b0; - cke <= 1'b0; - cs_n <= 1'bz; - ras_n <= 1'bz; - cas_n <= 1'bz; - we_n <= 1'bz; - a <= {ADDR_BITS{1'bz}}; - ba <= {BA_BITS{1'bz}}; - dq_en <= 1'b0; - dqs_en <= 1'b0; - power_up; - nop (10); // wait 10 clocks intead of 200 us for simulation purposes - precharge('h00000000, 1); - nop(trp); - refresh; - nop(trfc); - refresh; - nop(trfc); - load_mode('h0, 'b0%s_0_%s); // setting CL and BL correctly - nop(tmrd); - load_mode('h2, 'b0); - nop(tmrd); - """ % (cl_bits, bl_bits) - return prefix - - def generate_modelsim_script(self, script_name=""): - if not self.script_out: - self.script_out = "run_modelsim_lpddr.sh" - megs = calculate_megs_per_device(self.configs) - density = "den%dMb" % megs - tck = self.configs["timing"]["tck"] - speed_table = { # based on 1Gb device - 4.8: "sg5", - 5.4 : "sg54", - 6.0 : "sg6", - 7.5 : "sg75", - } - if tck not in speed_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR3:" +\ - str([k for k in speed_table])) - speed = speed_table[tck] - width = self.configs["dram_structure"]["device_width"] - cmd_str = \ - """ - vlib work - vlog -quiet -suppress 2597 +define+%s +define+%s +define+x%d tb.v mobile_ddr.v - vsim -quiet -nostdout -c -l v_out.log -novopt tb -do "run -all" - """ % (density, speed, width) - - with open(self.script_out, "w") as fp: - fp.write(cmd_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "nop(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr3_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -if __name__ == "__main__": - assert len(sys.argv) == 3, "Need 2 arguments, 1. config file name 2. command trace file name" - - if not (os.path.exists(sys.argv[1]) and os.path.exists(sys.argv[2])): - print("cannot locate input files, please check your input file name and path") - exit(1) - - ini_file = sys.argv[1] - cmd_trace_file = sys.argv[2] - - configs = parse_config.get_dict(ini_file) - - validation = None - if configs["dram_structure"]["protocol"] == "DDR4": - validation = DDR4Validation(ini_file, cmd_trace_file) - elif configs["dram_structure"]["protocol"] == "DDR3": - validation = DDR3Validation(ini_file, cmd_trace_file) - elif configs["dram_structure"]["protocol"] == "LPDDR": - validation = LPDDRValidtion(ini_file, cmd_trace_file) - else: - pass - - validation.validation() - - - - - diff --git a/src/configuration.cc b/src/configuration.cc index ea4a09ed..669bb977 100644 --- a/src/configuration.cc +++ b/src/configuration.cc @@ -68,7 +68,8 @@ DRAMProtocol Config::GetDRAMProtocol(std::string protocol_str) { {"GDDR5", DRAMProtocol::GDDR5}, {"GDDR5X", DRAMProtocol::GDDR5X}, {"GDDR6", DRAMProtocol::GDDR6}, {"LPDDR", DRAMProtocol::LPDDR}, {"LPDDR3", DRAMProtocol::LPDDR3}, {"LPDDR4", DRAMProtocol::LPDDR4}, {"HBM", DRAMProtocol::HBM}, - {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}, {"MODEL_SWAP", DRAMProtocol::MODEL_SWAP}}; + {"HBM2", DRAMProtocol::HBM2}, {"HMC", DRAMProtocol::HMC}, + {"MODEL_SWAP", DRAMProtocol::MODEL_SWAP}, {"IDEAL", DRAMProtocol::IDEAL}}; if (protocol_pairs.find(protocol_str) == protocol_pairs.end()) { std::cout << "Unkwown/Unsupported DRAM Protocol: " << protocol_str diff --git a/src/configuration.h b/src/configuration.h index 3c0f13dc..974bd302 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -22,7 +22,8 @@ enum class DRAMProtocol { HBM2, HMC, SIZE, - MODEL_SWAP + MODEL_SWAP, + IDEAL }; enum class RefreshPolicy { @@ -157,6 +158,7 @@ class Config { protocol == DRAMProtocol::HBM2); } bool IsModelSwap() const { return (protocol == DRAMProtocol::MODEL_SWAP); } + bool IsIdeal() const { return (protocol == DRAMProtocol::IDEAL); } bool IsHMC() const { return (protocol == DRAMProtocol::HMC); } // yzy: add another function bool IsDDR4() const { return (protocol == DRAMProtocol::DDR4); } diff --git a/src/dram_system.cc b/src/dram_system.cc index 22352776..ba7f3beb 100644 --- a/src/dram_system.cc +++ b/src/dram_system.cc @@ -173,7 +173,12 @@ IdealDRAMSystem::IdealDRAMSystem(Config &config, const std::string &output_dir, std::function read_callback, std::function write_callback) : BaseDRAMSystem(config, output_dir, read_callback, write_callback), - latency_(config_.ideal_memory_latency) {} + latency_(config_.ideal_memory_latency) { + if (config_.IsModelSwap()) { + std::cerr << "Initialized an ideal memory system!" + << std::endl; + } + } IdealDRAMSystem::~IdealDRAMSystem() {} diff --git a/src/memory_system.cc b/src/memory_system.cc index 33d0ef89..f8abba84 100644 --- a/src/memory_system.cc +++ b/src/memory_system.cc @@ -13,6 +13,9 @@ MemorySystem::MemorySystem(const std::string &config_file, } else if (config_->IsModelSwap()) { dram_system_ = new ModelSwapDRAMSystem(*config_, output_dir, read_callback, write_callback); + } else if (config_->IsIdeal()) { + dram_system_ = new IdealDRAMSystem(*config_, output_dir, read_callback, + write_callback); } else { dram_system_ = new JedecDRAMSystem(*config_, output_dir, read_callback, write_callback); From 0944befe6b364186a970447a3840425a8b7583f5 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Lynch Date: Thu, 28 Oct 2021 18:44:10 -0400 Subject: [PATCH 11/17] delete heatmap and validation to allow a merge? --- scripts/heatmap.py | 222 ---------------- scripts/validation.py | 604 ------------------------------------------ 2 files changed, 826 deletions(-) delete mode 100644 scripts/heatmap.py delete mode 100644 scripts/validation.py diff --git a/scripts/heatmap.py b/scripts/heatmap.py deleted file mode 100644 index e48aa990..00000000 --- a/scripts/heatmap.py +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import os -import sys -from collections import OrderedDict - -try: - import numpy as np - import pandas as pd - import matplotlib -except: - print("please install numpy, matplotlib and pandas") - raise - -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import matplotlib.patches as patches - - - -def construct_mesh(df, val_key, xkey="x", ykey="y"): - """ - to construct mesh data structure to be used for plotting later - this should be as generic as possible - the 3 keys in the args are used to locate data in the dataframe - return a dict that can be used by pcolor/pcolormesh functions - """ - x = df[xkey] - y = df[ykey] - t = df[val_key] - xx, yy = np.meshgrid(x.unique(), y.unique()) - zz = [] - y_groups = df.groupby(ykey) - for i in y.unique(): - group = y_groups.get_group(i) - z = group[val_key] - zz.append(z) - zz = np.array(zz) - res = {"x":xx, "y":yy, "val":zz} - return res - - -def plot_heatmap(x, y, t, title, save_to=""): - """ - quick access to single heatmap - """ - fig = plt.figure() - ax = fig.add_subplot(111) - pcm = ax.pcolormesh(x, y, t, cmap="coolwarm") - fig.colorbar(pcm, ax=ax, extend="max") - fig.savefig("heatmap.png") - - -def plot_sub_heatmap(fig, ax, x, y, t, title): - pcm = ax.pcolormesh(x, y, t, cmap="coolwarm") - ax.set_title(title) - # no offset used since temperature should be straightforward - c_bar_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False) - cbar = fig.colorbar(pcm, ax=ax, extend="max", format=c_bar_formatter) - return fig, ax - -def prep_fig_axes(num_plots): - """ - so for each z dimension we plot 1 fig and if - there are multiple channels plot them as subplots - returns a dict with fig as keys and axes list as values - """ - fig = plt.figure(tight_layout=True) - if num_plots == 1: - n_rows = 1 - n_cols = 1 - elif num_plots == 2: - n_rows = 1 - n_cols = 2 - elif num_plots == 4: - n_rows = 2 - n_cols = 2 - elif num_plots ==8: - n_rows = 2 - n_cols = 4 - elif num_plots == 16: - n_rows = 4 - n_cols = 4 - elif num_plots == 32: - n_rows = 4 - n_cols = 8 - elif num_plots == 64: - n_rows = 8 - n_cols = 8 - else: - n_rows = 1 - n_cols = 1 - # create axes in subplot - plot_num = 1 - for i in range(num_plots): - # args in add_subplot start from 1 - ax = fig.add_subplot(n_rows, n_cols, plot_num) - plot_num += 1 - return fig, fig.get_axes() - - -def plot_multi_rank_heatmap(multi_rank_data, save_to=""): - """ - this should also be a generic plot function - return figs and axes so that we can process it later - """ - num_plots = len(multi_rank_data) - fig, axes = prep_fig_axes(num_plots) - plot_num = 0 - for ax in axes: - data = multi_rank_data[plot_num] - plot_sub_heatmap(fig, ax, data["x"], data["y"], data["val"], data["title"]) - plot_num += 1 - return fig, axes - - -def plot_bank_patch(bank_line_data, fig_axes, show_num=True): - z = bank_line_data["z"] - fig = fig_axes[z]["fig"] - axes = fig_axes[z]["axes"] - x_len = bank_line_data["end_x"] - bank_line_data["start_x"] - y_len = bank_line_data["end_y"] - bank_line_data["start_y"] - starting_coord = (bank_line_data["start_x"], bank_line_data["start_y"]) - for ax in axes: - ax.add_patch( - patches.Rectangle( - starting_coord, - x_len, - y_len, - fill=False, - edgecolor=None, # default - linewidth=None # default - ) - ) - if show_num: - ax.text( - starting_coord[0] + 2, - starting_coord[1] + 2, - "B" + str(bank_line_data["bank_id"]), - fontsize=8, - color="white" - ) - - return - - -def save_figs(figs, prefix, img_format="png"): - for i, fig_axes in enumerate(figs): - fig = fig_axes["fig"] - fig_name = prefix + str(i) + "." + img_format - print("generating ",fig_name) - fig.savefig(fig_name) - - -def plot_simulation(stats_csv_file, bank_pos_file): - """ - so for each z dimension we plot 1 fig and if - there are multiple channels plot them as subplots - """ - frame = pd.read_csv(stats_csv_file) - die_frames = frame.groupby("z") - power_data = [] - temp_data = [] - for z, z_frame in die_frames: - rank_frames = z_frame.groupby("rank_channel_index") - z_power_data = [] - z_temp_data = [] - for rank, rank_frame in rank_frames: - rank_power_data = construct_mesh(rank_frame, "power", "x", "y") - rank_power_data["title"] = "die_" + str(z) + "_channel_rank_" + str(rank) + "_power" - rank_temp_data = construct_mesh(rank_frame, "temperature", "x", "y") - rank_temp_data["title"] = "die_" + str(z) + "_channel_rank_" + str(rank) + "_temperature" - z_power_data.append(rank_power_data) - z_temp_data.append(rank_temp_data) - power_data.append(z_power_data) - temp_data.append(z_temp_data) - - num_figs = len(power_data) - power_figs = [] - temp_figs = [] - for i in range(num_figs): - fig, axes = plot_multi_rank_heatmap(power_data[i]) - power_figs.append({"fig":fig, "axes":axes}) - fig, axes = plot_multi_rank_heatmap(temp_data[i]) - temp_figs.append({"fig":fig, "axes":axes}) - - bank_pos_frame = pd.read_csv(bank_pos_file) - - bank_pos = [] - for index, row in bank_pos_frame.iterrows(): - plot_bank_patch(row, power_figs) - plot_bank_patch(row, temp_figs) - return power_figs, temp_figs - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Plot power and temperature heatmap") - parser.add_argument("-p", "--prefix", help="prefix of the simulation," - "if this is provided then no need for other arguments", - default = "") - parser.add_argument("-s", "--stats-csv", help="temp and power stats csv file") - parser.add_argument("-b", "--bank-csv", help="bank postion csv file") - args = parser.parse_args() - prefix = args.prefix - if prefix: - csv_file = prefix + "final_power_temperature.csv" - bank_pos_file = prefix + "bank_position.csv" - else: - if args.stats_csv: - print(args.stats_csv) - csv_file = args.stats_csv - else: - print("need stats csv file for temp and power!") - exit(1) - if args.bank_csv: - print(args.bank_csv) - bank_pos_file = args.bank_csv - else: - print("need bank position file!") - exit(1) - p_figs, t_figs = plot_simulation(csv_file, bank_pos_file) - save_figs(p_figs, prefix + "fig_power_") - save_figs(t_figs, prefix + "fig_temp_") diff --git a/scripts/validation.py b/scripts/validation.py deleted file mode 100644 index 81889e41..00000000 --- a/scripts/validation.py +++ /dev/null @@ -1,604 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import parse_config - -class Command(object): - """ - providing a data structure to - conveniently convert the format from simulator output to the verilog format - """ - def __init__(self, line): - elements = line.split() - assert len(elements) == 8, "each line has to be in the format of "\ - "clk cmd chan rank bankgroup bank row col" - self.clk = int(elements[0]) - self.cmd = elements[1] - self.chan = int(elements[2]) - self.rank = int(elements[3]) - self.bankgroup = int(elements[4]) - self.bank = int(elements[5]) - self.row = int(elements[6], 16) - self.col = int(elements[7], 16) - - def get_ddr4_str(self): - """ - get a command line for verilog model workbench - """ - if self.cmd == "activate": - return "activate(.bg(%d), .ba(%d), .row(%d));\n" % (self.bankgroup, self.bank, self.row) - elif self.cmd == "read": # ap=0 no auto precharge, bc=1 NO burst chop, weird... - return "read(.bg(%d), .ba(%d), .col(%d), .ap(0), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "read_p": - return "read(.bg(%d), .ba(%d), .col(%d), .ap(1), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "write": - return "write(.bg(%d), .ba(%d), .col(%d), .ap(0), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "write_p": - return "write(.bg(%d), .ba(%d), .col(%d), .ap(1), .bc(1));\n" % \ - (self.bankgroup, self.bank, self.col) - elif self.cmd == "precharge": - return "precharge(.bg(%d), .ba(%d), .ap(0));\n" % \ - (self.bankgroup, self.bank) - elif self.cmd == "refresh" or self.cmd == "refresh_bank": - return "refresh();\n" # currently the verilog model doesnt do bank refresh - return - - def get_ddr3_str(self): - """ - get a command line for verilog model workbench - """ - if self.cmd == "activate": - return "activate(%d, %d);\n" % (self.bank, self.row) - elif self.cmd == "read": - return "read(%d, %d, %d, %d);\n" % (self.bank, self.col, 0, 1) - elif self.cmd == "read_p": - return "read(%d, %d, %d, %d);\n" % (self.bank, self.col, 1, 1) - elif self.cmd == "write": - return "write(%d, %d, %d, %d, %d, %d);\n" % (self.bank, self.col, 0, 1, 0, 0xdeadbeaf) - elif self.cmd == "write_p": - return "write(%d, %d, %d, %d, %d, %d);\n" % (self.bank, self.col, 1, 1, 0, 0xdeadbeaf) - elif self.cmd == "refresh": - return "refresh;\n" - elif self.cmd == "precharge": - return "precharge(%d, %d);\n" % (self.bank, 0) - - def get_drampower_str(self, config): - """ - translate to generate command trace that DRAMPower can take as input - to validate power calculation, but - we need to know the config in order to calculate bank number - """ - str_map = { - "activate": "ACT", - "read": "RD", - "read_p": "RDA", - "write": "WR", - "write_p": "WRA", - "precharge": "PRE", - "refresh": "REF" - } - cmd_str = str_map[self.cmd] - bank_num = self.bankgroup * config["dram_structure"]["banks_per_group"] + self.bank - return "%d,%s,%d\n" % (self.clk, cmd_str, bank_num) - -def calculate_megs_per_device(config): - """ - given config dict, calculate device density in Mbits - """ - rows = config["dram_structure"]["rows"] - cols = config["dram_structure"]["columns"] - width = config["dram_structure"]["device_width"] - bgs = config["dram_structure"]["bankgroups"] - banks_per_group = config["dram_structure"]["banks_per_group"] - banks = bgs * banks_per_group - bytes_per_bank = rows * cols * width - mega_bytes_per_device = bytes_per_bank * banks / 1024 /1024 - return mega_bytes_per_device - - -class DRAMValidation(object): - """ - Base class for validation - """ - def __init__(self, config_file_name, trace_file_name, script_name="", verilog_output=""): - """ - Need to specify config ini file and trace file upon creation - """ - if (not os.path.exists(config_file_name)) or \ - (not os.path.exists(trace_file_name)): - print("config file or path file does not exist!") - exit(1) - - if verilog_output: - self.verilog_out = verilog_output - else: - self.verilog_out = trace_file_name + ".vh" - - if script_name: - self.script_out = script_name - else: - self.script_out = "" - - self.drampower_out = self.verilog_out[:-3] + ".power.trc" - - self.configs = parse_config.get_dict(config_file_name) - - trace_in = open(trace_file_name, "r") - - self.commands = trace_in.readlines() - - def get_prefix_str(self): - pass - - def get_postfix_str(self): - postfix_str = """ - test_done; - end - """ - return postfix_str - - def generate_modelsim_script(self, script_name=""): - pass - - def generate_verilog_bench(self, bench_name=""): - pass - - def generate_drampower_trace(self): - with open(self.drampower_out, "w") as fp: - for cmd_str in self.commands: - cmd = Command(cmd_str) - fp.write(cmd.get_drampower_str(self.configs)) - return - - - def validation(self): - self.generate_modelsim_script(self.script_out) - self.generate_verilog_bench(self.verilog_out) - self.generate_drampower_trace() - - -class DDR3Validation(DRAMValidation): - - def get_prefix_str(self): - """ - setting up the workbench initialization - """ - al = self.configs["timing"]["al"] - cl = self.configs["timing"]["cl"] - - if al == 0: - mod_1_str = "b0000000110" - elif al == (cl - 1): - mod_1_str = "b0000001110" - elif al == (cl - 2): - mod_1_str = "b0000010110" - else: - mod_1_str = "b0000000110" - print("Invalid AL/CL values!") - exit(1) - - prefix_str = """ - initial begin : test - parameter [31:0] REP = DQ_BITS/8.0; - reg [BA_BITS-1:0] r_bank; - reg [ROW_BITS-1:0] r_row; - reg [COL_BITS-1:0] r_col; - reg [BL_MAX*DQ_BITS-1:0] r_data; - integer r_i, r_j; - real original_tck; - reg [8*DQ_BITS-1:0] d0, d1, d2, d3; - d0 = { - {REP{8'h07}}, {REP{8'h06}}, {REP{8'h05}}, {REP{8'h04}}, - {REP{8'h03}}, {REP{8'h02}}, {REP{8'h01}}, {REP{8'h00}} - }; - d1 = { - {REP{8'h17}}, {REP{8'h16}}, {REP{8'h15}}, {REP{8'h14}}, - {REP{8'h13}}, {REP{8'h12}}, {REP{8'h11}}, {REP{8'h10}} - }; - d2 = { - {REP{8'h27}}, {REP{8'h26}}, {REP{8'h25}}, {REP{8'h24}}, - {REP{8'h23}}, {REP{8'h22}}, {REP{8'h21}}, {REP{8'h20}} - }; - d3 = { - {REP{8'h37}}, {REP{8'h36}}, {REP{8'h35}}, {REP{8'h34}}, - {REP{8'h33}}, {REP{8'h32}}, {REP{8'h31}}, {REP{8'h30}} - }; - rst_n <= 1'b0; - cke <= 1'b0; - cs_n <= 1'b1; - ras_n <= 1'b1; - cas_n <= 1'b1; - we_n <= 1'b1; - ba <= {BA_BITS{1'bz}}; - a <= {ADDR_BITS{1'bz}}; - odt_out <= 1'b0; - dq_en <= 1'b0; - dqs_en <= 1'b0; - // POWERUP SECTION - power_up; - // INITIALIZE SECTION - zq_calibration (1); // perform Long ZQ Calibration - load_mode (3, 14'b00000000000000); // Extended Mode Register (3) - nop (tmrd-1); - load_mode (2, {14'b00001000_000_000} | mr_cwl<<3); // Extended Mode Register 2 with DCC Disable - nop (tmrd-1); - load_mode (1, 14'%s); // Extended Mode Register with DLL Enable - nop (tmrd-1); - load_mode (0, {14'b0_1_000_1_0_000_1_0_00} | mr_wr<<9 | mr_cl<<2); // Mode Register with DLL Reset - nop (683); // make sure tDLLK and tZQINIT satisify - odt_out <= 0; // turn off odt, making life much easier... - nop (7); - """ % (mod_1_str) - return prefix_str - - def generate_modelsim_script(self, script_name=""): - if not self.script_out: - self.script_out = "run_modelsim_ddr3.sh" - - megs = calculate_megs_per_device(self.configs) - if megs == 1024: - density = "den1024Mb" - elif megs == 2048: - density = "den2048Mb" - elif megs == 4096: - density = "den4096Mb" - elif megs == 8192: - density = "den8192Mb" - else: - print("unknown device density: %d! MBs" % (megs)) - exit(1) - width = self.configs["dram_structure"]["device_width"] - tck = self.configs["timing"]["tck"] - speed_table = { # based on 1Gb device - 0.938: "sg093", # 2133 - 1.07 : "sg107", # 1866 - 1.25 : "sg125", # 1600 - 1.50 : "sg15", # 1333J, there is also sg15E - 1.875: "sg187", # 1066G, there is also sg187E - 2.5: "sg25", # 800, there is also sg25E - } - if tck not in speed_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR3:" +\ - str([k for k in speed_table])) - speed = speed_table[tck] - - # generate script to run modelsim simulation in command line mode - # note this will generate a run_modelsim.sh script file - # also a v_out.log file after running the script - cmd_str = \ - """ - vlib work - vlog -quiet -suppress 2597 +define+%s +define+x%d +define+%s tb.v ddr3.v - vsim -quiet -nostdout -c -l v_out.log -novopt tb -do "run -all" - - """ % (density, width, speed) - - with open(self.script_out, "w") as fp: - fp.write(cmd_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "nop(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr3_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -class DDR4Validation(DRAMValidation): - - def get_prefix_str(self): - """ - this is necessary for setting up a verilog workbench - depending on the config, some of the values in this string will change correspondingly - """ - ts_table = { # tCK -> [min_ts, nominal_ts, max_ts] - 1.875: ["TS_1875", "TS_1875", "TS_1875"], # 1066MHz - 1.500: ["TS_1500", "TS_1500", "TS_1875"], # 1333MHz - 1.250: ["TS_1250", "TS_1250", "TS_1500"], # 1600MHz - 1.072: ["TS_1072", "TS_1072", "TS_1250"], # 1866MHz - 0.938: ["TS_938", "TS_938", "TS_1072"], # 2133MHz - 0.833: ["TS_833", "TS_833", "TS_938"], # 2400MHz - 0.750: ["TS_750", "TS_750", "TS_833"], # 2667MHz - 0.682: ["TS_682", "TS_682", "TS_750"], # 2934MHz - 0.625: ["TS_625", "TS_625", "TS_682"] # 3200MHz - } - ts = self.configs["timing"]["tck"] - if ts not in ts_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR4:" +\ - str([k for k in ts_table])) - ddr4_prefix_str = """ - initial begin : test - UTYPE_TS min_ts, nominal_ts, max_ts; - reg [MAX_BURST_LEN*MAX_DQ_BITS-1:0] b0to7, b8tof, b7to0, bfto8; - reg [MODEREG_BITS-1:0] mode_regs[MAX_MODEREGS]; - UTYPE_DutModeConfig dut_mode_config; - bit failure; - min_ts = %s; - nominal_ts = %s; - max_ts = %s; - b0to7 = { {MAX_DQ_BITS/4{4'h7}}, {MAX_DQ_BITS/4{4'h6}}, {MAX_DQ_BITS/4{4'h5}}, {MAX_DQ_BITS/4{4'h4}}, - {MAX_DQ_BITS/4{4'h3}}, {MAX_DQ_BITS/4{4'h2}}, {MAX_DQ_BITS/4{4'h1}}, {MAX_DQ_BITS/4{4'h0}} }; - b8tof = { {MAX_DQ_BITS/4{4'hf}}, {MAX_DQ_BITS/4{4'he}}, {MAX_DQ_BITS/4{4'hd}}, {MAX_DQ_BITS/4{4'hc}}, - {MAX_DQ_BITS/4{4'hb}}, {MAX_DQ_BITS/4{4'ha}}, {MAX_DQ_BITS/4{4'h9}}, {MAX_DQ_BITS/4{4'h8}} }; - b7to0 = { {MAX_DQ_BITS/4{4'h0}}, {MAX_DQ_BITS/4{4'h1}}, {MAX_DQ_BITS/4{4'h2}}, {MAX_DQ_BITS/4{4'h3}}, - {MAX_DQ_BITS/4{4'h4}}, {MAX_DQ_BITS/4{4'h5}}, {MAX_DQ_BITS/4{4'h6}}, {MAX_DQ_BITS/4{4'h7}} }; - bfto8 = { {MAX_DQ_BITS/4{4'h8}}, {MAX_DQ_BITS/4{4'h9}}, {MAX_DQ_BITS/4{4'ha}}, {MAX_DQ_BITS/4{4'hb}}, - {MAX_DQ_BITS/4{4'hc}}, {MAX_DQ_BITS/4{4'hd}}, {MAX_DQ_BITS/4{4'he}}, {MAX_DQ_BITS/4{4'hf}} }; - iDDR4.RESET_n <= 1'b1; - iDDR4.CKE <= 1'b0; - iDDR4.CS_n <= 1'b1; - iDDR4.ACT_n <= 1'b1; - iDDR4.RAS_n_A16 <= 1'b1; - iDDR4.CAS_n_A15 <= 1'b1; - iDDR4.WE_n_A14 <= 1'b1; - iDDR4.BG <= '1; - iDDR4.BA <= '1; - iDDR4.ADDR <= '1; - iDDR4.ADDR_17 <= '0; - iDDR4.ODT <= 1'b0; - iDDR4.PARITY <= 0; - iDDR4.ALERT_n <= 1; - iDDR4.PWR <= 0; - iDDR4.TEN <= 0; - iDDR4.VREF_CA <= 0; - iDDR4.VREF_DQ <= 0; - iDDR4.ZQ <= 0; - dq_en <= 1'b0; - dqs_en <= 1'b0; - default_period(nominal_ts); - // POWERUP SECTION - power_up(); - // Reset DLL - dut_mode_config = _state.DefaultDutModeConfig(.cl(%d), - .write_recovery(%d), - .qoff(0), - .cwl(%d), - .rd_preamble_clocks(%d), - .wr_preamble_clocks(%d), - .read_dbi(0), - .write_dbi(0), - .bl_reg(rBL8), - .dll_enable(1), - .dll_reset(1), - .dm_enable(0)); - dut_mode_config.AL = 0; - dut_mode_config.BL = 8; - _state.ModeToAddrDecode(dut_mode_config, mode_regs); - load_mode(.bg(0), .ba(1), .addr(mode_regs[1])); - deselect(timing.tDLLKc); - dut_mode_config.DLL_reset = 0; - _state.ModeToAddrDecode(dut_mode_config, mode_regs); - load_mode(.bg(0), .ba(3), .addr(mode_regs[3])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(2), .addr(mode_regs[6])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(1), .addr(mode_regs[5])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(1), .ba(0), .addr(mode_regs[4])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(2), .addr(mode_regs[2])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(1), .addr(mode_regs[1])); - deselect(timing.tMOD/timing.tCK); - load_mode(.bg(0), .ba(0), .addr(mode_regs[0])); - deselect(timing.tMOD/timing.tCK); - zq_cl(); - deselect(timing.tZQinitc); - odt_out <= 0; // turn off odt - - golden_model.SetDutModeConfig(dut_mode_config); - golden_model.set_timing_parameter_lock(.locked(1), .recalculate_params(1), .non_spec_tck(%s)); // Prevent tCK changes from changing the loaded timeset. - """ % (ts_table[ts][0], # min_ts, not used - ts_table[ts][1], - ts_table[ts][2], # max_ts, not used - self.configs["timing"]["cl"], - self.configs["timing"]["twr"] + 1, # have to + 1 to make verilog model happy.. - self.configs["timing"]["cwl"], - self.configs["timing"]["trpre"], - self.configs["timing"]["twpre"], - ts_table[ts][1][3:], # non_spec_tck, throw away TS_ and only leaves clock - ) - return ddr4_prefix_str - - def generate_modelsim_script(self, script_name=""): - """ - This function should: - - generate a verilog file for the validation workbench - - generate the command based on the config file - """ - if not self.script_out: - self.script_out = "run_modelsim_ddr4.sh" - - dev_str = "DDR4_" - megs = calculate_megs_per_device(self.configs) - if megs == 4096: - density = "4G" - elif megs == 8192: - density = "8G" - elif megs == 16384: - density = "16G" - else: - print("unknown device density: %d! MBs" % (megs)) - exit(1) - - width = self.configs["dram_structure"]["device_width"] - - dev_str = dev_str + density + "_X" + str(width) # should be something like DDR4_8G_X8 - - vlib_str = "vlib work\n" - cmd_str = "vlog -quiet -suppress 2597 -work work +acc -l vcs.log -novopt -sv "\ - "+define+%s arch_package.sv proj_package.sv " \ - "interface.sv StateTable.svp MemoryArray.svp ddr4_model.svp tb.sv \n" % dev_str - vsim_str = "vsim -quiet -nostdout -c -l v_out.log -novopt tb -do \"run -all\"\n" - - with open(self.script_out, "w") as fp: - fp.write(vlib_str) - fp.write(cmd_str) - fp.write(vsim_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "deselect(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr4_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -class LPDDRValidtion(DRAMValidation): - - def get_prefix_str(self): - cl = self.configs["timing"]["cl"] - bl = self.configs["dram_structure"]["bl"] - - if bl == 2: - bl_bits = "001" - elif bl == 4: - bl_bits = "010" - elif bl == 8: - bl_bits = "011" - else: # BL=16 - bl_bits = "100" - - if cl == 2: - cl_bits = "10" - else: - cl_bits = "11" - - prefix = """ - initial begin:test - //ck <= 1'b0; - cke <= 1'b0; - cs_n <= 1'bz; - ras_n <= 1'bz; - cas_n <= 1'bz; - we_n <= 1'bz; - a <= {ADDR_BITS{1'bz}}; - ba <= {BA_BITS{1'bz}}; - dq_en <= 1'b0; - dqs_en <= 1'b0; - power_up; - nop (10); // wait 10 clocks intead of 200 us for simulation purposes - precharge('h00000000, 1); - nop(trp); - refresh; - nop(trfc); - refresh; - nop(trfc); - load_mode('h0, 'b0%s_0_%s); // setting CL and BL correctly - nop(tmrd); - load_mode('h2, 'b0); - nop(tmrd); - """ % (cl_bits, bl_bits) - return prefix - - def generate_modelsim_script(self, script_name=""): - if not self.script_out: - self.script_out = "run_modelsim_lpddr.sh" - megs = calculate_megs_per_device(self.configs) - density = "den%dMb" % megs - tck = self.configs["timing"]["tck"] - speed_table = { # based on 1Gb device - 4.8: "sg5", - 5.4 : "sg54", - 6.0 : "sg6", - 7.5 : "sg75", - } - if tck not in speed_table.keys(): - print("Invalid tCK value in ini file, use the followings for DDR3:" +\ - str([k for k in speed_table])) - speed = speed_table[tck] - width = self.configs["dram_structure"]["device_width"] - cmd_str = \ - """ - vlib work - vlog -quiet -suppress 2597 +define+%s +define+%s +define+x%d tb.v mobile_ddr.v - vsim -quiet -nostdout -c -l v_out.log -novopt tb -do "run -all" - """ % (density, speed, width) - - with open(self.script_out, "w") as fp: - fp.write(cmd_str) - return - - def generate_verilog_bench(self, bench_name=""): - with open(self.verilog_out, "w") as fp: - # write prefix that initializes device - fp.write(self.get_prefix_str()) - - # convert trace file - last_clk = 0 - for cmd_str in self.commands: - cmd = Command(cmd_str) - this_clk = cmd.clk - nop_cycles = this_clk - last_clk - 1 - if nop_cycles > 0: - nop_str = "nop(%d);\n" % nop_cycles - fp.write(nop_str) - last_clk = this_clk - fp.write(cmd.get_ddr3_str()) - - # finishing up - fp.write(self.get_postfix_str()) - return - - -if __name__ == "__main__": - assert len(sys.argv) == 3, "Need 2 arguments, 1. config file name 2. command trace file name" - - if not (os.path.exists(sys.argv[1]) and os.path.exists(sys.argv[2])): - print("cannot locate input files, please check your input file name and path") - exit(1) - - ini_file = sys.argv[1] - cmd_trace_file = sys.argv[2] - - configs = parse_config.get_dict(ini_file) - - validation = None - if configs["dram_structure"]["protocol"] == "DDR4": - validation = DDR4Validation(ini_file, cmd_trace_file) - elif configs["dram_structure"]["protocol"] == "DDR3": - validation = DDR3Validation(ini_file, cmd_trace_file) - elif configs["dram_structure"]["protocol"] == "LPDDR": - validation = LPDDRValidtion(ini_file, cmd_trace_file) - else: - pass - - validation.validation() - - - - - From 8d8e49ca2923fff037a9af4283ef9dc62c3ddc20 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Thu, 28 Oct 2021 21:28:04 -0400 Subject: [PATCH 12/17] Add `.DS_Store` to `.gitignore` and create new folder for `config` files --- .gitignore | 6 ++++-- {configs => configs_custom}/DDR3_8Gb_x16_1866_ideal.ini | 0 .../DDR3_8Gb_x16_1866_model_swap.ini | 0 3 files changed, 4 insertions(+), 2 deletions(-) rename {configs => configs_custom}/DDR3_8Gb_x16_1866_ideal.ini (100%) rename {configs => configs_custom}/DDR3_8Gb_x16_1866_model_swap.ini (100%) diff --git a/.gitignore b/.gitignore index 9104c128..89118192 100644 --- a/.gitignore +++ b/.gitignore @@ -51,9 +51,11 @@ release dramsim3.json dramsim3.txt - # CMake stuff CMakeCache.txt CMakeFiles/ cmake_install.cmake -Makefile \ No newline at end of file +Makefile + +# DS_Store +.DS_Store \ No newline at end of file diff --git a/configs/DDR3_8Gb_x16_1866_ideal.ini b/configs_custom/DDR3_8Gb_x16_1866_ideal.ini similarity index 100% rename from configs/DDR3_8Gb_x16_1866_ideal.ini rename to configs_custom/DDR3_8Gb_x16_1866_ideal.ini diff --git a/configs/DDR3_8Gb_x16_1866_model_swap.ini b/configs_custom/DDR3_8Gb_x16_1866_model_swap.ini similarity index 100% rename from configs/DDR3_8Gb_x16_1866_model_swap.ini rename to configs_custom/DDR3_8Gb_x16_1866_model_swap.ini From 62fe0c99c033132e4eca7df4a5456a7f6b7a7cef Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Thu, 28 Oct 2021 21:33:44 -0400 Subject: [PATCH 13/17] Add large transaction queue config --- ...3_8Gb_x16_1866_large_transaction_queue.ini | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 configs_custom/DDR3_8Gb_x16_1866_large_transaction_queue.ini diff --git a/configs_custom/DDR3_8Gb_x16_1866_large_transaction_queue.ini b/configs_custom/DDR3_8Gb_x16_1866_large_transaction_queue.ini new file mode 100644 index 00000000..ecea118b --- /dev/null +++ b/configs_custom/DDR3_8Gb_x16_1866_large_transaction_queue.ini @@ -0,0 +1,68 @@ +[dram_structure] +protocol = MODEL_SWAP +bankgroups = 1 +banks_per_group = 8 +rows = 65536 +columns = 1024 +device_width = 16 +BL = 8 + +[timing] +tCK = 1.07 +AL = 0 +CL = 13 +CWL = 9 +tRCD = 13 +tRP = 13 +tRAS = 32 +tRFC = 328 +tRFC2 = 328 +tRFC4 = 328 +REFI = 7290 +tRPRE = 0 +tWPRE = 0 +tRRD_S = 6 +tRRD_L = +tWTR_S = 7 +tWTR_L = 7 +tFAW = 33 +tWR = 15 +tWR2 = 15 +tRTP = 7 +tCCD_S = 4 +tCCD_L = 4 +tCKE = 5 +tCKESR = 6 +tXS = 338 +tXP = 6 +tRTRS = 1 +ideal_memory_latency = 20 + +[power] +VDD = 1.35 +IDD0 = 69 +IPP0 = 0.0 +IDD2P = 11 +IDD2N = 38 +IDD3P = 38 +IDD3N = 53 +IDD4W = 195 +IDD4R = 195 +IDD5AB = 275 +IDD6x = 24 + +[system] +channel_size = 8192 +channels = 1 +bus_width = 64 +address_mapping = rochrababgco +queue_structure = PER_BANK +refresh_policy = RANK_LEVEL_STAGGERED +row_buf_policy = OPEN_PAGE +cmd_queue_size = 8 +trans_queue_size = 1024 + +[other] +epoch_period = 934579 +output_level = 1 + From 23f91c7d9e3edf5f3e813c213a4668c6864b4509 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:32:21 -0500 Subject: [PATCH 14/17] Added phase statistics (not tested yet) --- CMakeLists.txt | 5 +++++ src/common.h | 18 +++++++++++++++++ src/controller.cc | 11 +++++++++++ src/controller.h | 10 ++++++++-- src/dram_system.cc | 14 +++++++++++-- src/dram_system.h | 1 + src/phase_stats.cc | 49 ++++++++++++++++++++++++++++++++++++++++++++++ src/phase_stats.h | 29 +++++++++++++++++++++++++++ src/simple_stats.h | 3 +++ 9 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 src/phase_stats.cc create mode 100644 src/phase_stats.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eaa40bfc..4dd0f40f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ add_library(dramsim3 SHARED src/simple_stats.cc src/timing.cc src/memory_system.cc + src/phase_stats.cc ) if (THERMAL) @@ -67,6 +68,10 @@ if (THERMAL) target_compile_options(thermalreplay PRIVATE -DTHERMAL -D_LONGINT -DAdd_ ${OpenMP_C_FLAGS}) endif (THERMAL) +if (PHASEANALYSIS) + target_compile_options(dramsim3 PRIVATE -DPHASEANALYSIS) +endif (PHASEANALYSIS) + if (CMD_TRACE) target_compile_options(dramsim3 PRIVATE -DCMD_TRACE) endif (CMD_TRACE) diff --git a/src/common.h b/src/common.h index 2f3f0443..6d96e086 100644 --- a/src/common.h +++ b/src/common.h @@ -110,15 +110,33 @@ struct Transaction { : addr(addr), added_cycle(0), complete_cycle(0), + #ifdef PHASEANALYSIS + phase_id(-1), + #endif is_write(is_write) {} + Transaction(const Transaction& tran) : addr(tran.addr), added_cycle(tran.added_cycle), complete_cycle(tran.complete_cycle), + #ifdef PHASEANALYSIS + phase_id(-1), + #endif is_write(tran.is_write) {} +#ifdef PHASEANALYSIS + Transaction(uint64_t addr, bool is_write, int64_t phase_id) + : addr(addr), + added_cycle(0), + complete_cycle(0), + phase_id(phase_id), + is_write(is_write) {} +#endif uint64_t addr; uint64_t added_cycle; uint64_t complete_cycle; +#ifdef PHASEANALYSIS + int64_t phase_id; +#endif bool is_write; friend std::ostream& operator<<(std::ostream& os, const Transaction& trans); diff --git a/src/controller.cc b/src/controller.cc index ac1c501f..835e3fc5 100644 --- a/src/controller.cc +++ b/src/controller.cc @@ -2,6 +2,7 @@ #include #include #include +#include namespace dramsim3 { @@ -48,9 +49,15 @@ std::vector> Controller::ReturnAllDoneTrans(uint64_t cl auto it = return_queue_.begin(); while (it != return_queue_.end()) { if (clk >= it->complete_cycle) { +#ifdef PHASEANALYSIS + phase_stats.AddValue("expected_transaction_latency", it->complete_cycle - it->added_cycle, it->phase_id); +#endif if (it->is_write) { simple_stats_.Increment("num_writes_done"); } else { +#ifdef PHASEANALYSIS + phase_stats.AddValue("read_latency", clk_ - it->added_cycle, it->phase_id); +#endif simple_stats_.Increment("num_reads_done"); simple_stats_.AddValue("read_latency", clk_ - it->added_cycle); } @@ -183,6 +190,10 @@ bool Controller::WillAcceptTransaction(uint64_t hex_addr, bool is_write) const { bool Controller::AddTransaction(Transaction trans) { trans.added_cycle = clk_; + +#ifdef PHASEANALYSIS + phase_stats.AddValue("interarrival_latency", clk_ - last_trans_clk_, trans.phase_id); +#endif simple_stats_.AddValue("interarrival_latency", clk_ - last_trans_clk_); last_trans_clk_ = clk_; diff --git a/src/controller.h b/src/controller.h index 23dd4ffa..ae190375 100644 --- a/src/controller.h +++ b/src/controller.h @@ -2,7 +2,7 @@ #define __CONTROLLER_H #include -#include +#include #include #include #include "channel_state.h" @@ -10,6 +10,9 @@ #include "common.h" #include "refresh.h" #include "simple_stats.h" +#ifdef PHASEANALYSIS +#include "phase_stats.h" +#endif #ifdef THERMAL #include "thermal.h" @@ -34,11 +37,14 @@ class Controller { // Stats output void PrintEpochStats(); void PrintFinalStats(); - void ResetStats() { simple_stats_.Reset(); } + void ResetStats() { simple_stats_.Reset();} std::vector> ReturnAllDoneTrans(uint64_t clock); std::pair ReturnDoneTrans(uint64_t clock); int channel_id_; +#ifdef PHASEANALYSIS + PhaseStats phase_stats; +#endif private: uint64_t clk_; diff --git a/src/dram_system.cc b/src/dram_system.cc index ba7f3beb..d57f4e92 100644 --- a/src/dram_system.cc +++ b/src/dram_system.cc @@ -238,20 +238,30 @@ bool ModelSwapDRAMSystem::WillAcceptTransaction(uint64_t hex_addr, return ctrls_[channel]->WillAcceptTransaction(hex_addr, is_write); } -bool ModelSwapDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { +bool ModelSwapDRAMSystem::AddTransactionByPhase(uint64_t hex_addr, bool is_write, int64_t phase_id, uint64_t latency=-1) { int channel = GetChannel(hex_addr); bool ok = ctrls_[channel]->WillAcceptTransaction(hex_addr, is_write); assert(ok); if (ok) { +#ifdef PHASEANALYSIS + Transaction trans = Transaction(hex_addr, is_write, phase_id); +#else Transaction trans = Transaction(hex_addr, is_write); +#endif trans.added_cycle = clk_; - trans.complete_cycle = clk_ + latency_; + if (latency != -1) { + trans.complete_cycle = clk_ + latency_; + } ctrls_[channel]->AddTransaction(trans); } last_req_clk_ = clk_; return ok; } +bool ModelSwapDRAMSystem::AddTransaction(uint64_t hex_addr, bool is_write) { + return AddTransactionByPhase(hex_addr, is_write, -1); +} + void ModelSwapDRAMSystem::ClockTick() { for (size_t i = 0; i < ctrls_.size(); i++) { auto completed_transactions = ctrls_[i]->ReturnAllDoneTrans(clk_); diff --git a/src/dram_system.h b/src/dram_system.h index 4a4a73b6..0ecec376 100644 --- a/src/dram_system.h +++ b/src/dram_system.h @@ -98,6 +98,7 @@ class ModelSwapDRAMSystem : public BaseDRAMSystem { std::function write_callback); ~ModelSwapDRAMSystem(); bool WillAcceptTransaction(uint64_t hex_addr, bool is_write) const override; + bool AddTransactionByPhase(uint64_t hex_addr, bool is_write, int64_t phase_id, uint64_t latency); bool AddTransaction(uint64_t hex_addr, bool is_write) override; void ClockTick() override; diff --git a/src/phase_stats.cc b/src/phase_stats.cc new file mode 100644 index 00000000..880a3718 --- /dev/null +++ b/src/phase_stats.cc @@ -0,0 +1,49 @@ +#include + +#include "phase_stats.h" + +namespace dramsim3 { + void PhaseStats::AddValue(std::string name, std::uint64_t value, int64_t phase_id) { + if (stats_map_.find(phase_id) != stats_map_.end() ) { + auto stats_phase = stats_map_.find(phase_id); + stats_phase->second.AddValue(name, value); + } else { + auto stats_phase = StatsData(); + stats_phase.AddValue(name, value); + stats_map_.insert({phase_id, stats_phase}); + } + } + + void PhaseStats::Increment(std::string name, int64_t phase_id) { + if (stats_map_.find(phase_id) != stats_map_.end() ) { + auto stats_phase = stats_map_.find(phase_id); + stats_phase->second.Increment(name); + } else { + auto stats_phase = StatsData(); + stats_phase.Increment(name); + stats_map_.insert({phase_id, stats_phase}); + } + } + + void PhaseStats::StatsData::Increment(std::string name) { + if (counter_stats_map_.find(name) != counter_stats_map_.end() ) { + auto counter_pair = counter_stats_map_.find(name); + counter_pair->second += 1; + } else { + auto counter_pair = 1; + counter_stats_map_.insert({name, counter_pair}); + } + } + + void PhaseStats::StatsData::AddValue(std::string name, uint64_t value) { + if (value_stats_map_.find(name) != value_stats_map_.end() ) { + auto values_vector = value_stats_map_.find(name); + values_vector->second.push_back(value); + } else { + std::vector values_vector; + values_vector.push_back(value); + value_stats_map_.insert({name, values_vector}); + } + } + +} // namespace : dramsim3 \ No newline at end of file diff --git a/src/phase_stats.h b/src/phase_stats.h new file mode 100644 index 00000000..91d44f78 --- /dev/null +++ b/src/phase_stats.h @@ -0,0 +1,29 @@ +#ifndef __PHASE_STATS_ +#define __PHASE_STATS_ + +#include +#include +#include + +namespace dramsim3 { + +class PhaseStats { + public: + void Increment(std::string name, int64_t phase_id); + void AddValue(std::string name, uint64_t value, int64_t phase_id); + + private: + class StatsData { + public: + std::unordered_map> value_stats_map_; + std::unordered_map counter_stats_map_; + + void Increment(std::string name); + void AddValue(std::string name, uint64_t value); + }; + + std::unordered_map stats_map_; + +}; +} // namespace : dramsim3 +#endif \ No newline at end of file diff --git a/src/simple_stats.h b/src/simple_stats.h index 2e03892c..4681d6b1 100644 --- a/src/simple_stats.h +++ b/src/simple_stats.h @@ -13,6 +13,9 @@ namespace dramsim3 { class SimpleStats { public: +#ifdef PHASEANALYSIS + SimpleStats(); +#endif SimpleStats(const Config& config, int channel_id); // incrementing counter void Increment(const std::string name) { epoch_counters_[name] += 1; } From c33779694f485b063f4cbcafdcc7ee491bdeff65 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Sun, 13 Feb 2022 00:28:03 -0500 Subject: [PATCH 15/17] Add phase model driver --- CMakeLists.txt | 1 + src/cpu.cc | 1 + src/cpu.h | 1 - src/main.cc | 16 +++ src/phase_detector.cc | 258 ++++++++++++++++++++++++++++++++++++++++++ src/phase_detector.h | 137 ++++++++++++++++++++++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 src/phase_detector.cc create mode 100644 src/phase_detector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd0f40f..4f20b675 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ add_library(dramsim3 SHARED src/timing.cc src/memory_system.cc src/phase_stats.cc + src/phase_detector.cc ) if (THERMAL) diff --git a/src/cpu.cc b/src/cpu.cc index 0abe2224..c9ad7a5d 100644 --- a/src/cpu.cc +++ b/src/cpu.cc @@ -89,6 +89,7 @@ void TraceBasedCPU::ClockTick() { return; } +// Adds ability to call phase model from DRAMsim3 void OnlineCPU::ClockTick() { memory_system_.ClockTick(); clk_++; diff --git a/src/cpu.h b/src/cpu.h index 9145a63f..d66106b0 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -70,7 +70,6 @@ class TraceBasedCPU : public CPU { class OnlineCPU : public CPU { - public: using CPU::CPU; void ClockTick() override; diff --git a/src/main.cc b/src/main.cc index 9ca252e2..ba8187d8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,6 +1,7 @@ #include #include "./../ext/headers/args.hxx" #include "cpu.h" +#include "phase_detector.h" using namespace dramsim3; @@ -27,6 +28,13 @@ int main(int argc, const char **argv) { {'t', "trace"}); args::Positional config_arg( parser, "config", "The config file name (mandatory)"); + args::Flag phase_model_arg( + parser, "phase_model", "Enable phase model. Requires an input file specified using -i", + {'p', "phasemodel"}); + args::ValueFlag phase_model_input_files_arg( + parser, "phase_model_input_file", + "Input file for phase model", + {'i', "inputfile"}); try { parser.ParseCLI(argc, argv); @@ -51,6 +59,14 @@ int main(int argc, const char **argv) { std::string stream_type = args::get(stream_arg); CPU *cpu; + + if (phase_model_arg) { + cpu = new OnlineCPU(config_file, output_dir); + std::string input_files = args::get(phase_model_input_files_arg); + run_phase_detector(cpu, input_files); + return 0; + } + if (!trace_file.empty()) { cpu = new TraceBasedCPU(config_file, output_dir, trace_file); } else { diff --git a/src/phase_detector.cc b/src/phase_detector.cc new file mode 100644 index 00000000..f0250e6f --- /dev/null +++ b/src/phase_detector.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2021, Georgia Institute of Technology +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Ryan Thomas Lynch +// Georgia Institute of Technology +// ryan.lynch@gatech.edu +// CRNCH Lab +// based on pseudocode from https://doi.org/10.1145/3457388.3458670 +// and Python code from Patrick Lavin available at: +// https://github.com/plavin/ModelSwapping/blob/master/PhaseDetector.py + + +// Phase detection code +// Version 0.9 + +#include "phase_detector.h" + +using namespace std; + +static std::map address_to_first_seen_map; + +static uint64_t clk = 0; + +static uint64_t current_phase_latency = 0; +static uint64_t current_phase_num_transactions = 0; + +static int old_phase = -2; +static uint64_t interval = 0; +static std::ofstream dram_phase_trace; + +double PhaseDetector::difference_measure_of_signatures(bitvec sig1, bitvec sig2) { + // auto xor_signatures = sig1 ^ sig2; + // auto or_signatures = sig1 | sig2; + return static_cast((sig1 ^ sig2).count()) / (sig1 | sig2).count(); // this should work with any compiler + // return ((double) xor_signatures.__builtin_count()) / or_signatures.__builtin_count(); // this might only work with GCC +} + +//hashes the address of the current phase detector +uint64_t PhaseDetector::hash_address(uint64_t address) { + // auto address_minus_bottom_drop_bits = address >> drop_bits; + // uint32_t hashed_randomized_address = hash_bitvec(address_minus_bottom_drop_bits); // minstd_rand(address_minus_bottom_drop_bits)(); //hash_bitvec(address_minus_bottom_drop_bits); + + //drop the bottom {drop_bits} bits of the signature + //hash it then return the top {log2_signature_len} bits of the hash (the number of bits determined by the length of the signature) + //use this to then index into a bitvec that represents the current signature to set a specific bit to 1 + return ((uint32_t) std::hash>{}(address >> phase_detector_constants::drop_bits)) >> (32 /*sizeof(uint32_t)*/ /* likely 32 if 32-bit MT or 64 if 64-bit MT or other hash */ - phase_detector_constants::log2_signature_len); + // return hashed_randomized_address >> (32 /*sizeof(uint32_t)*/ /* likely 32 if 32-bit MT or 64 if 64-bit MT or other hash */ - log2_signature_len); + + //old: hash>()(address_minus_bottom_drop_bits) - time test on big XS: 18.539s + //alt: hash>()(address_minus_bottom_drop_bits) - time test on big XS: 7.962s + //not really a hash: hash()(address_minus_bottom_drop_bits) - time test on big XS: 6.178s +} + +void PhaseDetector::detect(uint64_t instruction_pointer) { + current_signature[hash_address(instruction_pointer)] = 1; + + + if (instruction_count % phase_detector_constants::interval_len == 0) { + // we are on a boundary! determine phase and notify listeners + + //first, check if the phase is stable since the difference measure is acceptably low + if (difference_measure_of_signatures(current_signature, last_signature) < phase_detector_constants::threshold) { + stable_count += 1; + if (stable_count >= stable_min && phase == -1) { + //add the current signature to the phase table and make the phase #/phase id to its index + phase_table.push_back(current_signature); + phase = phase_table.size() - 1; // or indexof curr_sig? + //line 194 in the python + } + } else { //line 196 in python + //if difference too high then it's not stable and we might now know the phase + stable_count = 0; + phase = -1; + + //see if we've entered a phase we have seen before + if (!phase_table.empty()) { //line 201 python + double best_diff = phase_detector_constants::threshold; + for (auto phase_table_iterator = phase_table.begin(); phase_table_iterator != phase_table.end(); phase_table_iterator++) { + const auto s = *phase_table_iterator; + const auto diff = difference_measure_of_signatures(current_signature, s); + // difference_scores_from_phase_table.push_back(diff); + if (diff < phase_detector_constants::threshold && diff < best_diff) { + phase = std::distance(phase_table.begin(), phase_table_iterator); + best_diff = diff; + //set current phase to the phase of the one with the lowest difference from current (which is the index in the phase table) + } + } + } + } + //whether or not the phase is stable, we need to update last phase and whatnot + last_signature = current_signature; + current_signature.reset(); + + //add the current phase ID to the phase trace - from line 209 in python + phase_trace.push_back(phase); + + //notify listeners of the current phase ID + //from line 212 in python + for (auto f : listeners) { + f(phase); + } + + + //TODO: add addr info to phase, dwarf map? + + } + instruction_count += 1; // should this be before or after the if? +} + +void PhaseDetector::init_phase_detector() { + current_signature.reset(); + last_signature.reset(); + // hash_bitvec + instruction_count = 0; + stable_count = 0; + phase = -1; + phase_table.clear(); + phase_trace.clear(); + listeners.clear(); +} + +void PhaseDetector::print_log_file(string log_file_name) { + + ofstream log(log_file_name); + // for (auto p : phase_trace) { + for (size_t index = 0; index < phase_trace.size(); index++) { + // cout << p << endl; + auto p = phase_trace[index]; + if (log.is_open()) { + log << index * phase_detector_constants::interval_len << "," << p << '\n'; + } + } + log.close(); + // } else { + // ofstream log("phase_trace_medium.txt"); + // for (auto p : phase_trace) { + // // cout << p << endl; + // if (log.is_open()) { + // log << p << endl; + // } + // } + // log.close(); + // } +} + +void PhaseDetector::cleanup_phase_detector(string log_file_name = "") { + + if (log_file_name.size() > 0) { + print_log_file(log_file_name); + } + init_phase_detector(); +} + +void PhaseDetector::register_listeners(listener_function f) { + listeners.push_back(f); +} + +void dram_phase_trace_listener(int new_phase) { + if (new_phase != old_phase) { + if (dram_phase_trace.good()) { + + //TODO: need to get the stats for the current phase here to put in the output file all together + + int64_t adjustment = 0; // (new_phase == -1) ? 0 : detector.stable_min * -1; //if we want to back label intervals + + double phase_aat = current_phase_latency / static_cast(current_phase_num_transactions); + + dram_phase_trace << (interval + adjustment) << "," << new_phase << "," << phase_aat << '\n'; + } else { + std::cerr << "dram phase trace file not good anymore! on phase " << new_phase << " and clock # " << clk << std::endl; + } + old_phase = new_phase; + // memSystem->ResetStats(); + current_phase_latency = 0; + current_phase_num_transactions = 0; + + //TODO: determine if transactions that cross boundaries are a big deal - just gonna throw them away for now lol + address_to_first_seen_map.clear(); + + } + interval += 1; +} + +void dramsim_transaction_callback_listener(uint64_t addr) { + if (address_to_first_seen_map.count(addr)) { + uint64_t latency = clk - address_to_first_seen_map[addr]; + address_to_first_seen_map.erase(addr); + current_phase_num_transactions++; + current_phase_latency += latency; + } +} + +void run_phase_detector(OnlineCPU *cpu, string input_files) { + PhaseDetector detector; + detector.init_phase_detector(); + + ifstream input_file_list_stream(input_files); + std::string line; + clk = 0; + current_phase_latency = 0; + current_phase_num_transactions = 0; + + auto callback = std::bind(dramsim_transaction_callback_listener, std::placeholders::_1); + detector.register_listeners(dram_phase_trace_listener); + cpu->RegisterCallbacks(callback, callback); + // memSystem->RegisterCallbacks(callback, callback); + + while (std::getline(input_file_list_stream, line)) { + //line is the name of the current file to read from + ifstream in_stream; + in_stream.open(line); + binary_output_struct_t current; + bool readNext = true; + while (in_stream.good()) { + if (readNext) { + in_stream.read((char*)¤t, sizeof(binary_output_struct_t)); + detector.detect(current.instruction_pointer); + address_to_first_seen_map[current.virtual_address] = clk; + readNext = false; + } + readNext = cpu->canSendTransaction(current.virtual_address, current.is_write); + cpu->ClockTick(); + clk++; + if (readNext) { + cout << "READ NEXT!" << endl; + } else { + cout << "did not read next" << endl; + } + if (clk % 10000 == 0) { + cout << clk << endl; + } + } + in_stream.close(); + } + + input_file_list_stream.close(); + + // cpu->PrintStats(); + + delete cpu; + + dram_phase_trace.close(); + +} diff --git a/src/phase_detector.h b/src/phase_detector.h new file mode 100644 index 00000000..38799ae2 --- /dev/null +++ b/src/phase_detector.h @@ -0,0 +1,137 @@ +// Copyright (c) 2021, Georgia Institute of Technology +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Ryan Thomas Lynch +// Georgia Institute of Technology +// ryan.lynch@gatech.edu +// CRNCH Lab + + +// Phase detection header file +// Version 0.9 + +#ifndef PHASE_DETECTOR_H +#define PHASE_DETECTOR_H + +#include +#include +#include + +#include +#include +// #include +#include +// #include +#include "cpu.h" +#include +#include +#include +//TODO: replace bits/stdc++ with something that actually works for other compilers? +// #include +// #include +#include +// #include + +using namespace dramsim3; +using namespace std; + + +// double threshold = 0.5; +// int interval_len = 10000; +// const int signature_len = 1024; +// const int log2_signature_len = 10; // should be log 2 of the above value +// int drop_bits = 3; + +// #define threshold 0.5 +// #define interval_len 10000 +// #define signature_len 1024 +// #define log2_signature_len 10 +// #define drop_bits 3 + +namespace phase_detector_constants { + constexpr double threshold = 0.5; + constexpr uint64_t interval_len = 10000; + constexpr uint signature_len = 1024; + constexpr uint log2_signature_len = 10; + constexpr uint drop_bits = 3; +} + +using bitvec = bitset; + +typedef int phase_id_type; + +typedef void (*listener_function)(phase_id_type); //listener functor type that takes in a phase ID and returns nothing + +typedef void (*dram_listener_function)(uint64_t, phase_id_type); //listener functor type that takes in a phase ID and returns nothing + +void read_file(char const log_file[], int is_binary = 1); + +void test_listener(phase_id_type current_phase); +void dram_phase_trace_listener(phase_id_type new_phase); +void register_dram_trace_listener(dram_listener_function f); + +//used for reading from memtrace binary output files +struct Binary_output_struct_type { + + bool is_write; + uint64_t virtual_address; + uint64_t size_of_access; + uint64_t instruction_pointer; + +}; + +typedef struct Binary_output_struct_type binary_output_struct_t; + +class PhaseDetector { + private: + bitvec current_signature; + bitvec last_signature; + + // static hash> hash_bitvec(); + //hash hash_bitvec; + + uint64_t instruction_count = 0; + uint64_t stable_count = 0; + + phase_id_type phase = -1; + + vector phase_table; + + //phase trace?? should it be deque/stack or vector/arraylist? + + // vector phase_trace; + deque phase_trace; + + vector listeners; + public: + + const uint64_t stable_min = 5; + + double difference_measure_of_signatures(bitvec sig1, bitvec sig2); + uint64_t hash_address(uint64_t address); + void detect(uint64_t instruction_pointer); + void init_phase_detector(); + void cleanup_phase_detector(string log_file_name); + void register_listeners(listener_function f); + void print_log_file(string log_file_name); +}; + +void dram_phase_trace_listener(int new_phase); +void dramsim_transaction_callback_listener(uint64_t addr); +void run_phase_detector(OnlineCPU *cpu, string input_files); + +#endif \ No newline at end of file From f1f7b1ad15e8796dfb9facfaa983cb424c1cdfa0 Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Sun, 13 Feb 2022 23:22:00 -0500 Subject: [PATCH 16/17] Add Docker support --- Dockerfile | 8 ++++++++ src/main.cc | 8 ++++---- start-docker.sh | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100755 start-docker.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..83c47138 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:20.04 + +WORKDIR ../DRAMSIM3 + +RUN apt-get update \ + && apt-get install -y make \ + && apt-get install -y cmake \ + && apt-get install -y build-essential \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index ba8187d8..162c9a50 100644 --- a/src/main.cc +++ b/src/main.cc @@ -58,15 +58,15 @@ int main(int argc, const char **argv) { std::string trace_file = args::get(trace_file_arg); std::string stream_type = args::get(stream_arg); - CPU *cpu; - if (phase_model_arg) { - cpu = new OnlineCPU(config_file, output_dir); + OnlineCPU *online_cpu = new OnlineCPU(config_file, output_dir); std::string input_files = args::get(phase_model_input_files_arg); - run_phase_detector(cpu, input_files); + run_phase_detector(online_cpu, input_files); return 0; } + CPU *cpu; + if (!trace_file.empty()) { cpu = new TraceBasedCPU(config_file, output_dir, trace_file); } else { diff --git a/start-docker.sh b/start-docker.sh new file mode 100755 index 00000000..d93c421f --- /dev/null +++ b/start-docker.sh @@ -0,0 +1,4 @@ +ROOT_DIR="$(pwd)" + +docker build -t dramsim3-docker . +docker run --rm -it --name="dramsim3" -v "${ROOT_DIR}/":/DRAMSIM3 -w="/DRAMSIM3" dramsim3-docker \ No newline at end of file From 0dfad602c5ff72055b474b6f05c155479883a75a Mon Sep 17 00:00:00 2001 From: sudhanshu2 <24910339+sudhanshu2@users.noreply.github.com> Date: Sun, 13 Feb 2022 23:33:55 -0500 Subject: [PATCH 17/17] Add example for using phase model --- src/main.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main.cc b/src/main.cc index 162c9a50..f7bbd801 100644 --- a/src/main.cc +++ b/src/main.cc @@ -8,10 +8,12 @@ using namespace dramsim3; int main(int argc, const char **argv) { args::ArgumentParser parser( "DRAM Simulator.", - "Examples: \n." + "Examples: \n" "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -c 100 -t " "sample_trace.txt\n" - "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -s random -c 100"); + "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -s random -c 100\n" + "./build/dramsim3main configs/DDR4_8Gb_x8_3200.ini -p -i phase_trace.txt"); + args::HelpFlag help(parser, "help", "Display the help menu", {'h', "help"}); args::ValueFlag num_cycles_arg(parser, "num_cycles", "Number of cycles to simulate", @@ -32,7 +34,7 @@ int main(int argc, const char **argv) { parser, "phase_model", "Enable phase model. Requires an input file specified using -i", {'p', "phasemodel"}); args::ValueFlag phase_model_input_files_arg( - parser, "phase_model_input_file", + parser, "file_name", "Input file for phase model", {'i', "inputfile"});